X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=daemon%2Ffnet-dc.c;h=c4d81c6ddfacf386a2fb49eb2ec2cb5696a70def;hb=be11f9941bebe6659f95f71460470b0eb6d9a105;hp=804bd2c70838c955af73b717d89a284d8893d115;hpb=5ec60e4217863b0e2d6a86ba3f60f60c68608227;p=doldaconnect.git diff --git a/daemon/fnet-dc.c b/daemon/fnet-dc.c index 804bd2c..c4d81c6 100644 --- a/daemon/fnet-dc.c +++ b/daemon/fnet-dc.c @@ -1,6 +1,6 @@ /* * Dolda Connect - Modular multiuser Direct Connect-style client - * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com) + * Copyright (C) 2004 Fredrik Tolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,13 +19,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -103,6 +101,7 @@ struct qcommand struct dchub { + struct socket *sk; char *inbuf; size_t inbufdata, inbufsize; struct qcommand *queue; @@ -110,6 +109,7 @@ struct dchub char *charset; char *nativename; char *nativenick; + char **supports; }; struct dcexppeer @@ -127,7 +127,7 @@ struct dcpeer struct fnetnode *fn; char *inbuf; size_t inbufdata, inbufsize; - size_t curread, totalsize; + off_t curread, totalsize; int freeing; struct timer *timeout; struct qcommand *queue; @@ -160,13 +160,11 @@ static char *xmllistname = NULL; static char *xmlbz2listname = NULL; static struct timer *listwritetimer = NULL; -static int peerconnect(struct socket *sk, int err, struct fnetnode *fn); -static int peerread(struct socket *sk, struct dcpeer *peer); -static int peererror(struct socket *sk, int err, struct dcpeer *peer); +static void peerconnect(struct socket *sk, int err, struct fnetnode *fn); static void freedcpeer(struct dcpeer *peer); -static void transread(struct dcpeer *peer); -static void transerr(struct dcpeer *peer); -static int transwrite(struct socket *sk, struct dcpeer *peer); +static void transread(struct socket *sk, struct dcpeer *peer); +static void transerr(struct socket *sk, int err, struct dcpeer *peer); +static void transwrite(struct socket *sk, struct dcpeer *peer); static void updatehmlist(void); static void updatexmllist(void); static void updatexmlbz2list(void); @@ -247,6 +245,24 @@ static int isdchash(struct hash *hash) return(1); } +/* + * Uncomment when used! + +static int hubsupports(struct dchub *hub, char *cap) +{ + char **p; + + if(hub->supports == NULL) + return(0); + for(p = hub->supports; *p != NULL; p++) + { + if(!strcasecmp(*p, cap)) + return(1); + } + return(0); +} +*/ + static int supports(struct dcpeer *peer, char *cap) { char **p; @@ -486,7 +502,11 @@ static void sendadc(struct socket *sk, char *arg) free(buf); } -static void sendadcf(struct socket *sk, char *arg, ...) +#if defined(__GNUC__) +static void __attribute__ ((format (printf, 2, 3))) sendadcf(struct socket *sk, char *arg, ...) +#else +static void sendadcf(struct socket *sk, char *arg, ...) +#endif { char *buf; va_list args; @@ -621,7 +641,7 @@ static int trresumecb(struct transfer *transfer, wchar_t *cmd, wchar_t *arg, str flog(LOG_WARNING, "filter returned no position for \"resume\" on transfer %i", transfer->id); freedcpeer(peer); } else { - transfer->curpos = wcstol(arg, NULL, 10); + transfer->curpos = wcstoll(arg, NULL, 10); peer->hascurpos = 1; requestfile(peer); } @@ -651,10 +671,14 @@ static void sendpeerlock(struct dcpeer *peer) static void sendsupports(struct dcpeer *peer) { - if(peer->dcppemu) + if(peer->dcppemu) { qstr(peer->sk, "$Supports MiniSlots XmlBZList ADCGet TTHL TTHF GetZBlock ZLIG |"); - else - qstr(peer->sk, "$Supports MiniSlots XmlBZList ADCGet TTHL TTHF GetZBlock ZLIG|"); + } else { + qstr(peer->sk, "$Supports MiniSlots XmlBZList ADCGet TTHL TTHF"); + if(!confgetint("dc", "hidedeflate")) + qstr(peer->sk, " GetZBlock ZLIG"); + qstr(peer->sk, "|"); + } } static void requestfile(struct dcpeer *peer) @@ -720,8 +744,8 @@ static void requestfile(struct dcpeer *peer) } sendadc(peer->sk, buf); free(buf); - sendadcf(peer->sk, "%i", peer->transfer->curpos); - sendadcf(peer->sk, "%i", peer->transfer->size - peer->transfer->curpos); + sendadcf(peer->sk, "%ji", (intmax_t)peer->transfer->curpos); + sendadcf(peer->sk, "%ji", (intmax_t)(peer->transfer->size - peer->transfer->curpos)); qstr(peer->sk, "|"); } else if(supports(peer, "xmlbzlist")) { if((buf = icswcstombs(peer->transfer->path, "UTF-8", NULL)) == NULL) @@ -730,7 +754,7 @@ static void requestfile(struct dcpeer *peer) freedcpeer(peer); return; } - qstrf(peer->sk, "$UGetBlock %i %i %s|", peer->transfer->curpos, peer->transfer->size - peer->transfer->curpos, buf); + qstrf(peer->sk, "$UGetBlock %ji %ji %s|", (intmax_t)peer->transfer->curpos, (intmax_t)(peer->transfer->size - peer->transfer->curpos), buf); } else { /* Use DCCHARSET for $Get paths until further researched... */ if((buf = icswcstombs(peer->transfer->path, DCCHARSET, NULL)) == NULL) @@ -739,7 +763,7 @@ static void requestfile(struct dcpeer *peer) freedcpeer(peer); return; } - qstrf(peer->sk, "$Get %s$%i|", buf, peer->transfer->curpos + 1); + qstrf(peer->sk, "$Get %s$%ji|", buf, (intmax_t)peer->transfer->curpos + 1); } } @@ -816,10 +840,14 @@ static void cmd_lock(struct socket *sk, struct fnetnode *fn, char *cmd, char *ar *(p++) = 0; if(hub->extended) { - if(hub->dcppemu) + if(hub->dcppemu) { qstrf(sk, "$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch GetZBlock |"); - else - qstrf(sk, "$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch GetZBlock|"); + } else { + qstrf(sk, "$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch"); + if(!confgetint("dc", "hidedeflate")) + qstr(sk, " GetZBlock"); + qstr(sk, "|"); + } } key = dcmakekey(args); qstrf(sk, "$Key %s|", key); @@ -1112,7 +1140,7 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * goto out; prefix = sprintf2("$SR %s ", hub->nativenick); infix = sprintf2(" %i/%i\005", slotsleft(), confgetint("transfer", "slots")); - postfix = sprintf2(" (%s)\005%s|", formataddress(fn->sk->remote, fn->sk->remotelen), args + 4); + postfix = sprintf2(" (%s)\005%s|", formataddress(hub->sk->remote, hub->sk->remotelen), args + 4); dsk = sk; getsock(dsk); } else { @@ -1125,7 +1153,7 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * addr.sin_port = htons(atoi(p2)); prefix = sprintf2("$SR %s ", hub->nativenick); infix = sprintf2(" %i/%i\005", slotsleft(), confgetint("transfer", "slots")); - postfix = sprintf2(" (%s)|", formataddress(fn->sk->remote, fn->sk->remotelen)); + postfix = sprintf2(" (%s)|", formataddress(hub->sk->remote, hub->sk->remotelen)); netdgramconn(dsk = netdupsock(udpsock), (struct sockaddr *)&addr, sizeof(addr)); } @@ -1233,10 +1261,10 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * if(node->f.b.hastth) { buf2 = base32encode(node->hashtth, 24); - qstrf(dsk, "%s%s\005%i%sTTH:%.39s%s", prefix, buf, node->size, infix, buf2, postfix); + qstrf(dsk, "%s%s\005%ji%sTTH:%.39s%s", prefix, buf, (intmax_t)node->size, infix, buf2, postfix); free(buf2); } else { - qstrf(dsk, "%s%s\005%i%s%s%s", prefix, buf, node->size, infix, hub->nativename, postfix); + qstrf(dsk, "%s%s\005%ji%s%s%s", prefix, buf, (intmax_t)node->size, infix, hub->nativename, postfix); } free(buf); } @@ -1302,7 +1330,7 @@ static void cmd_connecttome(struct socket *sk, struct fnetnode *fn, char *cmd, c addr.sin_port = htons(atoi(p)); if(!inet_aton(args, &addr.sin_addr)) return; - newsk = netcsconn((struct sockaddr *)&addr, sizeof(addr), (int (*)(struct socket *, int, void *))peerconnect, fn); + newsk = netcsconn((struct sockaddr *)&addr, sizeof(addr), (void (*)(struct socket *, int, void *))peerconnect, fn); getfnetnode(fn); hubhandleaction(sk, fn, cmd, args); } @@ -1377,7 +1405,7 @@ static void cmd_to(struct socket *sk, struct fnetnode *fn, char *cmd, char *args return; *p2 = 0; p2 += 2; - hubrecvchat(fn->sk, fn, p, p2); + hubrecvchat(hub->sk, fn, p, p2); hubhandleaction(sk, fn, cmd, args); } @@ -1386,7 +1414,8 @@ static void cmd_sr(struct socket *sk, struct fnetnode *fn, char *cmd, char *args struct dchub *hub; char *p, *p2, *buf; char *nick, *filename, *hubname; - int size, slots; + off_t size; + int slots; size_t buflen; struct srchres *sr; wchar_t *wnick, *wfile; @@ -1405,7 +1434,7 @@ static void cmd_sr(struct socket *sk, struct fnetnode *fn, char *cmd, char *args if((p2 = strchr(p, ' ')) == NULL) return; *p2 = 0; - size = atoi(p); + size = strtoll(p, NULL, 10); p = p2 + 1; if((p2 = strchr(p, '/')) == NULL) return; @@ -1483,6 +1512,36 @@ static void cmd_logedin(struct socket *sk, struct fnetnode *fn, char *cmd, char hubhandleaction(sk, fn, cmd, args); } +static void cmd_hubsupports(struct socket *sk, struct fnetnode *fn, char *cmd, char *args) +{ + struct dchub *hub; + int i; + char *p, *p2; + char **arr; + size_t arrsize, arrdata; + + hub = fn->data; + if(hub->supports != NULL) + { + for(i = 0; hub->supports[i] != NULL; i++) + free(hub->supports[i]); + free(hub->supports); + } + arr = NULL; + arrsize = arrdata = 0; + p = args; + do + { + if((p2 = strchr(p, ' ')) != NULL) + *(p2++) = 0; + if(*p == 0) + continue; + addtobuf(arr, sstrdup(p)); + } while((p = p2) != NULL); + addtobuf(arr, NULL); + hub->supports = arr; +} + static void cmd_mynick(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { struct dcexppeer *expect; @@ -1635,6 +1694,8 @@ static void startdl(struct dcpeer *peer) canceltimer(peer->timeout); peer->state = PEER_TRNS; transferstartdl(peer->transfer, peer->sk); + peer->sk->readcb = (void (*)(struct socket *, void *))transread; + peer->sk->errcb = (void (*)(struct socket *, int, void *))transerr; } static void startul(struct dcpeer *peer) @@ -1643,12 +1704,12 @@ static void startul(struct dcpeer *peer) canceltimer(peer->timeout); peer->state = PEER_TRNS; transferstartul(peer->transfer, peer->sk); - CBREG(peer->sk, socket_write, (int (*)(struct socket *, void *))transwrite, NULL, peer); + peer->sk->writecb = (void (*)(struct socket *, void *))transwrite; } static void cmd_filelength(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { - int size; + off_t size; struct transfer *transfer; if(peer->transfer == NULL) @@ -1656,7 +1717,7 @@ static void cmd_filelength(struct socket *sk, struct dcpeer *peer, char *cmd, ch freedcpeer(peer); return; } - size = atoi(args); + size = strtoll(args, NULL, 10); if(peer->transfer->size != size) { transfersetsize(peer->transfer, size); @@ -1779,7 +1840,7 @@ static struct sharecache *resdcpath(char *path, char *charset, char sep) static void cmd_get(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { - int offset; + off_t offset; char *p, *buf; wchar_t *buf2; struct sharecache *node; @@ -1798,7 +1859,7 @@ static void cmd_get(struct socket *sk, struct dcpeer *peer, char *cmd, char *arg return; } *(p++) = 0; - if((offset = (atoi(p) - 1)) < 0) + if((offset = (strtoll(p, NULL, 10) - 1)) < 0) { freedcpeer(peer); return; @@ -1861,7 +1922,7 @@ static void cmd_get(struct socket *sk, struct dcpeer *peer, char *cmd, char *arg lesk = wrapsock(fd); transferprepul(peer->transfer, sb.st_size, offset, -1, lesk); putsock(lesk); - qstrf(sk, "$FileLength %i|", peer->transfer->size); + qstrf(sk, "$FileLength %ji|", (intmax_t)peer->transfer->size); } static void cmd_send(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) @@ -1912,7 +1973,7 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char { int fd; char *p, *p2; - int start, numbytes; + off_t start, numbytes; char *charset, *buf; wchar_t *buf2; struct sharecache *node; @@ -1931,7 +1992,7 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char return; } *(p2++) = 0; - start = atoi(p); + start = strtoll(p, NULL, 10); p = p2; if((p2 = strchr(p, ' ')) == NULL) { @@ -1939,7 +2000,7 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char return; } *(p2++) = 0; - numbytes = atoi(p); + numbytes = strtoll(p, NULL, 10); p = p2; if(!strcmp(cmd, "$UGetBlock") || !strcmp(cmd, "$UGetZBlock")) charset = "UTF-8"; @@ -2001,7 +2062,7 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char lesk = wrapsock(fd); transferprepul(peer->transfer, sb.st_size, start, start + numbytes, lesk); putsock(lesk); - qstrf(sk, "$Sending %i|", numbytes); + qstrf(sk, "$Sending %ji|", (intmax_t)numbytes); startul(peer); } @@ -2009,7 +2070,7 @@ static void cmd_adcget(struct socket *sk, struct dcpeer *peer, char *cmd, char * { int i; char **argv, *buf; - int start, numbytes; + off_t start, numbytes; struct sharecache *node; struct stat sb; struct socket *lesk; @@ -2031,8 +2092,8 @@ static void cmd_adcget(struct socket *sk, struct dcpeer *peer, char *cmd, char * freedcpeer(peer); goto out; } - start = atoi(argv[2]); - numbytes = atoi(argv[3]); + start = strtoll(argv[2], NULL, 10); + numbytes = strtoll(argv[3], NULL, 10); node = NULL; fd = -1; if(((fd = openfilelist(argv[1])) < 0) && (errno != 0)) @@ -2105,8 +2166,8 @@ static void cmd_adcget(struct socket *sk, struct dcpeer *peer, char *cmd, char * qstr(sk, "$ADCSND"); sendadc(sk, "file"); sendadc(sk, argv[1]); - sendadcf(sk, "%i", start); - sendadcf(sk, "%i", numbytes); + sendadcf(sk, "%ji", (intmax_t)start); + sendadcf(sk, "%ji", (intmax_t)numbytes); if(peer->compress == CPRS_ZLIB) sendadc(sk, "ZL1"); qstr(sk, "|"); @@ -2167,7 +2228,7 @@ static void handletthl(struct dcpeer *peer) static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { char **argv; - int start, numbytes; + off_t start, numbytes; if(peer->transfer == NULL) { @@ -2184,8 +2245,8 @@ static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char * freedcpeer(peer); goto out; } - start = atoi(argv[2]); - numbytes = atoi(argv[3]); + start = strtoll(argv[2], NULL, 10); + numbytes = strtoll(argv[3], NULL, 10); if(!strcmp(argv[0], "tthl")) { if((start != 0) || (numbytes % 24 != 0)) @@ -2215,7 +2276,12 @@ static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char * goto out; } startdl(peer); - transread(peer); + if(peer->inbufdata > 0) + { + sockpushdata(sk, peer->inbuf, peer->inbufdata); + peer->inbufdata = 0; + transread(sk, peer); + } } else { /* We certainly didn't request this...*/ freedcpeer(peer); @@ -2228,14 +2294,14 @@ static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char * static void cmd_sending(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { - int numbytes; + off_t numbytes; if(peer->transfer == NULL) { freedcpeer(peer); return; } - numbytes = atoi(args); + numbytes = strtoll(args, NULL, 10); if(peer->transfer->size - peer->transfer->curpos != numbytes) { transfersetsize(peer->transfer, peer->transfer->curpos + numbytes); @@ -2243,7 +2309,12 @@ static void cmd_sending(struct socket *sk, struct dcpeer *peer, char *cmd, char return; } startdl(peer); - transread(peer); + if(peer->inbufdata > 0) + { + sockpushdata(sk, peer->inbuf, peer->inbufdata); + peer->inbufdata = 0; + transread(sk, peer); + } } /* @@ -2282,10 +2353,10 @@ static int hubreqconn(struct fnetpeer *peer) return(1); /* Shouldn't happen, of course, but who knows... */ if(tcpsock != NULL) { - sendctm(peer->fn->sk, mbsnick); + sendctm(hub->sk, mbsnick); expectpeer(mbsnick, peer->fn); } else { - qstrf(peer->fn->sk, "$RevConnectToMe %s %s|", hub->nativenick, mbsnick); + qstrf(hub->sk, "$RevConnectToMe %s %s|", hub->nativenick, mbsnick); } free(mbsnick); return(0); @@ -2325,12 +2396,12 @@ static int hubsendchat(struct fnetnode *fn, int public, wchar_t *to, wchar_t *st { if(*to == L'\0') { - qstrf(fn->sk, "<%s> %s|", hub->nativenick, mbsstring); + qstrf(hub->sk, "<%s> %s|", hub->nativenick, mbsstring); } else { - qstrf(fn->sk, "$To: %s From: %s $<%s> %s|", mbsto, hub->nativenick, hub->nativenick, mbsstring); + qstrf(hub->sk, "$To: %s From: %s $<%s> %s|", mbsto, hub->nativenick, hub->nativenick, mbsstring); } } else { - qstrf(fn->sk, "$To: %s From: %s $<%s> %s|", mbsto, hub->nativenick, hub->nativenick, mbsstring); + qstrf(hub->sk, "$To: %s From: %s $<%s> %s|", mbsto, hub->nativenick, hub->nativenick, mbsstring); } free(mbsto); free(mbsstring); @@ -2445,7 +2516,7 @@ static int hubsearch(struct fnetnode *fn, struct search *srch, struct srchfnnlis struct hash *hash; hub = fn->data; - if((fn->state != FNN_EST) || (fn->sk == NULL) || (fn->sk->state != SOCK_EST)) + if((fn->state != FNN_EST) || (hub->sk == NULL) || (hub->sk->state != SOCK_EST)) return(1); list = findsexprstrs(srch->sexpr); findsizelimit(srch->sexpr, &minsize, &maxsize); @@ -2523,15 +2594,15 @@ static int hubsearch(struct fnetnode *fn, struct search *srch, struct srchfnnlis addtobuf(sstr, 0); if(tcpsock != NULL) { - if(sockgetremotename2(udpsock, fn->sk, &name, &namelen) < 0) + if(sockgetremotename2(udpsock, hub->sk, &name, &namelen) < 0) { flog(LOG_WARNING, "cannot get address of UDP socket"); } else { - qstrf(fn->sk, "$Search %s %s|", formataddress(name, namelen), sstr); + qstrf(hub->sk, "$Search %s %s|", formataddress(name, namelen), sstr); free(name); } } else { - qstrf(fn->sk, "$Search Hub:%s %s|", hub->nativenick, sstr); + qstrf(hub->sk, "$Search Hub:%s %s|", hub->nativenick, sstr); } free(sstr); freesl(&list); @@ -2564,6 +2635,7 @@ static struct command hubcmds[] = {"$UserCommand", cc(cmd_usercommand)}, {"$GetPass", cc(cmd_getpass)}, {"$LogedIn", cc(cmd_logedin)}, /* sic */ + {"$Supports", cc(cmd_hubsupports)}, {NULL, NULL} }; @@ -2592,7 +2664,7 @@ static struct command peercmds[] = static void dctransdetach(struct transfer *transfer, struct dcpeer *peer) { - CBUNREG(transfer, trans_filterout, trresumecb, peer); + CBUNREG(transfer, trans_filterout, peer); if(peer->freeing) return; peer->transfer = NULL; @@ -2667,7 +2739,7 @@ static void dctransgotdata(struct transfer *transfer, struct dcpeer *peer) transfersetstate(transfer, TRNS_HS); socksettos(peer->sk, confgetint("fnet", "fnptos")); transfer->flags.b.minislot = 0; - CBUNREG(peer->sk, socket_write, transwrite, peer); + peer->sk->writecb = NULL; } } } @@ -2686,22 +2758,22 @@ static void dcwantdata(struct transfer *transfer, struct dcpeer *peer) peer->sk->ignread = 0; } -static void transread(struct dcpeer *peer) +static void transread(struct socket *sk, struct dcpeer *peer) { - size_t num; + void *buf; + size_t bufsize; struct transfer *transfer; + if((buf = sockgetinbuf(sk, &bufsize)) == NULL) + return; if(peer->transfer == NULL) { + free(buf); freedcpeer(peer); return; } - if(peer->inbufsize > peer->transfer->size - peer->transfer->curpos) - num = peer->transfer->size - peer->transfer->curpos; - else - num = peer->inbufsize; - transferputdata(peer->transfer, peer->inbuf, num); - memmove(peer->inbuf, peer->inbuf + num, peer->inbufsize -= num); + transferputdata(peer->transfer, buf, bufsize); + free(buf); if(peer->transfer->curpos >= peer->transfer->size) { transfer = peer->transfer; @@ -2710,39 +2782,42 @@ static void transread(struct dcpeer *peer) return; } if(transferdatasize(peer->transfer) > 65535) - peer->sk->ignread = 1; + sk->ignread = 1; } -static void transerr(struct dcpeer *peer) +static void transerr(struct socket *sk, int err, struct dcpeer *peer) { struct transfer *transfer; if((transfer = peer->transfer) == NULL) + { + freedcpeer(peer); return; + } transferdetach(transfer); transferendofdata(transfer); } -static int transwrite(struct socket *sk, struct dcpeer *peer) +static void transwrite(struct socket *sk, struct dcpeer *peer) { if((peer->state != PEER_TRNS) && (peer->state != PEER_SYNC)) - return(1); + return; if(peer->transfer == NULL) { freedcpeer(peer); - return(1); + return; } dctransgotdata(peer->transfer, peer); - return(0); } -static int udpread(struct socket *sk, void *data) +static void udpread(struct socket *sk, void *data) { char *buf, *p, *p2, *hashbuf; size_t buflen, hashlen; char *nick, *filename, *hubname; struct sockaddr_in hubaddr; - int size, slots; + off_t size; + int slots; struct fnetnode *fn, *myfn; struct dchub *hub; struct srchres *sr; @@ -2750,7 +2825,7 @@ static int udpread(struct socket *sk, void *data) struct hash *hash; if((buf = sockgetinbuf(sk, &buflen)) == NULL) - return(0); + return; buf = srealloc(buf, buflen + 1); buf[buflen] = 0; if(!strncmp(buf, "$SR ", 4)) @@ -2760,7 +2835,7 @@ static int udpread(struct socket *sk, void *data) if((p2 = strchr(p, ' ')) == NULL) { free(buf); - return(0); + return; } *p2 = 0; p = p2 + 1; @@ -2768,22 +2843,22 @@ static int udpread(struct socket *sk, void *data) if((p2 = strchr(p, 5)) == NULL) { free(buf); - return(0); + return; } *p2 = 0; p = p2 + 1; if((p2 = strchr(p, ' ')) == NULL) { free(buf); - return(0); + return; } *p2 = 0; - size = atoi(p); + size = strtoll(p, NULL, 10); p = p2 + 1; if((p2 = strchr(p, '/')) == NULL) { free(buf); - return(0); + return; } *p2 = 0; slots = atoi(p); @@ -2791,34 +2866,34 @@ static int udpread(struct socket *sk, void *data) if((p2 = strchr(p, 5)) == NULL) { free(buf); - return(0); + return; } p = p2 + 1; hubname = p; if((p2 = strstr(p, " (")) == NULL) { free(buf); - return(0); + return; } *p2 = 0; p = p2 + 2; if((p2 = strchr(p, ':')) == NULL) { free(buf); - return(0); + return; } *(p2++) = 0; hubaddr.sin_family = AF_INET; if(!inet_aton(p, &hubaddr.sin_addr)) { free(buf); - return(0); + return; } p = p2; if((p2 = strchr(p, ')')) == NULL) { free(buf); - return(0); + return; } *p2 = 0; hubaddr.sin_port = htons(atoi(p)); @@ -2826,7 +2901,7 @@ static int udpread(struct socket *sk, void *data) if((wfile = icmbstowcs(filename, DCCHARSET)) == NULL) { free(buf); - return(0); + return; } myfn = NULL; hash = NULL; @@ -2860,10 +2935,13 @@ static int udpread(struct socket *sk, void *data) { for(fn = fnetnodes; fn != NULL; fn = fn->next) { - if((fn->fnet == &dcnet) && (fn->sk != NULL) && addreq(fn->sk->remote, (struct sockaddr *)&hubaddr)) + if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL)) { - myfn = fn; - break; + if((hub->sk != NULL) && addreq(hub->sk->remote, (struct sockaddr *)&hubaddr)) + { + myfn = fn; + break; + } } } } @@ -2873,7 +2951,7 @@ static int udpread(struct socket *sk, void *data) if((wnick = icmbstowcs(nick, (hub == NULL)?DCCHARSET:(hub->charset))) == NULL) { free(buf); - return(0); + return; } sr = newsrchres(&dcnet, wfile, wnick); if(sr->peernick != NULL) @@ -2891,7 +2969,6 @@ static int udpread(struct socket *sk, void *data) freesrchres(sr); } free(buf); - return(0); } static void hubread(struct socket *sk, struct fnetnode *fn) @@ -3033,9 +3110,11 @@ static void freedcpeer(struct dcpeer *peer) } if(peer->timeout != NULL) canceltimer(peer->timeout); - /* XXX: Unregister transwrite from peer->sk->socket_write? */ - CBUNREG(peer->sk, socket_read, peerread, peer); - CBUNREG(peer->sk, socket_err, peererror, peer); + if(peer->sk->data == peer) + peer->sk->data = NULL; + peer->sk->readcb = NULL; + peer->sk->writecb = NULL; + peer->sk->errcb = NULL; putsock(peer->sk); endcompress(peer); if(peer->supports != NULL) @@ -3062,29 +3141,34 @@ static void freedcpeer(struct dcpeer *peer) numdcpeers--; } -static void hubconnect(struct fnetnode *fn) +static void hubconnect(struct fnetnode *fn, struct socket *sk) { - CBREG(fn->sk, socket_read, (int (*)(struct socket *, void *))hubread, (void (*)(void *))putfnetnode, getfnetnode(fn)); - CBREG(fn->sk, socket_err, (int (*)(struct socket *, int, void *))huberr, (void (*)(void *))putfnetnode, getfnetnode(fn)); - fn->data = newdchub(fn); + struct dchub *hub; + + sk->readcb = (void (*)(struct socket *, void *))hubread; + sk->errcb = (void (*)(struct socket *, int, void *))huberr; + fn->data = hub = newdchub(fn); + sk->data = fn; + getsock(hub->sk = sk); return; } static void hubdestroy(struct fnetnode *fn) { + int i; struct dchub *hub; struct qcommand *qcmd; hub = (struct dchub *)fn->data; - if(fn->sk != NULL) - { - CBUNREG(fn->sk, socket_read, hubread, fn); - CBUNREG(fn->sk, socket_err, huberr, fn); - } - if(hub == NULL) - return; + putsock(hub->sk); while((qcmd = ulqcmd(&hub->queue)) != NULL) freeqcmd(qcmd); + if(hub->supports != NULL) + { + for(i = 0; hub->supports[i] != NULL; i++) + free(hub->supports[i]); + free(hub->supports); + } if(hub->nativename != NULL) free(hub->nativename); if(hub->nativenick != NULL) @@ -3096,6 +3180,14 @@ static void hubdestroy(struct fnetnode *fn) free(hub); } +static void hubkill(struct fnetnode *fn) +{ + struct dchub *hub; + + hub = (struct dchub *)fn->data; + hub->sk->close = 1; +} + static wchar_t *dcbasename(wchar_t *filename) { wchar_t *ret; @@ -3118,6 +3210,7 @@ static struct fnet dcnet = .name = L"dc", .connect = hubconnect, .destroy = hubdestroy, + .kill = hubkill, .setnick = hubsetnick, .reqconn = hubreqconn, .sendchat = hubsendchat, @@ -3125,61 +3218,48 @@ static struct fnet dcnet = .filebasename = dcbasename }; -static void cmdread(struct dcpeer *peer) -{ - char *p; - struct command *cmd; - - p = peer->inbuf; - while((peer->inbufdata > 0) && (p = memchr(peer->inbuf, '|', peer->inbufdata)) != NULL) - { - *(p++) = 0; - newqcmd(&peer->queue, peer->inbuf); - for(cmd = peercmds; cmd->handler != NULL; cmd++) - { - if(!memcmp(peer->inbuf, cmd->name, strlen(cmd->name)) && ((peer->inbuf[strlen(cmd->name)] == ' ') || (peer->inbuf[strlen(cmd->name)] == '|'))) - break; - } - memmove(peer->inbuf, p, peer->inbufdata -= p - peer->inbuf); - if(cmd->stop) - { - peer->state = PEER_STOP; - break; - } - } -} - -static int peerread(struct socket *sk, struct dcpeer *peer) +static void peerread(struct socket *sk, struct dcpeer *peer) { - char *newbuf; + char *newbuf, *p; size_t datalen; + struct command *cmd; if((newbuf = sockgetinbuf(sk, &datalen)) == NULL) - return(0); + return; sizebuf2(peer->inbuf, peer->inbufdata + datalen, 1); memcpy(peer->inbuf + peer->inbufdata, newbuf, datalen); free(newbuf); peer->inbufdata += datalen; if(peer->state == PEER_CMD) { - cmdread(peer); - } else if(peer->state == PEER_TRNS) { - transread(peer); + p = peer->inbuf; + while((peer->inbufdata > 0) && (p = memchr(peer->inbuf, '|', peer->inbufdata)) != NULL) + { + *(p++) = 0; + newqcmd(&peer->queue, peer->inbuf); + for(cmd = peercmds; cmd->handler != NULL; cmd++) + { + if(!memcmp(peer->inbuf, cmd->name, strlen(cmd->name)) && ((peer->inbuf[strlen(cmd->name)] == ' ') || (peer->inbuf[strlen(cmd->name)] == '|'))) + break; + } + memmove(peer->inbuf, p, peer->inbufdata -= p - peer->inbuf); + if(cmd->stop) + { + peer->state = PEER_STOP; + break; + } + } } else if(peer->state == PEER_TTHL) { handletthl(peer); } - return(0); } -static int peererror(struct socket *sk, int err, struct dcpeer *peer) +static void peererror(struct socket *sk, int err, struct dcpeer *peer) { - if(peer->state == PEER_TRNS) - transerr(peer); freedcpeer(peer); - return(0); } -static int peerconnect(struct socket *sk, int err, struct fnetnode *fn) +static void peerconnect(struct socket *sk, int err, struct fnetnode *fn) { struct dcpeer *peer; struct dchub *hub; @@ -3188,34 +3268,34 @@ static int peerconnect(struct socket *sk, int err, struct fnetnode *fn) { putfnetnode(fn); putsock(sk); - return(1); + return; } hub = fn->data; peer = newdcpeer(sk); peer->fn = fn; peer->accepted = 0; peer->dcppemu = hub->dcppemu; - CBREG(sk, socket_read, (int (*)(struct socket *, void *))peerread, NULL, peer); - CBREG(sk, socket_err, (int (*)(struct socket *, int, void *))peererror, NULL, peer); + sk->readcb = (void (*)(struct socket *, void *))peerread; + sk->errcb = (void (*)(struct socket *, int, void *))peererror; + sk->data = peer; socksettos(sk, confgetint("fnet", "fnptos")); putsock(sk); peer->timeout = timercallback(ntime() + 180, (void (*)(int, void *))peertimeout, peer); sendmynick(peer); sendpeerlock(peer); - return(1); } -static int peeraccept(struct socket *sk, struct socket *newsk, void *data) +static void peeraccept(struct socket *sk, struct socket *newsk, void *data) { struct dcpeer *peer; peer = newdcpeer(newsk); peer->accepted = 1; - CBREG(sk, socket_read, (int (*)(struct socket *, void *))peerread, NULL, peer); - CBREG(sk, socket_err, (int (*)(struct socket *, int, void *))peererror, NULL, peer); + newsk->readcb = (void (*)(struct socket *, void *))peerread; + newsk->errcb = (void (*)(struct socket *, int, void *))peererror; + newsk->data = peer; socksettos(newsk, confgetint("fnet", "fnptos")); peer->timeout = timercallback(ntime() + 180, (void (*)(int, void *))peertimeout, peer); - return(0); } static void updatehmlist(void) @@ -3243,7 +3323,7 @@ static void updatehmlist(void) if(node->f.b.type == FILE_REG) { addtobuf(buf, '|'); - sprintf(numbuf, "%i", node->size); + sprintf(numbuf, "%ji", (intmax_t)node->size); bufcat(buf, numbuf, strlen(numbuf)); } addtobuf(buf, 13); @@ -3418,7 +3498,7 @@ static void updatexmllist(void) lev++; continue; } else { - fprintf(fs, "size); + fprintf(fs, "size); if(node->f.b.hastth) { hashbuf = base32encode(node->hashtth, 24); @@ -3528,7 +3608,7 @@ static void updatelists(int now) if(!now) { if(listwritetimer == NULL) - listwritetimer = timercallback(ntime() + 300, listtimercb, NULL); + listwritetimer = timercallback(ntime() + confgetint("cli", "hashwritedelay"), listtimercb, NULL); return; } if(listwritetimer != NULL) @@ -3544,6 +3624,78 @@ static int shareupdate(unsigned long long uusharesize, void *data) return(0); } +static char *quotestr(char *str) +{ + unsigned char *buf; + unsigned char *p; + size_t bufsize, bufdata; + wchar_t *wbuf; + static char *enc = NULL; + size_t encsize, encdata; + + buf = NULL; + bufsize = bufdata = 0; + for(p = (unsigned char *)str; *p; p++) + { + if(*p == '\b') + bufcat(buf, "\\b", 2); + else if(*p == '\t') + bufcat(buf, "\\t", 2); + else if(*p == '\n') + bufcat(buf, "\\n", 2); + else if(*p == '\r') + bufcat(buf, "\\r", 2); + else if(*p == '\\') + bufcat(buf, "\\\\", 2); + else if(*p >= 32) + addtobuf(buf, *p); + else + bprintf(buf, "\\x%02x", *p); + } + addtobuf(buf, 0); + if(enc != NULL) + free(enc); + enc = NULL; + if((wbuf = icmbstowcs((char *)buf, DCCHARSET)) != NULL) + { + enc = icwcstombs(wbuf, NULL); + free(wbuf); + } + if(enc == NULL) + { + encsize = encdata = 0; + for(p = buf; *p; p++) { + if(*p < 128) + addtobuf(enc, *p); + else + bprintf(buf, "\\x%x", *p); + } + } + free(buf); + return(enc); +} + +static void logunimpl(char *list, char *cmd, char *args) +{ + FILE *log; + + if((log = fopen("/tmp/dc-unimpl", "a")) == NULL) + { + flog(LOG_WARNING, "could not open unimpl log: %s", strerror(errno)); + return; + } + fputs(list, log); + fputc('\t', log); + fputs(quotestr(cmd), log); + if(args != NULL) + { + fputc('\t', log); + fputs(quotestr(args), log); + } + fputc('\n', log); + fclose(log); +} + static void dispatchcommand(struct qcommand *qcmd, struct command *cmdlist, struct socket *sk, void *data) { char *p; @@ -3557,11 +3709,16 @@ static void dispatchcommand(struct qcommand *qcmd, struct command *cmdlist, stru break; } if(cmd->handler != NULL) + { cmd->handler(sk, data, qcmd->string, p); -/* - else - flog(LOG_DEBUG, "Unimplemented DC command: %s \"%s\"", qcmd->string, p?p:"noargs"); -*/ + } else if(confgetint("dc", "logunimpl")) { + if(cmdlist == hubcmds) + logunimpl("hub", qcmd->string, p); + else if(cmdlist == peercmds) + logunimpl("peer", qcmd->string, p); + else + logunimpl("other?!", qcmd->string, p); + } } static int run(void) @@ -3585,10 +3742,10 @@ static int run(void) { if(*qcmd->string == '$') { - if((fn->sk != NULL) && (fn->sk->state == SOCK_EST)) - dispatchcommand(qcmd, hubcmds, fn->sk, fn); + if((hub->sk != NULL) && (hub->sk->state == SOCK_EST)) + dispatchcommand(qcmd, hubcmds, hub->sk, fn); } else if(*qcmd->string != 0) { - hubrecvchat(fn->sk, fn, NULL, qcmd->string); + hubrecvchat(hub->sk, fn, NULL, qcmd->string); } freeqcmd(qcmd); ret = 1; @@ -3633,7 +3790,7 @@ static int updateudpport(struct configvar *var, void *uudata) flog(LOG_WARNING, "could not create new DC UDP socket, reverting to old: %s", strerror(errno)); return(0); } - CBREG(newsock, socket_read, udpread, NULL, NULL); + newsock->readcb = udpread; if(udpsock != NULL) putsock(udpsock); udpsock = newsock; @@ -3675,7 +3832,7 @@ static int init(int hup) flog(LOG_CRIT, "could not create DC UDP socket: %s", strerror(errno)); return(1); } - CBREG(udpsock, socket_read, udpread, NULL, NULL); + udpsock->readcb = udpread; addr.sin_port = htons(confgetint("dc", "tcpport")); if((tcpsock = netcslisten(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), peeraccept, NULL)) == NULL) flog(LOG_INFO, "could not listen to a remote address, going into passive mode"); @@ -3707,12 +3864,41 @@ static void terminate(void) static struct configvar myvars[] = { + /** Specifies the share description reported to other DC users. */ {CONF_VAR_STRING, "desc", {.str = L""}}, + /** Specifies the speed reported to other DC users. Normal values + * are 28.8Kbps, 33.6Kbps, 56Kbps, Satellite, ISDN, DSL, Cable, + * LAN(T1) or LAN(T3)*/ {CONF_VAR_STRING, "speedstring", {.str = L"LAN(T1)"}}, + /** The e-mail address to report to other DC users. */ {CONF_VAR_STRING, "email", {.str = L"spam@spam.org"}}, + /** Specifies a specific UDP port to use for DC search results. If + * left unspecified, a port is allocated dynamically. Useful for + * NAT routers (see also the net.visibleipv4 address for those + * cases). */ {CONF_VAR_INT, "udpport", {.num = 0}}, + /** Specifies a specific TCP port to use for DC peer + * connections. If left unspecified, a port is allocated + * dynamically. Useful for NAT routers (see also the + * net.visibleipv4 address for those cases). */ {CONF_VAR_INT, "tcpport", {.num = 0}}, + /** If set to true, doldacond will do its best to emulate DC++ + * (currently v0.674). This should be left off if at all possible, + * since turning it on will violate the rules of most hubs and + * thus give hub owners an actual reason to kick you if it is + * detected. It might be needed for some of the more bone-headed + * hub owners, though. Note that DC++ emulation can also be turned + * on or off for individual hubs, overriding this setting. */ {CONF_VAR_BOOL, "dcppemu", {.num = 0}}, + /** Use for debugging. If set to true, doldacond will log all + * unknown commands it receives, and their arguments, to + * /tmp/dc-unimpl. */ + {CONF_VAR_BOOL, "logunimpl", {.num = 0}}, + /** If set to true, doldacond will hide its support for deflate + * compression of transfers from other clients, so that they will + * not request compressed uploads. Compressed transfers may + * consume a non-trivial amount of CPU time on slower machines. */ + {CONF_VAR_BOOL, "hidedeflate", {.num = 0}}, {CONF_VAR_END} };