torrentd

simple torrent daemon
git clone git@git.2f30.org/torrentd.git
Log | Files | Refs | LICENSE

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:
MMakefile | 11++++++++---
Mstorrent.h | 3---
Mtracker.c | 158+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mutil.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; -}