Merge branch 'master' of git.dolda2000.com:/srv/git/r/doldaconnect
[doldaconnect.git] / daemon / fnet-dc.c
index 01592c6..f41f9bf 100644 (file)
@@ -91,6 +91,7 @@ struct command
     char *name;
     void (*handler)(struct socket *sk, void *data, char *cmd, char *args);
     int stop;
+    int limit;
 };
 
 struct qcommand
@@ -99,12 +100,18 @@ struct qcommand
     char *string;
 };
 
+struct qcmdqueue
+{
+    struct qcommand *f, *l;
+    int size;
+};
+
 struct dchub
 {
     struct socket *sk;
     char *inbuf;
     size_t inbufdata, inbufsize;
-    struct qcommand *queue;
+    struct qcmdqueue queue;
     int extended, dcppemu;
     char *charset;
     char *nativename;
@@ -127,10 +134,10 @@ 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;
+    struct qcmdqueue queue;
     struct transfer *transfer;
     int state;
     int ptclose;      /* Close after transfer is complete */
@@ -376,26 +383,31 @@ static struct dcexppeer *expectpeer(char *nick, struct fnetnode *fn)
     return(ep);
 }
 
-static struct qcommand *newqcmd(struct qcommand **queue, char *string)
+static struct qcommand *newqcmd(struct qcmdqueue *queue, char *string)
 {
     struct qcommand *new;
     
-    while(*queue != NULL)
-       queue = &(*queue)->next;
     new = smalloc(sizeof(*new));
     new->string = sstrdup(string);
-    new->next = *queue;
-    *queue = new;
+    new->next = NULL;
+    if(queue->l == NULL)
+       queue->f = new;
+    else
+       queue->l->next = new;
+    queue->l = new;
+    queue->size++;
     return(new);
 }
 
-static struct qcommand *ulqcmd(struct qcommand **queue)
+static struct qcommand *ulqcmd(struct qcmdqueue *queue)
 {
     struct qcommand *qcmd;
     
-    if((qcmd = *queue) == NULL)
+    if((qcmd = queue->f) == NULL)
        return(NULL);
-    *queue = qcmd->next;
+    if((queue->f = qcmd->next) == NULL)
+       queue->l = NULL;
+    queue->size--;
     return(qcmd);
 }
 
@@ -502,7 +514,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;
@@ -637,7 +653,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);
        }
@@ -740,8 +756,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)
@@ -750,7 +766,7 @@ static void requestfile(struct dcpeer *peer)
            freedcpeer(peer);
            return;
        }
-       qstrf(peer->sk, "$UGetBlock %zi %zi %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)
@@ -759,7 +775,7 @@ static void requestfile(struct dcpeer *peer)
            freedcpeer(peer);
            return;
        }
-       qstrf(peer->sk, "$Get %s$%zi|", buf, peer->transfer->curpos + 1);
+       qstrf(peer->sk, "$Get %s$%ji|", buf, (intmax_t)peer->transfer->curpos + 1);
     }
 }
 
@@ -901,10 +917,10 @@ static void cmd_nicklist(struct socket *sk, struct fnetnode *fn, char *cmd, char
     struct dchub *hub;
     char *p;
     wchar_t *buf;
-    struct fnetpeer *peer, *npeer;
+    struct fnetpeer *peer;
     
     hub = fn->data;
-    for(peer = fn->peers; peer != NULL; peer = peer->next)
+    for(peer = btreeiter(fn->peers); peer != NULL; peer = btreeiter(NULL))
        peer->flags.b.delete = 1;
     while((p = strstr(args, "$$")) != NULL)
     {
@@ -920,12 +936,7 @@ static void cmd_nicklist(struct socket *sk, struct fnetnode *fn, char *cmd, char
        }
        args = p + 2;
     }
-    for(peer = fn->peers; peer != NULL; peer = npeer)
-    {
-       npeer = peer->next;
-       if(peer->flags.b.delete)
-           fnetdelpeer(peer);
-    }
+    fnetpeerdm(fn);
     hubhandleaction(sk, fn, cmd, args);
 }
 
