commit 96de6a4c1d694bebc2eed373b2b37aa9539da052
parent 691c21ea9dc4912bbe7b8c4450d2d11318464afd
Author: sin <sin@2f30.org>
Date: Sat, 26 Dec 2015 12:17:29 +0000
Use curl to communicate with tracker
Diffstat:
M | Makefile | | | 11 | ++++++++--- |
M | storrent.h | | | 3 | --- |
M | tracker.c | | | 158 | +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------- |
M | util.c | | | 78 | ------------------------------------------------------------------------------ |
4 files changed, 110 insertions(+), 140 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,9 +2,14 @@ VERSION = 0.0
PREFIX = /usr/local
-CPPFLAGS = -D_DEFAULT_SOURCE
-CFLAGS = -g -std=c99 -Wall -Wextra
-LDFLAGS =
+CURLINC = /usr/local/include
+CURLLIB = /usr/local/lib
+
+INCS = -I$(CURLINC)
+LIBS = -L$(CURLLIB) -lcurl
+
+CFLAGS = -g -std=c99 -Wall -Wextra $(INCS)
+LDFLAGS = $(LIBS)
OBJ =\
ben.o\
diff --git a/storrent.h b/storrent.h
@@ -80,12 +80,9 @@ uint8_t *hex2bin(const char *, uint8_t *, size_t);
char *bin2hex(const uint8_t *, char *, size_t);
void sha1sum(uint8_t *, unsigned long, uint8_t *);
int readfile(char *, char **, size_t *);
-char *urlencode(char *, size_t);
-char *urldecode(char *);
ssize_t writen(int, const void *, size_t);
ssize_t readn(int, void *, size_t);
#undef strlcpy
size_t strlcpy(char *, const char *, size_t);
#undef strlcat
size_t strlcat(char *, const char *, size_t);
-char *parseurl(char *, char **, char **, char **, char **);
diff --git a/tracker.c b/tracker.c
@@ -1,6 +1,4 @@
/* See LICENSE file for copyright and license details. */
-#include <sys/socket.h>
-
#include <arpa/inet.h>
#include <netinet/in.h>
@@ -9,69 +7,69 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
+
+#include <curl/curl.h>
+
#include "storrent.h"
-int
-getpeers(struct torrent *t)
+struct buf {
+ char *p;
+ size_t size;
+};
+
+static void
+initbuf(struct buf *b)
+{
+ memset(b, 0, sizeof(*b));
+}
+
+static void
+freebuf(struct buf *b)
+{
+ free(b->p);
+ b->p = NULL;
+}
+
+static size_t
+writefn(void *ptr, size_t size, size_t nmemb, struct buf *buf)
+{
+ size_t newsz;
+
+ newsz = buf->size + size * nmemb;
+ if (!(buf->p = realloc(buf->p, newsz + 1)))
+ err(1, "realloc");
+ memcpy(buf->p + buf->size, ptr, size * nmemb);
+ buf->size = newsz;
+ return size * nmemb;
+}
+
+static int
+parsepeers(struct torrent *t, struct buf *b)
{
struct sockaddr_in sa;
struct ben *reply, *peers;
struct peer *peer;
- char *url, *proto, *host, *port, *path;
- char *infohash, *id;
- char buf[8192], *p;
- int r, s;
-
- url = parseurl(t->announcers[0].urls[0], &proto, &host, &port, &path);
- infohash = urlencode((char *)t->infohash, 20);
- id = urlencode(peerid(), 20);
- if (proto && strcmp(proto, "http")) {
- fprintf(stderr, "unsupported protocol: %s\n", proto);
- goto fail;
- }
+ char *p;
- r = snprintf(buf, sizeof(buf),
- "GET /%s?info_hash=%s&peer_id=%s&port=6881&uploaded=0&"
- "downloaded=0&left=%zu&compact=1&event=started HTTP/1.1\r\n\r\n",
- path, infohash, id, t->totallen);
- if (r < 0 || (size_t)r >= sizeof(buf))
- goto fail;
-
- if ((s = dial(host, port)) < 0)
- goto fail;
-
- writen(s, buf, r);
- r = readn(s, buf, sizeof(buf) - 1);
- buf[r] = '\0';
-
- if ((p = strstr(buf, "\r\n\r\n"))) {
- p += 4;
- r -= (p - buf);
- } else if ((p = strstr(buf, "\n\n"))) {
- p += 2;
- r -= (p - buf);
- } else {
- p = buf;
- }
+ if (!bdecode(b->p, b->p + b->size, &reply))
+ return -1;
- if (!bdecode(p, p + r, &reply))
- goto fail;
- peers = dlookstr(reply, "peers");
- if (!peers) {
+ if (!(peers = dlookstr(reply, "peers"))) {
warnx("no peers field in tracker reply");
bfree(reply);
- goto fail;
+ return -1;
}
+
if (peers->type != 's') {
warnx("expected compact reply");
bfree(reply);
- goto fail;
+ return -1;
}
+
if (peers->len % 6) {
warnx("peers length needs to be a multiple of 6 bytes");
bfree(reply);
- goto fail;
+ return -1;
}
for (p = peers->s; p < &peers->s[peers->len]; p += 6) {
@@ -88,14 +86,62 @@ getpeers(struct torrent *t)
t->npeers++;
}
- bfree(reply);
- free(id);
- free(infohash);
- free(url);
+ free(reply);
return 0;
-fail:
- free(id);
- free(infohash);
- free(url);
- return -1;
+}
+
+int
+getpeers(struct torrent *t)
+{
+ CURL *curl;
+ CURLcode res;
+ char buf[8192], *infohash, *id;
+ struct buf reply;
+ int r;
+
+ if (!(curl = curl_easy_init()))
+ return -1;
+
+ if (!(infohash = curl_easy_escape(curl, t->infohash, 20))) {
+ curl_easy_cleanup(curl);
+ return -1;
+ }
+
+ if (!(id = curl_easy_escape(curl, peerid(), 20))) {
+ curl_free(infohash);
+ curl_easy_cleanup(curl);
+ return -1;
+ }
+
+ r = snprintf(buf, sizeof(buf),
+ "%s?info_hash=%s&peer_id=%s&port=6881&uploaded=0&"
+ "downloaded=0&left=%zu&compact=1&event=started",
+ t->announcers[0].urls[0], infohash, id, t->totallen);
+ if (r < 0 || (size_t)r >= sizeof(buf)) {
+ curl_free(infohash);
+ curl_free(id);
+ curl_easy_cleanup(curl);
+ return -1;
+ }
+
+ initbuf(&reply);
+ curl_easy_setopt(curl, CURLOPT_URL, buf);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefn);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply);
+ res = curl_easy_perform(curl);
+ if (res == CURLE_OK) {
+ if (parsepeers(t, &reply) < 0) {
+ curl_free(infohash);
+ curl_free(id);
+ curl_easy_cleanup(curl);
+ freebuf(&reply);
+ return -1;
+ }
+ }
+
+ curl_free(infohash);
+ curl_free(id);
+ curl_easy_cleanup(curl);
+ freebuf(&reply);
+ return r;
}
diff --git a/util.c b/util.c
@@ -132,53 +132,6 @@ readfile(char *file, char **b, size_t *n)
return 0;
}
-char *
-urlencode(char *s, size_t n)
-{
- char *p = s, *buf, *bp;
-
- bp = buf = emalloc(n * 3 + 1);
- while (p < &s[n]) {
- if (*p == '-' || *p == '_' ||
- *p == '.' || *p == '~' ||
- isalnum(*p)) {
- *bp++ = *p;
- } else if (*p == ' ') {
- *bp++ = '+';
- } else {
- *bp++ = '%';
- *bp++ = int2hex(*p >> 4);
- *bp++ = int2hex(*p);
- }
- p++;
- }
- *bp = '\0';
- return buf;
-}
-
-char *
-urldecode(char *s)
-{
- char *p = s, *buf, *bp;
-
- bp = buf = emalloc(strlen(s) + 1);
- while (*p) {
- if (*p == '%') {
- if (p[1] && p[2]) {
- *bp++ = hex2int(p[1]) << 4 | hex2int(p[2]);
- p += 2;
- }
- } else if (*p == '+') {
- *bp++ = ' ';
- } else {
- *bp++ = *p;
- }
- p++;
- }
- *bp = '\0';
- return buf;
-}
-
ssize_t
writen(int fd, const void *buf, size_t count)
{
@@ -269,34 +222,3 @@ strlcat(char *dst, const char *src, size_t dsize)
return(dlen + (src - osrc)); /* count does not include NUL */
}
-
-char *
-parseurl(char *url, char **proto, char **host, char **port, char **path)
-{
- char *tmp, *p, *newurl;
-
- *proto = *host = *port = *path = NULL;
- if (!(newurl = p = strdup(url)))
- err(1, "strdup");
- if ((tmp = strstr(p, "://"))) {
- *proto = p;
- *tmp = '\0';
- p = tmp + 3;
- }
- if (!*p)
- return newurl;
- *host = p;
- if ((tmp = strchr(p, ':'))) {
- p = tmp;
- *p++ = '\0';
- *port = p;
- }
- if (!*p)
- return newurl;
- if ((tmp = strchr(p, '/'))) {
- p = tmp;
- *p++ = '\0';
- *path = p;
- }
- return newurl;
-}