Further work on the RPM spec file.
[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
61struct adchub {
ffa81d5f 62 struct socket *sk;
58e83d6a 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;
24a794c2 71 struct wcspair *hubinf;
58e83d6a 72 struct qcmd *queue;
73};
74
75static wchar_t *eoc;
76/* I've never understood why both of these are necessary, but... */
77static wchar_t *privid, *cid;
78
79static 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
119static void sendeoc(struct socket *sk)
120{
121 sockqueue(sk, "\n", 1);
122}
123
124static 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
150static 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
166static 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
179static 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
189static 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)
0d6c5363 196#ifdef __GNUC__
9db779f4 197#define UNUSED __attribute__ ((unused))
0d6c5363 198#else
9db779f4 199#define UNUSED
0d6c5363 200#endif
9db779f4 201#define ADC_CMDCOM \
ffa81d5f
FT
202 struct adchub *hub UNUSED = fn->data; \
203 struct socket *sk UNUSED = hub->sk;
58e83d6a 204
205ADC_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;
24a794c2 227 free(hub->sup[o]);
58e83d6a 228 memmove(hub->sup[o], hub->sup[o + 1], parrlen(hub->sup) - o);
229 }
230 }
231}
232
233ADC_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
24a794c2 245ADC_CMDFN(cmd_inf)
246{
247 ADC_CMDCOM;
248
249 if(sender == NULL) {
250
251 }
252}
253
58e83d6a 254static struct command hubcmds[] = {
255 {L"SUP", 1, 0, cmd_sup},
256 {L"SID", 2, 0, cmd_sid},
24a794c2 257 {L"INF", 0, 0, cmd_inf},
58e83d6a 258 {NULL, 0, 0, NULL}
259};
260
261static 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
cab0b442 297static void hubread(struct socket *sk, struct fnetnode *fn)
58e83d6a 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)
cab0b442 307 return;
58e83d6a 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);
cab0b442 332 return;
58e83d6a 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));
cab0b442 339 return;
58e83d6a 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
cab0b442 350static void huberr(struct socket *sk, int err, struct fnetnode *fn)
58e83d6a 351{
352 killfnetnode(fn);
353}
354
ffa81d5f 355static void hubconnect(struct fnetnode *fn, struct socket *sk)
58e83d6a 356{
357 struct adchub *hub;
358
ffa81d5f
FT
359 sk->readcb = (void (*)(struct socket *, void *))hubread;
360 sk->errcb = (void (*)(struct socket *, int, void *))huberr;
361 sk->data = fn;
58e83d6a 362
363 hub = smalloc(sizeof(*hub));
364 memset(hub, 0, sizeof(*hub));
70d8f2f1 365 getsock(hub->sk = sk);
58e83d6a 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;
ffa81d5f 372 sendadc(sk, 0, L"HSUP", L"ADBASE", eoc, NULL);
58e83d6a 373}
374
375static void hubdestroy(struct fnetnode *fn)
376{
377 struct adchub *hub;
378
ffa81d5f 379 hub = fn->data;
58e83d6a 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
ffa81d5f
FT
388static void hubkill(struct fnetnode *fn)
389{
390 struct adchub *hub;
391
392 hub = fn->data;
393 hub->sk->close = 1;
394}
395
58e83d6a 396static int hubsetnick(struct fnetnode *fn, wchar_t *newnick)
397{
398 return(0);
399}
400
401static int hubreqconn(struct fnetpeer *peer)
402{
403 return(0);
404}
405
3ad44ea7 406static struct fnet adcnet_store = {
58e83d6a 407 .connect = hubconnect,
408 .destroy = hubdestroy,
ffa81d5f 409 .kill = hubkill,
58e83d6a 410 .setnick = hubsetnick,
411 .reqconn = hubreqconn,
412 .name = L"adc"
413};
414
3ad44ea7 415static struct fnet *adcnet = &adcnet_store;
416
58e83d6a 417static 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;
3ad44ea7 427 if(fn->fnet != adcnet)
58e83d6a 428 continue;
429 if((hub = fn->data) == NULL)
430 continue;
431 if((qcmd = ulqcmd(&hub->queue)) != NULL) {
ffa81d5f 432 if((hub->sk != NULL) && (hub->sk->state == SOCK_EST))
58e83d6a 433 dispatch(qcmd, fn);
434 freeqcmd(qcmd);
435 ret = 1;
436 break;
437 }
438 }
439 return(ret);
440}
441
442static void preinit(int hup)
443{
444 if(hup)
445 return;
3ad44ea7 446 regfnet(adcnet);
58e83d6a 447}
448
449static 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
482static void terminate(void)
483{
484
485}
486
487static struct configvar myvars[] = {
d9f89ef5 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). */
58e83d6a 492 {CONF_VAR_INT, "udpport", {.num = 0}},
d9f89ef5 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). */
58e83d6a 497 {CONF_VAR_INT, "tcpport", {.num = 0}},
498 {CONF_VAR_END}
499};
500
501static 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
512MODULE(me)