@@ -937,7 +948,7 @@ static void cmd_oplist(struct socket *sk, struct fnetnode *fn, char *cmd, char *
     struct fnetpeer *peer;
     
     hub = fn->data;
-    for(peer = fn->peers; peer != NULL; peer = peer->next)
+    for(peer = btreeiter(fn->peers); peer != NULL; peer = btreeiter(NULL))
        peer->flags.b.op = 0;
     while((p = strstr(args, "$$")) != NULL)
     {
@@ -1257,10 +1268,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%zi%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%zi%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);
            }
@@ -1410,7 +1421,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;
@@ -1429,7 +1441,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;
@@ -1704,7 +1716,7 @@ static void startul(struct dcpeer *peer)
 
 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)
@@ -1712,7 +1724,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);
@@ -1835,7 +1847,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;
@@ -1854,7 +1866,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;
@@ -1917,7 +1929,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 %zi|", 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)
@@ -1968,7 +1980,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;
@@ -1987,7 +1999,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)
     {
@@ -1995,7 +2007,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";
@@ -2057,7 +2069,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);
 }
 
@@ -2065,7 +2077,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;
@@ -2087,8 +2099,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))
@@ -2161,8 +2173,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, "|");
@@ -2223,7 +2235,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)
     {
@@ -2240,8 +2252,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))
@@ -2289,14 +2301,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);
@@ -2620,10 +2632,10 @@ static struct command hubcmds[] =
     {"$OpList", cc(cmd_oplist)},
     {"$MyINFO", cc(cmd_myinfo)},
     {"$ForceMove", cc(cmd_forcemove)},
-    {"$Search", cc(cmd_search)},
-    {"$MultiSearch", cc(cmd_search)},
-    {"$ConnectToMe", cc(cmd_connecttome)},
-    {"$RevConnectToMe", cc(cmd_revconnecttome)},
+    {"$Search", cc(cmd_search), .limit = 100},
+    {"$MultiSearch", cc(cmd_search), .limit = 50},
+    {"$ConnectToMe", cc(cmd_connecttome), .limit = 200},
+    {"$RevConnectToMe", cc(cmd_revconnecttome), .limit = 500},
     {"$GetNetInfo", cc(cmd_getnetinfo)},
     {"$To:", cc(cmd_to)},
     {"$SR", cc(cmd_sr)},
@@ -2651,8 +2663,8 @@ static struct command peercmds[] =
     {"$GetZBlock", cc(cmd_getblock)},
     {"$UGetZBlock", cc(cmd_getblock)},
     {"$ADCGET", cc(cmd_adcget)},
-    {"$ADCSND", cc(cmd_adcsnd), 1},
-    {"$Sending", cc(cmd_sending), 1},
+    {"$ADCSND", cc(cmd_adcsnd), .stop = 1},
+    {"$Sending", cc(cmd_sending), .stop = 1},
     {NULL, NULL}
 };
 #undef cc
@@ -2811,7 +2823,8 @@ static void udpread(struct socket *sk, void *data)
     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;
@@ -2847,7 +2860,7 @@ static void udpread(struct socket *sk, void *data)
            return;
        }
        *p2 = 0;
-       size = atoi(p);
+       size = strtoll(p, NULL, 10);
        p = p2 + 1;
        if((p2 = strchr(p, '/')) == NULL)
        {
@@ -2968,8 +2981,9 @@ static void udpread(struct socket *sk, void *data)
 static void hubread(struct socket *sk, struct fnetnode *fn)
 {
     struct dchub *hub;
+    struct command *cmd;
     char *newbuf;
-    size_t datalen;
+    size_t datalen, cnlen;
     char *p;
     
     hub = (struct dchub *)fn->data;
@@ -2985,11 +2999,20 @@ static void hubread(struct socket *sk, struct fnetnode *fn)
     while((datalen > 0) && ((p = memchr(p, '|', datalen)) != NULL))
     {
        *(p++) = 0;
-       newqcmd(&hub->queue, hub->inbuf);
+       for(cmd = hubcmds; cmd->handler != NULL; cmd++)
+       {
+           cnlen = strlen(cmd->name);
+           if(!strncmp(hub->inbuf, cmd->name, cnlen) && ((hub->inbuf[cnlen] == ' ') || (hub->inbuf[cnlen] == 0)))
+               break;
+       }
+       if((cmd->limit == 0) || (hub->queue.size < cmd->limit))
+           newqcmd(&hub->queue, hub->inbuf);
        memmove(hub->inbuf, p, hub->inbufdata -= p - hub->inbuf);
        datalen = hub->inbufdata;
        p = hub->inbuf;
     }
+    if(hub->queue.size > 1000)
+       sk->ignread = 1;
 }
 
 static void huberr(struct socket *sk, int err, struct fnetnode *fn)
@@ -3215,7 +3238,7 @@ static struct fnet dcnet =
 static void peerread(struct socket *sk, struct dcpeer *peer)
 {
     char *newbuf, *p;
-    size_t datalen;
+    size_t datalen, cnlen;
     struct command *cmd;
 
     if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
@@ -3230,22 +3253,29 @@ static void peerread(struct socket *sk, struct dcpeer *peer)
        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)] == '|')))
