Clarified the dscp-tos documentation a bit.
[doldaconnect.git] / daemon / fnet-adc.c
... / ...
CommitLineData
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
51struct 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
57struct qcmd {
58 struct qcmd *next;
59 wchar_t **args;
60};
61
62struct qcmdqueue {
63 struct qcmd *f, *l;
64 int size;
65};
66
67struct 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
81static wchar_t *eoc, *ns, *fmt;
82/* I've never understood why both of these are necessary, but... */
83static wchar_t *privid, *cid;
84struct socket *udpsock, *tcpsock;
85
86static 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
126static void sendeoc(struct socket *sk)
127{
128 sockqueue(sk, "\n", 1);
129}
130
131static 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
157static 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
188static 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
197static 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
213static 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
225static void freeqcmd(struct qcmd *qcmd)
226{
227 freeparr(qcmd->args);
228 free(qcmd);
229}
230
231static 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
267ADC_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
295ADC_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
308ADC_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
319static 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
326static 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
362static void peeraccept(struct socket *sk, struct socket *newsk, void *uudata)
363{
364}
365
366static void udpread(struct socket *sk, void *uudata)
367{
368}
369
370static 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
423static void huberr(struct socket *sk, int err, struct fnetnode *fn)
424{
425 killfnetnode(fn);
426}
427
428static 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
448static 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
461static void hubkill(struct fnetnode *fn)
462{
463 struct adchub *hub;
464
465 hub = fn->data;
466 hub->sk->close = 1;
467}
468
469static int hubsetnick(struct fnetnode *fn, wchar_t *newnick)
470{
471 return(0);
472}
473
474static int hubreqconn(struct fnetpeer *peer)
475{
476 return(0);
477}
478
479static 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
488static struct fnet *adcnet = &adcnet_store;
489
490static 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
515static void preinit(int hup)
516{
517 if(hup)
518 return;
519 regfnet(adcnet);
520}
521
522static 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
545static 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
565static 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
581static 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
632static void terminate(void)
633{
634
635}
636
637static 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
651static 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
662MODULE(me)