#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;
}
|