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