Incremental work on ADC.
authorFredrik Tolf <fredrik@dolda2000.com>
Thu, 6 Mar 2008 23:59:02 +0000 (00:59 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Thu, 6 Mar 2008 23:59:02 +0000 (00:59 +0100)
daemon/fnet-adc.c

index c874b6e..a15575d 100644 (file)
@@ -50,7 +50,7 @@
 
 struct command {
     wchar_t *name;
-    int minargs, needsender;
+    int minargs, needsid, needsender;
     void (*func)(struct fnetnode *fn, wchar_t *command, wchar_t *sender, int argc, wchar_t **argv);
 };
 
@@ -78,9 +78,10 @@ struct adchub {
     struct qcmdqueue queue;
 };
 
-static wchar_t *eoc;
+static wchar_t *eoc, *ns, *fmt;
 /* I've never understood why both of these are necessary, but... */
 static wchar_t *privid, *cid;
+struct socket *udpsock, *tcpsock;
 
 static wchar_t **parseadc(wchar_t *cmdline)
 {
@@ -155,20 +156,44 @@ static void sendadc1(struct socket *sk, int sep, wchar_t *arg)
 
 static void sendadc(struct socket *sk, int sep, ...)
 {
+    int i;
     va_list args;
     wchar_t *arg;
-    int i;
+    wchar_t *type, *buf;
     
     va_start(args, sep);
     for(i = 0; (arg = va_arg(args, wchar_t *)) != NULL; i++) {
-       if(arg == eoc)
+       if(arg == eoc) {
            sendeoc(sk);
-       else
-           sendadc1(sk, (i == 0)?sep:1, arg);
+       } else if(arg == ns) {
+           sep = 0;
+       } else if(arg == fmt) {
+           type = va_arg(args, wchar_t *);
+           if(!wcscmp(type, L"i")) {
+               buf = swprintf2(L"%i", va_arg(args, int));
+           } else if(!wcscmp(type, L"mi")) {
+               buf = swprintf2(L"%ji", va_arg(args, intmax_t));
+           }
+           sendadc1(sk, sep, buf);
+           free(buf);
+           sep = 1;
+       } else {
+           sendadc1(sk, sep, arg);
+           sep = 1;
+       }
     }
     va_end(args);
 }
 
+static wchar_t *findkv(wchar_t **argv, wchar_t *name)
+{
+    while(*argv != NULL) {
+       if(!wcsncmp(*argv, name, 2))
+           return((*argv) + 2);
+    }
+    return(NULL);
+}
+
 static struct qcmd *newqcmd(struct qcmdqueue *queue, wchar_t **args)
 {
     struct qcmd *new;
@@ -203,6 +228,32 @@ static void freeqcmd(struct qcmd *qcmd)
     free(qcmd);
 }
 
+static void sendinf(struct fnetnode *fn)
+{
+    struct adchub *hub = fn->data;
+    struct socket *sk = hub->sk;
+    struct sockaddr_in *a4;
+    socklen_t alen;
+    
+    sendadc(sk, 0, L"BINF", hub->sid, NULL);
+    sendadc(sk, 1, L"PD", ns, privid, L"ID", ns, cid, NULL);
+    sendadc(sk, 1, L"VEDolda ", ns, icsmbstowcs(VERSION, "us-ascii", NULL), NULL);
+    sendadc(sk, 1, L"NI", ns, fn->mynick, NULL);
+    sendadc(sk, 1, L"SS", ns, fmt, L"mi", (intmax_t)sharesize, L"SF", ns, fmt, L"i", sharedfiles, NULL);
+    if(sk->family == AF_INET)
+       sendadc(sk, 1, L"I40.0.0.0", NULL);
+    else if(sk->family == AF_INET6)
+       sendadc(sk, 1, L"I6::", NULL);
+    sendadc(sk, 1, L"SL", ns, fmt, L"i", confgetint("transfer", "slot"), NULL);
+    if(tcpsock != NULL) {
+       if((sk->family == AF_INET) && !sockgetremotename(udpsock, (struct sockaddr **)&a4, &alen)) {
+           sendadc(sk, 1, L"U4", ns, fmt, L"i", ntohs(a4->sin_port), NULL);
+           free(a4);
+       }
+    }
+    sendadc(sk, 1, eoc, NULL);
+}
+
 #define ADC_CMDFN(name) static void name(struct fnetnode *fn, wchar_t *command, wchar_t *sender, int argc, wchar_t **argv)
 #ifdef __GNUC__
 #define UNUSED __attribute__ ((unused))
@@ -250,23 +301,26 @@ ADC_CMDFN(cmd_sid)
     hub->sid = swcsdup(argv[1]);
     if(hub->state == ADC_PROTOCOL) {
        hub->state = ADC_IDENTIFY;
+       sendinf(fn);
     }
 }
 
 ADC_CMDFN(cmd_inf)
 {
     ADC_CMDCOM;
+    wchar_t *p;
     
     if(sender == NULL) {
-       
+       if((p = findkv(argv, L"NI")) != NULL)
+           fnetsetname(fn, p);
     }
 }
 
 static struct command hubcmds[] = {
-    {L"SUP", 1, 0, cmd_sup},
-    {L"SID", 2, 0, cmd_sid},
-    {L"INF", 0, 0, cmd_inf},
-    {NULL, 0, 0, NULL}
+    {L"SUP", 1, 0, 0, cmd_sup},
+    {L"SID", 2, 0, 0, cmd_sid},
+    {L"INF", 1, 0, 0, cmd_inf},
+    {NULL, 0, 0, 0, NULL}
 };
 
 static void dispatch(struct qcmd *qcmd, struct fnetnode *fn)
@@ -305,6 +359,14 @@ static void dispatch(struct qcmd *qcmd, struct fnetnode *fn)
     flog(LOG_DEBUG, "unknown adc command: %ls", qcmd->args[0]);
 }
 
