Plan 9 from Bell Labs’s /usr/web/sources/contrib/mjl/wip/deluge/tracker.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "deluge.h"


char *
urlescape(char *s, int n)
{
	static char buf[512];
	int i;
	char *p;
	char c;

	if(n < 0)
		n = strlen(s);

	p = buf;
	for(i = 0; i < n; i++){
		c = s[i];
		if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9')
			*p++ = c;
		else
			p = seprint(p, buf+sizeof buf, "%%%02X", (int)(uchar)s[i]);
	}
	*p = 0;
	return buf;
}


char *
urlparse(char *url, int *https, char **host, char **port, char **path)
{
	char *p, *ep;

	url = estrdup(url);
	p = url;

	*https = 0;
	if(strncmp(p, "http://", strlen("http://")) == 0){
		p += strlen("http://");
	}else if(strncmp(p, "https://", strlen("https://")) == 0){
		*https = 1;
		p += strlen("https://");
	}else{
		free(url);
		return smprint("missing http:// or https://");
	}

	if(strchr(p, '/') == nil){
		int len = strlen(url);
		int offset = p - url;
		url = erealloc(url, strlen(url)+2);
		url[len++] = '/';
		url[len] = 0;
		p = url+offset;
	}

	ep = p;
	while(*ep != '/' && *ep != ':')
		ep++;
	*host = emallocz((ep - p) + 1, 1);
	memmove(*host, p, ep-p);
	if(*ep == ':'){
		p = ep+1;
		ep = p;
		while(*ep >= '0' && *ep <= '9')
			ep++;
		*port = emallocz((ep - p) + 1, 1);
		memmove(*port, p, ep-p);
		p = ep;
	}else
		*port = estrdup(*https ? "443" : "80");

	*path = estrdup(p);
	free(url);
	return nil;
}


char *
trackerget(Bee *b, char *announce, char *listenport, uchar *infohash, uchar *peerid, vlong ul, vlong dl, vlong left, char *event)
{
	int fd, sfd;
	String *qs;
	Biobuf *bp, bpbuf;
	int llen;
	char *p;
	char buf[64];
	char *l;
	int code;
	char *errmsg;
	int c;
	int https;
	char *host, *port, *path;
	TLSconn conn;

	errmsg = urlparse(announce, &https, &host, &port, &path);
	if(errmsg)
		return errmsg;

	bp = &bpbuf;

	fd = dial(netmkaddr(host, nil, port), 0, 0, 0);
	if(fd < 0)
		return smprint("dial %s: %r", netmkaddr(host, nil, port));

	if(https){
		memset(&conn, 0, sizeof conn);
		sfd = tlsClient(fd, &conn);
		if(sfd < 0){
			close(fd);
			return smprint("tlsclient: %r");
		}
		if(conn.cert)
				free(conn.cert);
		close(fd);
		fd = sfd;
	}

	qs = s_new();
	s_append(qs, "info_hash=");
	s_append(qs, urlescape((char*)infohash, 20));
	s_append(qs, "&peer_id=");
	s_append(qs, urlescape((char*)peerid, 20));
	s_append(qs, "&port=");
	s_append(qs, urlescape(listenport, -1));
	s_append(qs, "&uploaded=");
	snprint(buf, sizeof buf, "%lld", ul);
	s_append(qs, urlescape(buf, -1));
	s_append(qs, "&downloaded=");
	snprint(buf, sizeof buf, "%lld", dl);
	s_append(qs, urlescape(buf, -1));
	s_append(qs, "&left=");
	snprint(buf, sizeof buf, "%lld", left);
	s_append(qs, urlescape(buf, -1));
	if(event && event[0]){
		s_append(qs, "&event=");
		s_append(qs, urlescape(event, -1));
	}

	fprint(fd,
		"GET %s?%s HTTP/1.0\r\n"
		"Host: %s\r\n"
		"User-agent: Plan9/deluge\r\n\r\n",
		path, s_to_c(qs), host);
	DEBUG(2,
		"GET %s?%s HTTP/1.0\r\n"
		"Host: %s\r\n"
		"User-agent: Plan9/deluge\r\n\r\n",
		path, s_to_c(qs), host);
	s_free(qs);

	if(Binit(bp, fd, OREAD) < 0)
		return smprint("Binit for http fd: %r");
	l = Brdline(bp, '\n');
	if(l == nil)
		return smprint("error reading response: %r");
	llen = Blinelen(bp);
	p = l + strlen("HTTP/1.0 ");
	if(strncmp(l, "HTTP/1.0 ", strlen("HTTP/1.0 ")) != 0
			|| l[llen-2] != '\r' || strlen(l) < strlen("HTTP/1.0 XXX \r\n")
			|| !isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2])){
		l[llen-2] = 0;
		Bterm(bp);
		close(fd);
		return smprint("invalid response from tracker: %s", l);
	}
	code = atoi(p);
	if(code != 200){
		Bterm(bp);
		close(fd);
		return smprint("http get failed, code=%d\n", code);
	}

	/* skip through http headers */
	for(;;){
		l = Brdline(bp, (int)'\n');
		if(l == nil){
			Bterm(bp);
			close(fd);
			return smprint("error/unexpected eof while reading tracker response: %r");
		}
		if(Blinelen(bp) == 2 && strncmp(l, "\r\n", 2) == 0)
			break;
	}

	errmsg = beeunpickle(bp, b);
	while((c = Bgetc(bp)) >= 0){
		if(c == '\r' || c == '\n')
			continue;
		DEBUG(2, "extra data: ");
		while((c = Bgetc(bp)) >= 0)
			DEBUG(2, "%c", c);
		DEBUG(2, "\n");
		Bterm(bp);
		close(fd);
		return smprint("data after bencode data from tracker (%d)", c);
	}
	Bterm(bp);
	close(fd);
	if(errmsg)
		return smprint("invalid bencode from tracker: %s", errmsg);
	return nil;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.