Incremental work on excorcising the transfer iface.
[doldaconnect.git] / daemon / fnet-dc.c
index ebfea28..d2343da 100644 (file)
@@ -122,6 +122,7 @@ struct dcpeer
     struct timer *timeout;
     struct qcmdqueue queue;
     struct transfer *transfer;
+    struct socket *trpipe;
     int state;
     int ptclose;      /* Close after transfer is complete */
     int accepted;     /* If false, we connected, otherwise, we accepted */
@@ -139,9 +140,8 @@ struct dcpeer
 };
 
 static struct fnet dcnet;
-static struct transferiface dctransfer;
 static struct socket *udpsock = NULL;
-static struct socket *tcpsock = NULL;
+static struct lport *tcpsock = NULL;
 static struct dcpeer *peers = NULL;
 int numdcpeers = 0;
 static struct dcexppeer *expected = NULL;
@@ -150,6 +150,7 @@ static char *xmllistname = NULL;
 static char *xmlbz2listname = NULL;
 static struct timer *listwritetimer = NULL;
 
+static struct socket *mktrpipe(struct dcpeer *peer);
 static void peerconnect(struct socket *sk, int err, struct fnetnode *fn);
 static void freedcpeer(struct dcpeer *peer);
 static void transread(struct socket *sk, struct dcpeer *peer);
@@ -1145,7 +1146,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(hub->sk->remote, hub->sk->remotelen), args + 4);
+       postfix = sprintf2(" (%s)\005%s|", formatsockpeer(hub->sk), args + 4);
        dsk = sk;
        getsock(dsk);
     } else {
@@ -1158,8 +1159,8 @@ 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(hub->sk->remote, hub->sk->remotelen));
-       netdgramconn(dsk = netdupsock(udpsock), (struct sockaddr *)&addr, sizeof(addr));
+       postfix = sprintf2(" (%s)|", formatsockpeer(hub->sk));
+       dsk = netdgramconn(udpsock, (struct sockaddr *)&addr, sizeof(addr));
     }
     
     minsize = maxsize = -1;
@@ -1351,7 +1352,7 @@ static void sendctm(struct socket *sk, char *nick)
     
     if(tcpsock == NULL)
        return;
-    if(sockgetremotename2(tcpsock, sk, &addr, &addrlen) < 0)
+    if(lstgetremotename2(tcpsock, sk, &addr, &addrlen) < 0)
        return;
     if(addr->sa_family == AF_INET)
        qstrf(sk, "$ConnectToMe %s %s|", nick, formataddress(addr, addrlen));
@@ -1622,14 +1623,14 @@ static void cmd_direction(struct socket *sk, struct dcpeer *peer, char *cmd, cha
                peer->close = 1;
                return;
            }
-           transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer);
+           transfer = newupload(peer->fn, &dcnet, peer->wcsname, peer->trpipe = mktrpipe(peer));
        } else {
            if((transfer = finddownload(peer->wcsname)) == NULL)
            {
                peer->close = 1;
                return;
            }
-           transferattach(transfer, &dctransfer, peer);
+           transferattach(transfer, peer->trpipe = mktrpipe(peer));
            transfersetstate(transfer, TRNS_HS);
        }
        transfersetnick(transfer, peer->wcsname);
@@ -1674,10 +1675,10 @@ static void cmd_peerlock(struct socket *sk, struct dcpeer *peer, char *cmd, char
                return;
            }
            peer->direction = TRNSD_UP;
-           transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer);
+           transfer = newupload(peer->fn, &dcnet, peer->wcsname, peer->trpipe = mktrpipe(peer));
        } else {
            peer->direction = TRNSD_DOWN;
-           transferattach(transfer, &dctransfer, peer);
+           transferattach(transfer, peer->trpipe = mktrpipe(peer));
            transfersetstate(transfer, TRNS_HS);
        }
        transfersetnick(transfer, peer->wcsname);
@@ -2294,7 +2295,6 @@ static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char *
        {
            sockpushdata(sk, peer->inbuf, peer->inbufdata);
            peer->inbufdata = 0;
-           transread(sk, peer);
        }
     } else {
        /* We certainly didn't request this...*/
@@ -2327,7 +2327,6 @@ static void cmd_sending(struct socket *sk, struct dcpeer *peer, char *cmd, char
     {
        sockpushdata(sk, peer->inbuf, peer->inbufdata);
        peer->inbufdata = 0;
-       transread(sk, peer);
     }
 }
 
@@ -2676,6 +2675,15 @@ static struct command peercmds[] =
 };
 #undef cc
 