+               cnlen = strlen(cmd->name);
+               if(!strncmp(peer->inbuf, cmd->name, cnlen) && ((peer->inbuf[cnlen] == ' ') || (peer->inbuf[cnlen] == 0)))
                    break;
            }
+           if((cmd->limit == 0) || (peer->queue.size < cmd->limit))
+               newqcmd(&peer->queue, peer->inbuf);
            memmove(peer->inbuf, p, peer->inbufdata -= p - peer->inbuf);
            if(cmd->stop)
            {
                peer->state = PEER_STOP;
                break;
+           } else {
+               if(peer->queue.size > 50)
+                   sk->ignread = 1;
            }
        }
     } else if(peer->state == PEER_TTHL) {
        handletthl(peer);
     }
+    if(peer->inbufdata > 500000)
+       sk->ignread = 1;
 }
 
 static void peererror(struct socket *sk, int err, struct dcpeer *peer)
@@ -3317,7 +3347,7 @@ static void updatehmlist(void)
            if(node->f.b.type == FILE_REG)
            {
                addtobuf(buf, '|');
-               sprintf(numbuf, "%zi", node->size);
+               sprintf(numbuf, "%ji", (intmax_t)node->size);
                bufcat(buf, numbuf, strlen(numbuf));
            }
            addtobuf(buf, 13);
@@ -3492,7 +3522,7 @@ static void updatexmllist(void)
                lev++;
                continue;
            } else {
-               fprintf(fs, "<File Name=\"%s\" Size=\"%zi\"", namebuf, node->size);
+               fprintf(fs, "<File Name=\"%s\" Size=\"%ji\"", namebuf, (intmax_t)node->size);
                if(node->f.b.hastth)
                {
                    hashbuf = base32encode(node->hashtth, 24);
@@ -3721,9 +3751,10 @@ static int run(void)
     struct dchub *hub;
     struct dcpeer *peer, *nextpeer;
     struct qcommand *qcmd;
-    int ret;
+    int ret, quota;
     
     ret = 0;
+    quota = 20;
     for(fn = fnetnodes; fn != NULL; fn = nextfn)
     {
        nextfn = fn->next;
@@ -3732,7 +3763,7 @@ static int run(void)
        if(fn->data == NULL)
            continue;
        hub = (struct dchub *)fn->data;
-       if((qcmd = ulqcmd(&hub->queue)) != NULL)
+       while((quota > 0) && ((qcmd = ulqcmd(&hub->queue)) != NULL))
        {
            if(*qcmd->string == '$')
            {
@@ -3743,13 +3774,18 @@ static int run(void)
            }
            freeqcmd(qcmd);
            ret = 1;
-           break;
+           quota--;
        }
+       if(hub->queue.size < 1000)
+           hub->sk->ignread = 0;
+       if(quota < 1)
+           break;
     }
+    quota = 20;
     for(peer = peers; peer != NULL; peer = nextpeer)
     {
        nextpeer = peer->next;
-       if((qcmd = ulqcmd(&peer->queue)) != NULL)
+       while((quota > 0) && ((qcmd = ulqcmd(&peer->queue)) != NULL))
        {
            if(peer->timeout != NULL)
                canceltimer(peer->timeout);
@@ -3758,8 +3794,12 @@ static int run(void)
                dispatchcommand(qcmd, peercmds, peer->sk, peer);
            freeqcmd(qcmd);
            ret = 1;
-           break;
+           quota--;
        }
+       if((peer->queue.size < 50) && (peer->inbufdata < 500000))
+           peer->sk->ignread = 0;
+       if(quota < 1)
+           break;
     }
     return(ret);
 }