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