19141a21df5374cb0713193a8116c471eeccb7aa
[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 <stdarg.h>
23 #include <string.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <wctype.h>
27 #include <iconv.h>
28 #include <errno.h>
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 #include "filenet.h"
34 #include "log.h"
35 #include "module.h"
36 #include "utils.h"
37 #include "client.h"
38 #include "transfer.h"
39 #include "sysevents.h"
40 #include "net.h"
41 #include <tiger.h>
42
43 /* Protocol states */
44 #define ADC_PROTOCOL 0
45 #define ADC_IDENTIFY 1
46 #define ADC_VERIFY 2
47 #define ADC_NORMAL 3
48 #define ADC_DATA 4
49
50 struct command {
51     wchar_t *name;
52     int minargs, needsender;
53     void (*func)(struct fnetnode *fn, wchar_t *command, wchar_t *sender, int argc, wchar_t **argv);
54 };
55
56 struct qcmd {
57     struct qcmd *next;
58     wchar_t **args;
59 };
60
61 struct qcmdqueue {
62     struct qcmd *f, *l;
63     int size;
64 };
65
66 struct adchub {
67     struct socket *sk;
68     char *inbuf;
69     size_t inbufdata, inbufsize;
70     wchar_t *sid;
71     wchar_t *cb;
72     size_t cbdata, cbsize;
73     wchar_t **sup;
74     iconv_t ich;
75     int state;
76     struct wcspair *hubinf;
77     struct qcmdqueue queue;
78 };
79
80 static wchar_t *eoc;
81 /* I've never understood why both of these are necessary, but... */
82 static wchar_t *privid, *cid;
83
84 static wchar_t **parseadc(wchar_t *cmdline)
85 {
86     wchar_t **ret;
87     size_t retsize, retdata;
88     wchar_t *p, *p2, *ep;
89     wchar_t r;
90     ssize_t len;
91     
92     ret = NULL;
93     retsize = retdata = 0;
94     p = cmdline;
95     do {
96         if((p2 = wcschr(p, L' ')) != NULL)
97             *(p2++) = L'\0';
98         len = wcslen(p);
99         for(ep = p; len > 0; ep++, len--) {
100             if(*ep == L'\\') {
101                 if(ep[1] == L's') {
102                     r = L' ';
103                 } else if(ep[1] == L'n') {
104                     r = L'\n';
105                 } else if(ep[1] == L'\\') {
106                     r = L'\\';
107                 } else {
108                     memmove(ep, ep + 2, (len -= 2) * sizeof(*ep));
109                     ep--;
110                     continue;
111                 }
112                 memmove(ep, ep + 1, --len * sizeof(*ep));
113                 *ep = r;
114             }
115         }
116         *ep = L'\0';
117         addtobuf(ret, swcsdup(p));
118         p = p2;
119     } while(p2 != NULL);
120     addtobuf(ret, NULL);
121     return(ret);
122 }
123
124 static void sendeoc(struct socket *sk)
125 {
126     sockqueue(sk, "\n", 1);
127 }
128
129 static void sendadc1(struct socket *sk, int sep, wchar_t *arg)
130 {
131     char *mbsbuf;
132     wchar_t *buf;
133     size_t bufsize, bufdata;
134     
135     buf = NULL;
136     bufsize = bufdata = 0;
137     if(sep)
138         addtobuf(buf, L' ');
139     for(; *arg != L'\0'; arg++) {
140         if(*arg == L' ')
141             bufcat(buf, L"\\s", 2);
142         else if(*arg == L'\n')
143             bufcat(buf, L"\\n", 2);
144         else if(*arg == L'\\')
145             bufcat(buf, L"\\\\", 2);
146         else
147             addtobuf(buf, *arg);
148     }
149     addtobuf(buf, L'\0');
150     mbsbuf = icwcstombs(buf, "utf-8");
151     sockqueue(sk, mbsbuf, strlen(mbsbuf));
152     free(mbsbuf);
153 }
154
155 static void sendadc(struct socket *sk, int sep, ...)
156 {
157     va_list args;
158     wchar_t *arg;
159     int i;
160     
161     va_start(args, sep);
162     for(i = 0; (arg = va_arg(args, wchar_t *)) != NULL; i++) {
163         if(arg == eoc)
164             sendeoc(sk);
165         else
166             sendadc1(sk, (i == 0)?sep:1, arg);
167     }
168     va_end(args);
169 }
170
171 static struct qcmd *newqcmd(struct qcmdqueue *queue, wchar_t **args)
172 {
173     struct qcmd *new;
174     
175     new = smalloc(sizeof(*new));
176     new->next = NULL;
177     new->args = args;
178     if(queue->l == NULL)
179         queue->f = new;
180     else
181         queue->l->next = new;
182     queue->l = new;
183     queue->size++;
184     return(new);
185 }
186
187 static struct qcmd *ulqcmd(struct qcmdqueue *queue)
188 {
189     struct qcmd *ret;
190     
191     if((ret = queue->f) == NULL)
192         return(NULL);
193     if((queue->f = ret->next) == NULL)
194         queue->l = NULL;
195     queue->size--;
196     return(ret);
197 }
198
199 static void freeqcmd(struct qcmd *qcmd)
200 {
201     freeparr(qcmd->args);
202     free(qcmd);
203 }
204
205 #define ADC_CMDFN(name) static void name(struct fnetnode *fn, wchar_t *command, wchar_t *sender, int argc, wchar_t **argv)
206 #ifdef __GNUC__
207 #define UNUSED __attribute__ ((unused))
208 #else
209 #define UNUSED
210 #endif
211 #define ADC_CMDCOM \
212         struct adchub *hub UNUSED = fn->data; \
213         struct socket *sk UNUSED = hub->sk;
214
215 ADC_CMDFN(cmd_sup)
216 {
217     ADC_CMDCOM;
218     int i, o, f;
219     
220     for(i = 1; i < argc; i++) {
221         if(wcslen(argv[i]) < 3)
222             continue;
223         for(o = 0, f = 0; hub->sup[o]; o++) {
224             if(!wcscmp(argv[i] + 2, hub->sup[o])) {
225                 f = 1;
226                 break;
227             }
228         }
229         if(!wcsncmp(argv[i], L"AD", 2)) {
230             if(f)
231                 continue;
232             hub->sup = srealloc(hub->sup, sizeof(*(hub->sup)) * (o + 1));
233             hub->sup[o] = swcsdup(argv[i] + 2);
234         } else if(!wcsncmp(argv[i], L"RM", 2)) {
235             if(!f)
236                 continue;
237             free(hub->sup[o]);
238             memmove(hub->sup[o], hub->sup[o + 1], parrlen(hub->sup) - o);
239         }
240     }
241 }
242
243 ADC_CMDFN(cmd_sid)
244 {
245     ADC_CMDCOM;
246     
247     if(hub->sid != NULL)
248         free(hub->sid);
249     hub->sid = swcsdup(argv[1]);
250     if(hub->state == ADC_PROTOCOL) {
251         hub->state = ADC_IDENTIFY;
252     }
253 }
254
255 ADC_CMDFN(cmd_inf)
256 {
257     ADC_CMDCOM;
258     
259     if(sender == NULL) {
260         
261     }
262 }
263
264 static struct command hubcmds[] = {
265     {L"SUP", 1, 0, cmd_sup},
266     {L"SID", 2, 0, cmd_sid},
267     {L"INF", 0, 0, cmd_inf},
268     {NULL, 0, 0, NULL}
269 };
270
271 static void dispatch(struct qcmd *qcmd, struct fnetnode *fn)
272 {
273     struct command *cmd;
274     int argc;
275     wchar_t *cmdnm, *sender, **argv;
276     
277     if((argc = parrlen(argv = qcmd->args)) < 1)
278         return;
279     cmdnm = *(argv++);
280     argc--;
281     if(wcslen(cmdnm) < 2)
282         return;
283     sender = NULL;
284     if((*cmdnm == L'B') || (*cmdnm == L'F')) {
285         if(argc < 1)
286             return;
287         sender = *(argv++);
288         argc--;
289     } else if((*cmdnm == L'D') || (*cmdnm == L'E')) {
290         if(argc < 2)
291             return;
292         sender = *argv;
293         argv += 2;
294         argc -= 2;
295     }
296     for(cmd = hubcmds; cmd->func != NULL; cmd++) {
297         if(!wcscmp(cmd->name, qcmd->args[0] + 1)) {
298             if(argc < cmd->minargs)
299                 return;
300             cmd->func(fn, cmdnm, sender, argc, qcmd->args);
301             return;
302         }
303     }
304     flog(LOG_DEBUG, "unknown adc command: %ls", qcmd->args[0]);
305 }
306
307 static void hubread(struct socket *sk, struct fnetnode *fn)
308 {
309     int ret;
310     struct adchub *hub;
311     char *newbuf, *p1, *p2;
312     wchar_t *p;
313     size_t datalen, cblen;
314     
315     hub = fn->data;
316     if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
317         return;
318     if(hub->inbufdata > 1024)
319         hub->inbufdata = 0;
320     bufcat(hub->inbuf, newbuf, datalen);
321     free(newbuf);
322     /* Memory eating protection */
323     if(hub->cbdata > 65536)
324         hub->cbdata = 0;
325     while(hub->inbufdata > 0) {
326         if(hub->cbdata == hub->cbsize)
327             sizebuf2(hub->cb, hub->cbdata + datalen, 1);
328         p1 = hub->inbuf;
329         p2 = (char *)(hub->cb + hub->cbdata);
330         cblen = sizeof(*(hub->cb)) * (hub->cbsize - hub->cbdata);
331         ret = iconv(hub->ich, &p1, &hub->inbufdata, &p2, &cblen);
332         memmove(hub->inbuf, p1, hub->inbufdata);
333         if(((p2 - ((char *)hub->cb)) % sizeof(*hub->cb)) != 0) {
334             flog(LOG_CRIT, "Spotted a dismembered wchar_t!");
335             abort();
336         }
337         hub->cbdata = hub->cbsize - (cblen / sizeof(*(hub->cb)));
338         if(ret < 0) {
339             if(errno == EILSEQ) {
340                 flog(LOG_DEBUG, "adc fnetnode %i sent illegal utf-8 sequence", fn->id);
341                 killfnetnode(fn);
342                 return;
343             } else if(errno == EINVAL) {
344                 break;
345             } else if(errno == E2BIG) {
346                 /* continue; */
347             } else {
348                 flog(LOG_WARNING, "bug? iconv returned unexpected error: %s", strerror(errno));
349                 return;
350             }
351         }
352     }
353     while((p = wmemchr(hub->cb, L'\n', hub->cbdata)) != NULL) {
354         *(p++) = L'\0';
355         newqcmd(&hub->queue, parseadc(hub->cb));
356         memmove(hub->cb, p, (hub->cbdata -= (p - hub->cb)) * sizeof(*(hub->cb)));
357     }
358 }
359
360 static void huberr(struct socket *sk, int err, struct fnetnode *fn)
361 {
362     killfnetnode(fn);
363 }
364
365 static void hubconnect(struct fnetnode *fn, struct socket *sk)
366 {
367     struct adchub *hub;
368     
369     sk->readcb = (void (*)(struct socket *, void *))hubread;
370     sk->errcb = (void (*)(struct socket *, int, void *))huberr;
371     sk->data = fn;
372     
373     hub = smalloc(sizeof(*hub));
374     memset(hub, 0, sizeof(*hub));
375     getsock(hub->sk = sk);
376     if((hub->ich = iconv_open("wchar_t", "utf-8")) == (iconv_t)-1) {
377         flog(LOG_CRIT, "iconv cannot handle UTF-8: %s", strerror(errno));
378         killfnetnode(fn);
379         return;
380     }
381     fn->data = hub;
382     sendadc(sk, 0, L"HSUP", L"ADBASE", eoc, NULL);
383 }
384
385 static void hubdestroy(struct fnetnode *fn)
386 {
387     struct adchub *hub;
388     
389     hub = fn->data;
390     iconv_close(hub->ich);
391     if(hub->inbuf != NULL)
392         free(hub->inbuf);
393     if(hub->sup != NULL)
394         freeparr(hub->sup);
395     free(hub);
396 }
397
398 static void hubkill(struct fnetnode *fn)
399 {
400     struct adchub *hub;
401     
402     hub = fn->data;
403     hub->sk->close = 1;
404 }
405
406 static int hubsetnick(struct fnetnode *fn, wchar_t *newnick)
407 {
408     return(0);
409 }
410
411 static int hubreqconn(struct fnetpeer *peer)
412 {
413     return(0);
414 }
415
416 static struct fnet adcnet_store = {
417     .connect = hubconnect,
418     .destroy = hubdestroy,
419     .kill = hubkill,
420     .setnick = hubsetnick,
421     .reqconn = hubreqconn,
422     .name = L"adc"
423 };
424
425 static struct fnet *adcnet = &adcnet_store;
426
427 static int run(void)
428 {
429     int ret;
430     struct fnetnode *fn, *nextfn;
431     struct adchub *hub;
432     struct qcmd *qcmd;
433     
434     ret = 0;
435     for(fn = fnetnodes; fn != NULL; fn = nextfn) {
436         nextfn = fn->next;
437         if(fn->fnet != adcnet)
438             continue;
439         if((hub = fn->data) == NULL)
440             continue;
441         if((qcmd = ulqcmd(&hub->queue)) != NULL) {
442             if((hub->sk != NULL) && (hub->sk->state == SOCK_EST))
443                 dispatch(qcmd, fn);
444             freeqcmd(qcmd);
445             ret = 1;
446             break;
447         }
448     }
449     return(ret);
450 }
451
452 static void preinit(int hup)
453 {
454     if(hup)
455         return;
456     regfnet(adcnet);
457 }
458
459 static int init(int hup)
460 {
461     int i;
462     char idbuf[24], *id32;
463     struct tigerhash th;
464     
465     if(!hup) {
466         eoc = swcsdup(L"");
467         
468         if((privid = fetchvar("adc.pid", NULL)) == NULL) {
469             for(i = 0; i < sizeof(idbuf); i++)
470                 idbuf[i] = rand() % 256;
471             id32 = base32encode(idbuf, sizeof(idbuf));
472             id32[39] = 0;
473             privid = icmbstowcs(id32, "us-ascii");
474             free(id32);
475             storevar("adc.pid", privid, sizeof(*privid) * (wcslen(privid) + 1));
476         }
477         
478         id32 = base32decode(icswcstombs(privid, "us-ascii", NULL), NULL);
479         inittiger(&th);
480         dotiger(&th, id32, 24);
481         synctiger(&th);
482         free(id32);
483         restiger(&th, idbuf);
484         id32 = base32encode(idbuf, sizeof(idbuf));
485         id32[39] = 0;
486         cid = icmbstowcs(id32, "us-ascii");
487         free(id32);
488     }
489     return(0);
490 }
491
492 static void terminate(void)
493 {
494     
495 }
496
497 static struct configvar myvars[] = {
498     /** Specifies a specific UDP port to use for ADC search
499      * results. If left unspecified, a port is allocated
500      * dynamically. Useful for NAT routers (see also the
501      * net.visibleipv4 address for those cases). */
502     {CONF_VAR_INT, "udpport", {.num = 0}},
503     /** Specifies a specific TCP port to use for ADC peer
504      * connections. If left unspecified, a port is allocated
505      * dynamically. Useful for NAT routers (see also the
506      * net.visibleipv4 address for those cases). */
507     {CONF_VAR_INT, "tcpport", {.num = 0}},
508     {CONF_VAR_END}
509 };
510
511 static struct module me = {
512     .conf = {
513         .vars = myvars
514     },
515     .preinit = preinit,
516     .init = init,
517     .run = run,
518     .terminate = terminate,
519     .name = "adc"
520 };
521
522 MODULE(me)