Ported the qcmdqueue structure to the fnet-adc as well.
[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>
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"
24a794c2 41#include <tiger.h>
58e83d6a 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
50struct 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
56struct qcmd {
57 struct qcmd *next;
58 wchar_t **args;
59};
60
ed63a7f8
FT
61struct qcmdqueue {
62 struct qcmd *f, *l;
63 int size;
64};
65
58e83d6a 66struct adchub {
ffa81d5f 67 struct socket *sk;
58e83d6a 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;
24a794c2 76 struct wcspair *hubinf;
ed63a7f8 77 struct qcmdqueue queue;
58e83d6a 78};
79
80static wchar_t *eoc;
81/* I've never understood why both of these are necessary, but... */
82static wchar_t *privid, *cid;
83
84static 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
124static void sendeoc(struct socket *sk)
125{
126 sockqueue(sk, "\n", 1);
127}
128
129static 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
155static 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
ed63a7f8 171static struct qcmd *newqcmd(struct qcmdqueue *queue, wchar_t **args)
58e83d6a 172{
173 struct qcmd *new;
174
58e83d6a 175 new = smalloc(sizeof(*new));
176 new->next = NULL;
177 new->args = args;
ed63a7f8
FT
178 if(queue->l == NULL)
179 queue->f = new;
180 else
181 queue->l->next = new;
182 queue->l = new;
183 queue->size++;
58e83d6a 184 return(new);
185}
186
ed63a7f8 187static struct qcmd *ulqcmd(struct qcmdqueue *queue)
58e83d6a 188{
189 struct qcmd *ret;
190
ed63a7f8 191 if((ret = queue->f) == NULL)
58e83d6a 192 return(NULL);
ed63a7f8
FT
193 if((queue->f = ret->next) == NULL)
194 queue->l = NULL;
195 queue->size--;
58e83d6a 196 return(ret);
197}
198
199static 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)
0d6c5363 206#ifdef __GNUC__
9db779f4 207#define UNUSED __attribute__ ((unused))
0d6c5363 208#else
9db779f4 209#define UNUSED
0d6c5363 210#endif
9db779f4 211#define ADC_CMDCOM \
ffa81d5f
FT
212 struct adchub *hub UNUSED = fn->data; \
213 struct socket *sk UNUSED = hub->sk;
58e83d6a 214
215ADC_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;
24a794c2 237 free(hub->sup[o]);
58e83d6a 238 memmove(hub->sup[o], hub->sup[o + 1], parrlen(hub->sup) - o);
239 }
240 }
241}
242
243ADC_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
24a794c2 255ADC_CMDFN(cmd_inf)
256{
257 ADC_CMDCOM;
258
259 if(sender == NULL) {
260
261 }
262}
263
58e83d6a 264static struct command hubcmds[] = {
265 {L"SUP", 1, 0, cmd_sup},
266 {L"SID", 2, 0, cmd_sid},
24a794c2 267 {L"INF", 0, 0, cmd_inf},
58e83d6a 268 {NULL, 0, 0, NULL}
269};
270
271static 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
cab0b442 307static void hubread(struct socket *sk, struct fnetnode *fn)
58e83d6a 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)
cab0b442 317 return;
58e83d6a 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);
cab0b442 342 return;
58e83d6a 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));
cab0b442 349 return;
58e83d6a 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
cab0b442 360static void huberr(struct socket *sk, int err, struct fnetnode *fn)
58e83d6a 361{
362 killfnetnode(fn);
363}
364
ffa81d5f 365static void hubconnect(struct fnetnode *fn, struct socket *sk)
58e83d6a 366{
367 struct adchub *hub;
368
ffa81d5f
FT
369 sk->readcb = (void (*)(struct socket *, void *))hubread;
370 sk->errcb = (void (*)(struct socket *, int, void *))huberr;
371 sk->data = fn;
58e83d6a 372
373 hub = smalloc(sizeof(*hub));
374 memset(hub, 0, sizeof(*hub));
70d8f2f1 375 getsock(hub->sk = sk);
58e83d6a 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;
ffa81d5f 382 sendadc(sk, 0, L"HSUP", L"ADBASE", eoc, NULL);
58e83d6a 383}
384
385static void hubdestroy(struct fnetnode *fn)
386{
387 struct adchub *hub;
388
ffa81d5f 389 hub = fn->data;
58e83d6a 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
ffa81d5f
FT
398static void hubkill(struct fnetnode *fn)
399{
400 struct adchub *hub;
401
402 hub = fn->data;
403 hub->sk->close = 1;
404}
405
58e83d6a 406static int hubsetnick(struct fnetnode *fn, wchar_t *newnick)
407{
408 return(0);
409}
410
411static int hubreqconn(struct fnetpeer *peer)
412{
413 return(0);
414}
415
3ad44ea7 416static struct fnet adcnet_store = {
58e83d6a 417 .connect = hubconnect,
418 .destroy = hubdestroy,
ffa81d5f 419 .kill = hubkill,
58e83d6a 420 .setnick = hubsetnick,
421 .reqconn = hubreqconn,
422 .name = L"adc"
423};
424
3ad44ea7 425static struct fnet *adcnet = &adcnet_store;
426
58e83d6a 427static 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;
3ad44ea7 437 if(fn->fnet != adcnet)
58e83d6a 438 continue;
439 if((hub = fn->data) == NULL)
440 continue;
441 if((qcmd = ulqcmd(&hub->queue)) != NULL) {
ffa81d5f 442 if((hub->sk != NULL) && (hub->sk->state == SOCK_EST))
58e83d6a 443 dispatch(qcmd, fn);
444 freeqcmd(qcmd);
445 ret = 1;
446 break;
447 }
448 }
449 return(ret);
450}
451
452static void preinit(int hup)
453{
454 if(hup)
455 return;
3ad44ea7 456 regfnet(adcnet);
58e83d6a 457}
458
459static 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
492static void terminate(void)
493{
494
495}
496
497static struct configvar myvars[] = {
d9f89ef5 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). */
58e83d6a 502 {CONF_VAR_INT, "udpport", {.num = 0}},
d9f89ef5 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). */
58e83d6a 507 {CONF_VAR_INT, "tcpport", {.num = 0}},
508 {CONF_VAR_END}
509};
510
511static 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
522MODULE(me)