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