+static struct socket *mktrpipe(struct dcpeer *peer)
+{
+    struct socket *sk;
+    
+    sk = netsockpipe();
+    sk->data = peer;
+    return(sk);
+}
+
 static void dctransdetach(struct transfer *transfer, struct dcpeer *peer)
 {
     CBUNREG(transfer, trans_filterout, peer);
@@ -2693,7 +2701,7 @@ static void dctransgotdata(struct transfer *transfer, struct dcpeer *peer)
     
     if((peer->state == PEER_TRNS) || (peer->state == PEER_SYNC))
     {
-       if(sockqueuesize(peer->sk) < 65536)
+       if(sockqueueleft(peer->sk) > 0)
        {
            if((buf = transfergetdata(transfer, &bufsize)) != NULL)
            {
@@ -2764,18 +2772,14 @@ static void dctransendofdata(struct transfer *transfer, struct dcpeer *peer)
     dctransgotdata(transfer, peer);
 }
 
-static void dcwantdata(struct transfer *transfer, struct dcpeer *peer)
-{
-    if(transferdatasize(transfer) < 65536)
-       peer->sk->ignread = 0;
-}
-
 static void transread(struct socket *sk, struct dcpeer *peer)
 {
     void *buf;
     size_t bufsize;
     struct transfer *transfer;
     
+    if(transferdatasize(peer->transfer) < 0)
+       return;
     if((buf = sockgetinbuf(sk, &bufsize)) == NULL)
        return;
     if(peer->transfer == NULL)
@@ -2793,8 +2797,12 @@ static void transread(struct socket *sk, struct dcpeer *peer)
        transferendofdata(transfer);
        return;
     }
-    if(transferdatasize(peer->transfer) > 65535)
-       sk->ignread = 1;
+}
+
+static void dcwantdata(struct transfer *transfer, struct dcpeer *peer)
+{
+    if(transferdatasize(transfer) > 0)
+       transread(peer->sk, peer);
 }
 
 static void transerr(struct socket *sk, int err, struct dcpeer *peer)
@@ -2828,6 +2836,7 @@ static void udpread(struct socket *sk, void *data)
     size_t buflen, hashlen;
     char *nick, *filename, *hubname;
     struct sockaddr_in hubaddr;
+    struct sockaddr *addrbuf;
     off_t size;
     int slots;
     struct fnetnode *fn, *myfn;
@@ -2947,13 +2956,15 @@ static void udpread(struct socket *sk, void *data)
        {
            for(fn = fnetnodes; fn != NULL; fn = fn->next)
            {
-               if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL))
+               if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL) && !sockpeeraddr(hub->sk, &addrbuf, NULL))
                {
-                   if((hub->sk != NULL) && addreq(hub->sk->remote, (struct sockaddr *)&hubaddr))
+                   if((hub->sk != NULL) && addreq(addrbuf, (struct sockaddr *)&hubaddr))
                    {
                        myfn = fn;
+                       free(addrbuf);
                        break;
                    }
+                   free(addrbuf);
                }
            }
        }
@@ -2992,6 +3003,8 @@ static void hubread(struct socket *sk, struct fnetnode *fn)
     char *p, *p2;
     
     hub = (struct dchub *)fn->data;
+    if(hub->queue.size > 1000)
+       return;
     if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
        return;
     if(hub->inbufdata > 500000) /* Discard possible malicious data */
@@ -3015,8 +3028,6 @@ static void hubread(struct socket *sk, struct fnetnode *fn)
        p = p2;
     }
     memmove(hub->inbuf, p, hub->inbufdata -= p - hub->inbuf);
-    if(hub->queue.size > 1000)
-       sk->ignread = 1;
 }
 
 static void huberr(struct socket *sk, int err, struct fnetnode *fn)
@@ -3120,6 +3131,10 @@ static void freedcpeer(struct dcpeer *peer)
        peer->next->prev = peer->prev;
     if(peer->prev != NULL)
        peer->prev->next = peer->next;
+    if(peer->trpipe != NULL) {
+       closesock(peer->trpipe);
+       putsock(peer->trpipe);
+    }
     if(peer->transfer != NULL)
     {
        if(peer->transfer->dir == TRNSD_UP)
@@ -3204,17 +3219,9 @@ static void hubkill(struct fnetnode *fn)
     struct dchub *hub;
     
     hub = (struct dchub *)fn->data;
-    hub->sk->close = 1;
+    closesock(hub->sk);
 }
 