+static void peeraccept(struct socket *sk, struct socket *newsk, void *uudata)
+{
+}
+
+static void udpread(struct socket *sk, void *uudata)
+{
+}
+
 static void hubread(struct socket *sk, struct fnetnode *fn)
 {
     int ret;
@@ -480,13 +542,52 @@ static void makepid(char *idbuf)
     }
 }
 
+static int updateudpport(struct configvar *var, void *uudata)
+{
+    struct sockaddr_in addr;
+    struct socket *newsock;
+    
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(var->val.num);
+    if((newsock = netcsdgram((struct sockaddr *)&addr, sizeof(addr))) == NULL)
+    {
+       flog(LOG_WARNING, "could not create new DC UDP socket, reverting to old: %s", strerror(errno));
+       return(0);
+    }
+    newsock->readcb = udpread;
+    if(udpsock != NULL)
+       putsock(udpsock);
+    udpsock = newsock;
+    return(0);
+}
+
+static int updatetcpport(struct configvar *var, void *uudata)
+{
+    struct sockaddr_in addr;
+    struct socket *newsock;
+    
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(var->val.num);
+    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);
+    tcpsock = newsock;
+    return(0);
+}
+
 static int init(int hup)
 {
     char idbuf[24], *id32;
     struct tigerhash th;
+    struct sockaddr_in addr;
     
     if(!hup) {
        eoc = swcsdup(L"");
+       ns = swcsdup(L"");
+       fmt = swcsdup(L"");
        
        if((privid = fetchvar("adc.pid", NULL)) == NULL) {
            makepid(idbuf);
@@ -507,6 +608,23 @@ static int init(int hup)
        id32[39] = 0;
        cid = icmbstowcs(id32, "us-ascii");
        free(id32);
+       
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(confgetint("adc", "udpport"));
+       if((udpsock = netcsdgram((struct sockaddr *)&addr, sizeof(addr))) == NULL) {
+           flog(LOG_CRIT, "could not create ADC UDP socket: %s", strerror(errno));
+           return(1);
+       }
+       udpsock->readcb = udpread;
+       addr.sin_port = htons(confgetint("adc", "tcpport"));
+       if((tcpsock = netcslisten(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), peeraccept, NULL)) == NULL) {
+           flog(LOG_CRIT, "could not create ADC TCP socket: %s", strerror(errno));
+           return(1);
+       }
+       CBREG(confgetvar("adc", "udpport"), conf_update, updateudpport, NULL, NULL);
+       CBREG(confgetvar("adc", "tcpport"), conf_update, updatetcpport, NULL, NULL);
+       CBREG(confgetvar("net", "mode"), conf_update, updatetcpport, NULL, NULL);
     }
     return(0);
 }