a15575d4bc3bdd33620d54f9826d60e9b627ce9c
[doldaconnect.git] / daemon / fnet-adc.c
1 /*
2  *  Dolda Connect - Modular multiuser Direct Connect-style client
3  *  Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
4  *  
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *  
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *  
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <wctype.h>
28 #include <iconv.h>
29 #include <errno.h>
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 #include "filenet.h"
35 #include "log.h"
36 #include "module.h"
37 #include "utils.h"
38 #include "client.h"
39 #include "transfer.h"
40 #include "sysevents.h"
41 #include "net.h"
42 #include <tiger.h>
43
44 /* Protocol states */
45 #define ADC_PROTOCOL 0
46 #define ADC_IDENTIFY 1
47 #define ADC_VERIFY 2
48 #define ADC_NORMAL 3
49 #define ADC_DATA 4
50
51 struct command {
52     wchar_t *name;
53     int minargs, needsid, needsender;
54     void (*func)(struct fnetnode *fn, wchar_t *command, wchar_t *sender, int argc, wchar_t **argv);
55 };
56
57 struct qcmd {
58     struct qcmd *next;
59     wchar_t **args;
60 };
61
62 struct qcmdqueue {
63     struct qcmd *f, *l;
64     int size;
65 };
66
67 struct adchub {
68     struct socket *sk;
69     char *inbuf;
70     size_t inbufdata, inbufsize;
71     wchar_t *sid;
72     wchar_t *cb;
73     size_t cbdata, cbsize;
74     wchar_t **sup;
75     iconv_t ich;
76     int state;
77     struct wcspair *hubinf;
78     struct qcmdqueue queue;
79 };
80
81 static wchar_t *eoc, *ns, *fmt;
82 /* I've never understood why both of these are necessary, but... */
83 static wchar_t *privid, *cid;
84 struct socket *udpsock, *tcpsock;
85
86 static wchar_t **parseadc(wchar_t *cmdline)
87 {
88     wchar_t **ret;
89     size_t retsize, retdata;
90     wchar_t *p, *p2, *ep;
91     wchar_t r;
92     ssize_t len;
93     
94     ret = NULL;
95     retsize = retdata = 0;
96     p = cmdline;
97     do {
98         if((p2 = wcschr(p, L' ')) != NULL)
99             *(p2++) = L'\0';
100         len = wcslen(p);
101         for(ep = p; len > 0; ep++, len--) {
102             if(*ep == L'\\') {
103                 if(ep[1] == L's') {
104                     r = L' ';
105                 } else if(ep[1] == L'n') {
106                     r = L'\n';
107                 } else if(ep[1] == L'\\') {
108                     r = L'\\';
109                 } else {
110                     memmove(ep, ep + 2, (len -= 2) * sizeof(*ep));
111                     ep--;
112                     continue;
113                 }
114                 memmove(ep, ep + 1, --len * sizeof(*ep));
115                 *ep = r;
116             }
117         }
118         *ep = L'\0';
119         addtobuf(ret, swcsdup(p));
120         p = p2;
121     } while(p2 != NULL);
122     addtobuf(ret, NULL);
123     return(ret);
124 }
125
126 static void sendeoc(struct socket *sk)
127 {
128     sockqueue(sk, "\n", 1);
129 }
130
131 static void sendadc1(struct socket *sk, int sep, wchar_t *arg)
132 {
133     char *mbsbuf;
134     wchar_t *buf;
135     size_t bufsize, bufdata;
136     
137     buf = NULL;
138     bufsize = bufdata = 0;
139     if(sep)
140         addtobuf(buf, L' ');
141     for(; *arg != L'\0'; arg++) {
142         if(*arg == L' ')
143             bufcat(buf, L"\\s", 2);
144         else if(*arg == L'\n')
145             bufcat(buf, L"\\n", 2);
146         else if(*arg == L'\\')
147             bufcat(buf, L"\\\\", 2);
148         else
149             addtobuf(buf, *arg);
150     }
151     addtobuf(buf, L'\0');
152     mbsbuf = icwcstombs(buf, "utf-8");
153     sockqueue(sk, mbsbuf, strlen(mbsbuf));
154     free(mbsbuf);
155 }
156
157 static void sendadc(struct socket *sk, int sep, ...)
158 {
159     int i;
160     va_list args;
161     wchar_t *arg;
162     wchar_t *type, *buf;
163     
164     va_start(args, sep);
165     for(i = 0; (arg = va_arg(args, wchar_t *)) != NULL; i++) {
166         if(arg == eoc) {
167             sendeoc(sk);
168         } else if(arg == ns) {
169             sep = 0;
170         } else if(arg == fmt) {
171             type = va_arg(args, wchar_t *);
172             if(!wcscmp(type, L"i")) {
173                 buf = swprintf2(L"%i", va_arg(args, int));
174             } else if(!wcscmp(type, L"mi")) {
175                 buf = swprintf2(L"%ji", va_arg(args, intmax_t));
176             }
177             sendadc1(sk, sep, buf);
178             free(buf);
179             sep = 1;
180         } else {
181             sendadc1(sk, sep, arg);
182             sep = 1;
183         }
184     }
185     va_end(args);
186 }
187
188 static wchar_t *findkv(wchar_t **argv, wchar_t *name)
189 {
190     while(*argv != NULL) {
191         if(!wcsncmp(*argv, name, 2))
192             return((*argv) + 2);
193     }
194     return(NULL);
195 }
196
197 static struct qcmd *newqcmd(struct qcmdqueue *queue, wchar_t **args)
198 {
199     struct qcmd *new;
200     
201     new = smalloc(sizeof(*new));
202     new->next = NULL;
203     new->args = args;
204     if(queue->l == NULL)
205         queue->f = new;
206     else
207         queue->l->next = new;
208     queue->l = new;
209     queue->size++;
210     return(new);
211 }
212
213 static struct qcmd *ulqcmd(struct qcmdqueue *queue)
214 {
215     struct qcmd *ret;
216     
217     if((ret = queue->f) == NULL)
218         return(NULL);
219     if((queue->f = ret->next) == NULL)
220         queue->l = NULL;
221     queue->size--;
222     return(ret);
223 }
224
225 static void freeqcmd(struct qcmd *qcmd)
226 {
227     freeparr(qcmd->args);
228     free(qcmd);
229 }
230
231 static void sendinf(struct fnetnode *fn)
232 {
233     struct adchub *hub = fn->data;
234     struct socket *sk = hub->sk;
235     struct sockaddr_in *a4;
236     socklen_t alen;
237     
238     sendadc(sk, 0, L"BINF", hub->sid, NULL);
239     sendadc(sk, 1, L"PD", ns, privid, L"ID", ns, cid, NULL);
240     sendadc(sk, 1, L"VEDolda ", ns, icsmbstowcs(VERSION, "us-ascii", NULL), NULL);
241     sendadc(sk, 1, L"NI", ns, fn->mynick, NULL);
242     sendadc(sk, 1, L"SS", ns, fmt, L"mi", (intmax_t)sharesize, L"SF", ns, fmt, L"i", sharedfiles, NULL);
243     if(sk->family == AF_INET)
244         sendadc(sk, 1, L"I40.0.0.0", NULL);
245     else if(sk->family == AF_INET6)
246         sendadc(sk, 1, L"I6::", NULL);
247     sendadc(sk, 1, L"SL", ns, fmt, L"i", confgetint("transfer", "slot"), NULL);
248     if(tcpsock != NULL) {
249         if((sk->family == AF_INET) && !sockgetremotename(udpsock, (struct sockaddr **)&a4, &alen)) {
250             sendadc(sk, 1, L"U4", ns, fmt, L"i", ntohs(a4->sin_port), NULL);
251             free(a4);
252         }
253     }
254     sendadc(sk, 1, eoc, NULL);
255 }
256
257 #define ADC_CMDFN(name) static void name(struct fnetnode *fn, wchar_t *command, wchar_t *sender, int argc, wchar_t **argv)
258 #ifdef __GNUC__
259 #define UNUSED __attribute__ ((unused))
260 #else
261 #define UNUSED
262 #endif
263 #define ADC_CMDCOM \
264         struct adchub *hub UNUSED = fn->data; \
265         struct socket *sk UNUSED = hub->sk;
266
267 ADC_CMDFN(cmd_sup)
268 {
269     ADC_CMDCOM;
270     int i, o, f;
271     
272     for(i = 1; i < argc; i++) {
273         if(wcslen(argv[i]) < 3)
274             continue;
275         for(o = 0, f = 0; hub->sup[o]; o++) {
276             if(!wcscmp(argv[i] + 2, hub->sup[o])) {
277                 f = 1;
278                 break;
279             }
280         }
281         if(!wcsncmp(argv[i], L"AD", 2)) {
282             if(f)
283                 continue;
284             hub->sup = srealloc(hub->sup, sizeof(*(hub->sup)) * (o + 1));
285             hub->sup[o] = swcsdup(argv[i] + 2);
286         } else if(!wcsncmp(argv[i], L"RM", 2)) {
287             if(!f)
288                 continue;
289             free(hub->sup[o]);
290             memmove(hub->sup[o], hub->sup[o + 1], parrlen(hub->sup) - o);
291         }
292     }
293 }
294
295 ADC_CMDFN(cmd_sid)
296 {
297     ADC_CMDCOM;
298     
299     if(hub->sid != NULL)
300         free(hub->sid);
301     hub->sid = swcsdup(argv[1]);
302     if(hub->state == ADC_PROTOCOL) {
303         hub->state = ADC_IDENTIFY;
304         sendinf(fn);
305     }
306 }
307
308 ADC_CMDFN(cmd_inf)
309 {
310     ADC_CMDCOM;
311     wchar_t *p;
312     
313     if(sender == NULL) {
314         if((p = findkv(argv, L"NI")) != NULL)
315             fnetsetname(fn, p);
316     }
317 }
318
319 static struct command hubcmds[] = {
320     {L"SUP", 1, 0, 0, cmd_sup},
321     {L"SID", 2, 0, 0, cmd_sid},
322     {L"INF", 1, 0, 0, cmd_inf},
323     {NULL, 0, 0, 0, NULL}
324 };
325
326 static void dispatch(struct qcmd *qcmd, struct fnetnode *fn)
327 {
328     struct command *cmd;
329     int argc;
330     wchar_t *cmdnm, *sender, **argv;
331     
332     if((argc = parrlen(argv = qcmd->args)) < 1)
333         return;
334     cmdnm = *(argv++);
335     argc--;
336     if(wcslen(cmdnm) < 2)
337         return;
338     sender = NULL;
339     if((*cmdnm == L'B') || (*cmdnm == L'F')) {
340         if(argc < 1)
341             return;
342         sender = *(argv++);
343         argc--;
344     } else if((*cmdnm == L'D') || (*cmdnm == L'E')) {
345         if(argc < 2)
346             return;
347         sender = *argv;
348         argv += 2;
349         argc -= 2;
350     }
351     for(cmd = hubcmds; cmd->func != NULL; cmd++) {
352         if(!wcscmp(cmd->name, qcmd->args[0] + 1)) {
353             if(argc < cmd->minargs)
354                 return;
355             cmd->func(fn, cmdnm, sender, argc, argv);
356             return;
357         }
358     }
359     flog(LOG_DEBUG, "unknown adc command: %ls", qcmd->args[0]);
360 }
361
362 static void peeraccept(struct socket *sk, struct socket *newsk, void *uudata)
363 {
364 }
365
366 static void udpread(struct socket *sk, void *uudata)
367 {
368 }
369
370 static void hubread(struct socket *sk, struct fnetnode *fn)
371 {
372     int ret;
373     struct adchub *hub;
374     char *newbuf, *p1, *p2;
375     wchar_t *p;
376     size_t datalen, cblen;
377     
378     hub = fn->data;
379     if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
380         return;
381     if(hub->inbufdata > 1024)
382         hub->inbufdata = 0;
383     bufcat(hub->inbuf, newbuf, datalen);
384     free(newbuf);
385     /* Memory eating protection */
386     if(hub->cbdata > 65536)
387         hub->cbdata = 0;
388     while(hub->inbufdata > 0) {
389         if(hub->cbdata == hub->cbsize)
390             sizebuf2(hub->cb, hub->cbdata + datalen, 1);
391         p1 = hub->inbuf;
392         p2 = (char *)(hub->cb + hub->cbdata);
393         cblen = sizeof(*(hub->cb)) * (hub->cbsize - hub->cbdata);
394         ret = iconv(hub->ich, &p1, &hub->inbufdata, &p2, &cblen);
395         memmove(hub->inbuf, p1, hub->inbufdata);
396         if(((p2 - ((char *)hub->cb)) % sizeof(*hub->cb)) != 0) {
397             flog(LOG_CRIT, "Spotted a dismembered wchar_t!");
398             abort();
399         }
400         hub->cbdata = hub->cbsize - (cblen / sizeof(*(hub->cb)));
401         if(ret < 0) {
402             if(errno == EILSEQ) {
403                 flog(LOG_DEBUG, "adc fnetnode %i sent illegal utf-8 sequence", fn->id);
404                 killfnetnode(fn);
405                 return;
406             } else if(errno == EINVAL) {
407                 break;
408             } else if(errno == E2BIG) {
409                 /* continue; */
410             } else {
411                 flog(LOG_WARNING, "bug? iconv returned unexpected error: %s", strerror(errno));
412                 return;
413             }
414         }
415     }
416     while((p = wmemchr(hub->cb, L'\n', hub->cbdata)) != NULL) {
417         *(p++) = L'\0';
418         newqcmd(&hub->queue, parseadc(hub->cb));
419         memmove(hub->cb, p, (hub->cbdata -= (p - hub->cb)) * sizeof(*(hub->cb)));
420     }
421 }
422
423 static void huberr(struct socket *sk, int err, struct fnetnode *fn)
424 {
425     killfnetnode(fn);
426 }
427
428 static void hubconnect(struct fnetnode *fn, struct socket *sk)
429 {
430     struct adchub *hub;
431     
432     sk->readcb = (void (*)(struct socket *, void *))hubread;
433     sk->errcb = (void (*)(struct socket *, int, void *))huberr;
434     sk->data = fn;
435     
436     hub = smalloc(sizeof(*hub));
437     memset(hub, 0, sizeof(*hub));
438     getsock(hub->sk = sk);
439     if((hub->ich = iconv_open("wchar_t", "utf-8")) == (iconv_t)-1) {
440         flog(LOG_CRIT, "iconv cannot handle UTF-8: %s", strerror(errno));
441         killfnetnode(fn);
442         return;
443     }
444     fn->data = hub;
445     sendadc(sk, 0, L"HSUP", L"ADBASE", L"ADTIGR", eoc, NULL);
446 }
447
448 static void hubdestroy(struct fnetnode *fn)
449 {
450     struct adchub *hub;
451     
452     hub = fn->data;
453     iconv_close(hub->ich);
454     if(hub->inbuf != NULL)
455         free(hub->inbuf);
456     if(hub->sup != NULL)
457         freeparr(hub->sup);
458     free(hub);
459 }
460
461 static void hubkill(struct fnetnode *fn)
462 {
463     struct adchub *hub;
464     
465     hub = fn->data;
466     hub->sk->close = 1;
467 }
468
469 static int hubsetnick(struct fnetnode *fn, wchar_t *newnick)
470 {
471     return(0);
472 }
473
474 static int hubreqconn(struct fnetpeer *peer)
475 {
476     return(0);
477 }
478
479 static struct fnet adcnet_store = {
480     .connect = hubconnect,
481     .destroy = hubdestroy,
482     .kill = hubkill,
483     .setnick = hubsetnick,
484     .reqconn = hubreqconn,
485     .name = L"adc"
486 };
487
488 static struct fnet *adcnet = &adcnet_store;
489
490 static int run(void)
491 {
492     int ret;
493     struct fnetnode *fn, *nextfn;
494     struct adchub *hub;
495     struct qcmd *qcmd;
496     
497     ret = 0;
498     for(fn = fnetnodes; fn != NULL; fn = nextfn) {
499         nextfn = fn->next;
500         if(fn->fnet != adcnet)
501             continue;
502         if((hub = fn->data) == NULL)
503             continue;
504         if((qcmd = ulqcmd(&hub->queue)) != NULL) {
505             if((hub->sk != NULL) && (hub->sk->state == SOCK_EST))
506                 dispatch(qcmd, fn);
507             freeqcmd(qcmd);
508             ret = 1;
509             break;
510         }
511     }
512     return(ret);
513 }
514
515 static void preinit(int hup)
516 {
517     if(hup)
518         return;
519     regfnet(adcnet);
520 }
521
522 static void makepid(char *idbuf)
523 {
524     int i;
525     int fd, ret;
526     
527     i = 0;
528     if((fd = open("/dev/urandom", O_RDONLY)) >= 0) {
529         for(i = 0; i < 24; i += ret) {
530             if((ret = read(fd, idbuf + i, 24 - i)) <= 0) {
531                 flog(LOG_WARNING, "could not read random data from /dev/urandom for ADC PID: %s", (errno == 0)?"EOF":strerror(errno));
532                 break;
533             }
534         }
535         close(fd);
536     } else {
537         flog(LOG_WARNING, "could not open /dev/urandom: %s", strerror(errno));
538     }
539     if(i != 24) {
540         for(i = 0; i < sizeof(idbuf); i++)
541             idbuf[i] = rand() % 256;
542     }
543 }
544
545 static int updateudpport(struct configvar *var, void *uudata)
546 {
547     struct sockaddr_in addr;
548     struct socket *newsock;
549     
550     memset(&addr, 0, sizeof(addr));
551     addr.sin_family = AF_INET;
552     addr.sin_port = htons(var->val.num);
553     if((newsock = netcsdgram((struct sockaddr *)&addr, sizeof(addr))) == NULL)
554     {
555         flog(LOG_WARNING, "could not create new DC UDP socket, reverting to old: %s", strerror(errno));
556         return(0);
557     }
558     newsock->readcb = udpread;
559     if(udpsock != NULL)
560         putsock(udpsock);
561     udpsock = newsock;
562     return(0);
563 }
564
565 static int updatetcpport(struct configvar *var, void *uudata)
566 {
567     struct sockaddr_in addr;
568     struct socket *newsock;
569     
570     memset(&addr, 0, sizeof(addr));
571     addr.sin_family = AF_INET;
572     addr.sin_port = htons(var->val.num);
573     if((newsock = netcslisten(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), peeraccept, NULL)) == NULL)
574         flog(LOG_INFO, "could not listen to a remote address, going into passive mode");
575     if(tcpsock != NULL)
576         putsock(tcpsock);
577     tcpsock = newsock;
578     return(0);
579 }
580
581 static int init(int hup)
582 {
583     char idbuf[24], *id32;
584     struct tigerhash th;
585     struct sockaddr_in addr;
586     
587     if(!hup) {
588         eoc = swcsdup(L"");
589         ns = swcsdup(L"");
590         fmt = swcsdup(L"");
591         
592         if((privid = fetchvar("adc.pid", NULL)) == NULL) {
593             makepid(idbuf);
594             id32 = base32encode(idbuf, sizeof(idbuf));
595             id32[39] = 0;
596             privid = icmbstowcs(id32, "us-ascii");
597             free(id32);
598             storevar("adc.pid", privid, sizeof(*privid) * (wcslen(privid) + 1));
599         }
600         
601         id32 = base32decode(icswcstombs(privid, "us-ascii", NULL), NULL);
602         inittiger(&th);
603         dotiger(&th, id32, 24);
604         synctiger(&th);
605         free(id32);
606         restiger(&th, idbuf);
607         id32 = base32encode(idbuf, sizeof(idbuf));
608         id32[39] = 0;
609         cid = icmbstowcs(id32, "us-ascii");
610         free(id32);
611         
612         memset(&addr, 0, sizeof(addr));
613         addr.sin_family = AF_INET;
614         addr.sin_port = htons(confgetint("adc", "udpport"));
615         if((udpsock = netcsdgram((struct sockaddr *)&addr, sizeof(addr))) == NULL) {
616             flog(LOG_CRIT, "could not create ADC UDP socket: %s", strerror(errno));
617             return(1);
618         }
619         udpsock->readcb = udpread;
620         addr.sin_port = htons(confgetint("adc", "tcpport"));
621         if((tcpsock = netcslisten(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), peeraccept, NULL)) == NULL) {
622             flog(LOG_CRIT, "could not create ADC TCP socket: %s", strerror(errno));
623             return(1);
624         }
625         CBREG(confgetvar("adc", "udpport"), conf_update, updateudpport, NULL, NULL);
626         CBREG(confgetvar("adc", "tcpport"), conf_update, updatetcpport, NULL, NULL);
627         CBREG(confgetvar("net", "mode"), conf_update, updatetcpport, NULL, NULL);
628     }
629     return(0);
630 }
631
632 static void terminate(void)
633 {
634     
635 }
636
637 static struct configvar myvars[] = {
638     /** Specifies a specific UDP port to use for ADC search
639      * results. If left unspecified, a port is allocated
640      * dynamically. Useful for NAT routers (see also the
641      * net.visibleipv4 address for those cases). */
642     {CONF_VAR_INT, "udpport", {.num = 0}},
643     /** Specifies a specific TCP port to use for ADC peer
644      * connections. If left unspecified, a port is allocated
645      * dynamically. Useful for NAT routers (see also the
646      * net.visibleipv4 address for those cases). */
647     {CONF_VAR_INT, "tcpport", {.num = 0}},
648     {CONF_VAR_END}
649 };
650
651 static struct module me = {
652     .conf = {
653         .vars = myvars
654     },
655     .preinit = preinit,
656     .init = init,
657     .run = run,
658     .terminate = terminate,
659     .name = "adc"
660 };
661
662 MODULE(me)