-static struct transferiface dctransfer =
-{
-    .detach = (void (*)(struct transfer *, void *))dctransdetach,
-    .gotdata = (void (*)(struct transfer *, void *))dctransgotdata,
-    .endofdata = (void (*)(struct transfer *, void *))dctransendofdata,
-    .wantdata = (void (*)(struct transfer *, void *))dcwantdata
-};
-
 static struct fnet dcnet =
 {
     .name = L"dc",
@@ -3233,6 +3240,10 @@ static void peerread(struct socket *sk, struct dcpeer *peer)
     size_t datalen, cnlen;
     struct command *cmd;
 
+    if(peer->state == PEER_CMD) {
+       if((peer->queue.size > 50) || (peer->inbufdata > 65536))
+           return;
+    }
     if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
        return;
     sizebuf2(peer->inbuf, peer->inbufdata + datalen, 1);
@@ -3258,16 +3269,11 @@ static void peerread(struct socket *sk, struct dcpeer *peer)
            {
                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)
@@ -3301,7 +3307,7 @@ static void peerconnect(struct socket *sk, int err, struct fnetnode *fn)
     sendpeerlock(peer);
 }
 
-static void peeraccept(struct socket *sk, struct socket *newsk, void *data)
+static void peeraccept(struct lport *lp, struct socket *newsk, void *data)
 {
     struct dcpeer *peer;
     
@@ -3321,6 +3327,7 @@ static void updatehmlist(void)
     char *buf, *buf2, numbuf[32];
     size_t bufsize, bufdata;
     int fd, ibuf;
+    FILE *out;
     
     bufdata = 0;
     buf = smalloc(bufsize = 65536);
@@ -3378,27 +3385,28 @@ static void updatehmlist(void)
        free(hmlistname);
        hmlistname = NULL;
     } else {
+       out = fdopen(fd, "w");
        /*
         * I do not want to implement a good Huffman encoder, and it's not
         * like Huffman encoding actually yields any impressive results
         * for DC file lists anyway, so I'll just output a bogus
         * tree. Implement a good encoder if you want to.
         */
-       write(fd, "HE3\r\0", 5);
-       write(fd, &bufdata, 4);
+       fwrite("HE3\r\0", 1, 5, out);
+       fwrite(&bufdata, 4, 1, out); /* XXX: Endian unsafe */
        ibuf = 256;
-       write(fd, &ibuf, 2);
+       fwrite(&ibuf, 2, 1, out);
        ibuf = 8;
        for(i = 0; i < 256; i++)
        {
-           write(fd, &i, 1);
-           write(fd, &ibuf, 1);
+           fwrite(&i, 1, 1, out);
+           fwrite(&ibuf, 1, 1, out);
        }
        for(i = 0; i < 256; i++)
-           write(fd, &i, 1);
+           fwrite(&i, 1, 1, out);
        for(buf2 = buf; bufdata > 0;)
        {
-           if((ret = write(fd, buf2, bufdata)) < 0)
+           if((ret = fwrite(buf2, 1, bufdata, out)) < 0)
            {
                flog(LOG_WARNING, "could not write file list: %s", strerror(errno));
                break;
@@ -3406,7 +3414,7 @@ static void updatehmlist(void)
            bufdata -= ret;
            buf2 += ret;
        }
-       close(fd);
+       fclose(out);
     }
     free(buf);
 }
@@ -3769,7 +3777,7 @@ static int run(void)
            quota--;
        }
        if(hub->queue.size < 1000)
-           hub->sk->ignread = 0;
+           hubread(hub->sk, fn);
        if(quota < 1)
            break;
     }
@@ -3788,7 +3796,7 @@ static int run(void)
            quota--;
        }
        if((peer->queue.size < 50) && (peer->inbufdata < 500000))
-           peer->sk->ignread = 0;
+           peerread(peer->sk, peer);
        if(quota < 1)
            break;
     }
@@ -3831,7 +3839,7 @@ static int updateudpport(struct configvar *var, void *uudata)
 static int updatetcpport(struct configvar *var, void *uudata)
 {
     struct sockaddr_in addr;
-    struct socket *newsock;
+    struct lport *newsock;
     
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
@@ -3839,7 +3847,7 @@ static int updatetcpport(struct configvar *var, void *uudata)
     if((newsock = 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");
     if(tcpsock != NULL)
-       putsock(tcpsock);
+       closelport(tcpsock);
     tcpsock = newsock;
     return(0);
 }
@@ -3854,7 +3862,7 @@ static int init(int hup)
        if(udpsock != NULL)
            putsock(udpsock);
        if(tcpsock != NULL)
-           putsock(tcpsock);
+           closelport(tcpsock);
        addr.sin_family = AF_INET;
        memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
        addr.sin_port = htons(confgetint("dc", "udpport"));