1 #ifdef RCS
2 static char rcsid[]="$Id: link.c,v 1.1.1.1 2000/11/13 02:42:45 holsta Exp $";
3 #endif
4 /******************************************************************************
5 * Internetting Cooperating Programmers
6 * ----------------------------------------------------------------------------
7 *
8 * ____ PROJECT
9 * | _ \ __ _ _ __ ___ ___ _ __
10 * | | | |/ _` | '_ \ / __/ _ \ '__|
11 * | |_| | (_| | | | | (_| __/ |
12 * |____/ \__,_|_| |_|\___\___|_| the IRC bot
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 *
16 * $Source: /cvsroot/dancer/dancer/src/link.c,v $
17 * $Revision: 1.1.1.1 $
18 * $Date: 2000/11/13 02:42:45 $
19 * $Author: holsta $
20 * $State: Exp $
21 * $Locker: $
22 *
23 * ---------------------------------------------------------------------------
24 *****************************************************************************/
25
26 /*
27 * - Exchange of userlist not implemented.
28 * - Problems when linking more than two clusters of linkbots
29 * together (only one cluster gets to know about the other
30 * cluster)
31 */
32
33 /*
34 * Define to test reliability. If defined it will skip acks
35 * and send duplicates at random. Don't do this at home, kids.
36 */
37 #undef UNRELIABLE
38
39 #include "dancer.h"
40 #include "trio.h"
41 #include "strio.h"
42 #include "list.h"
43 #include "user.h"
44 #include "transfer.h"
45 #include "link.h"
46 #include "command.h"
47 #include "function.h"
48
49 #include <stdarg.h>
50 #include <sys/socket.h>
51
52 #define TIMEREQUEST (-1)
53
54 extern time_t now;
55 extern int linkSocket;
56
57 extern struct sockaddr_in fromaddr;
58 extern itemuser *userHead;
59 extern itemlink *linkHead;
60 extern char nickname[];
61 extern ulong linkvalue;
62 extern long levels[];
63
64 time_t commontime = 0; /* Reference zero time */
65
66
67 /* ----------------------------------------------------------------
68 *
69 * Level 1 routines
70 *
71 * ---------------------------------------------------------------- */
72
73 /*
74 * Various routines to provide reliable message passing. The rtt_XXX
75 * routines are taken from chapter 8.4 of "Unix Network Programming"
76 * by Stevens. Didn't bother to add the comments.
77 */
78
79 #ifdef UNRELIABLE
80 int exp_backoff[] = {1, 1, 1, 1, 1};
81 #else
82 int exp_backoff[] = {1, 2, 4, 8, 16};
83 #endif
84 int whatever[] = {1, 1};
85
86 #define RTT_RXTMIN 2
87 #define RTT_RXTMAX 120
88 #define RTT_MAXNREXMT (sizeof(exp_backoff)/sizeof(exp_backoff[0]))
89
rtt_init(itemlink * r)90 void rtt_init(itemlink *r)
91 {
92 snapshot;
93 r->rtt_rtt = r->rtt_srtt = 0;
94 r->rtt_rttdev = 1.5;
95 r->rtt_nxtrto = 0;
96 }
97
rtt_newpack(itemlink * r)98 inline void rtt_newpack(itemlink *r)
99 {
100 snapshot;
101 r->rtt_nrexmt = 0;
102 }
103
104 /* Returns timeout value */
rtt_start(itemlink * r)105 int rtt_start(itemlink *r)
106 {
107 int rexmt;
108
109 snapshot;
110 if (r->rtt_nrexmt > 0) {
111 r->rtt_currto *= exp_backoff[r->rtt_nrexmt];
112 return (r->rtt_currto);
113 }
114 gettimeofday(&r->time_start, NULL);
115 if (r->rtt_nxtrto > 0) {
116 r->rtt_currto = r->rtt_nxtrto;
117 r->rtt_nxtrto = 0;
118 return (r->rtt_currto);
119 }
120 rexmt = (int)(r->rtt_srtt + (2.0 * r->rtt_rttdev) + 0.5);
121 if (rexmt < RTT_RXTMIN)
122 rexmt = RTT_RXTMIN;
123 else if (rexmt > RTT_RXTMAX)
124 rexmt = RTT_RXTMAX;
125 return (r->rtt_currto = rexmt);
126 }
127
rtt_stop(itemlink * r)128 void rtt_stop(itemlink *r)
129 {
130 long diff;
131 float err;
132
133 snapshot;
134 if (r->rtt_nrexmt > 0)
135 r->rtt_nxtrto = r->rtt_currto;
136 else {
137 r->rtt_nxtrto = 0;
138 gettimeofday(&r->time_stop, NULL);
139 diff = r->time_stop.tv_sec - r->time_start.tv_sec;
140 if (r->time_stop.tv_usec < r->time_start.tv_usec)
141 diff--;
142 r->rtt_rtt = (float)diff;
143 /* Use integer version instead */
144 err = r->rtt_rtt - r->rtt_srtt;
145 r->rtt_srtt += err/8;
146 if (err < 0.0)
147 err = -err;
148 r->rtt_rttdev += (err - r->rtt_rttdev) / 4;
149 }
150 }
151
rtt_timeout(itemlink * r)152 int rtt_timeout(itemlink *r)
153 {
154 snapshot;
155 rtt_stop(r);
156 return (++r->rtt_nrexmt >= RTT_MAXNREXMT);
157 }
158
159 /*
160 * msgid, type, msg, \n
161 */
162
163 #if 0
164 int L1_recv(struct Socket *self, char *buf, int len, int flags)
165 {
166 int size = sizeof(self->fromaddr);
167
168 snapshot;
169 size = recvfrom(self->handle, buf, len, flags,
170 (struct sockaddr *)&(self->fromaddr), &size);
171 buf[size] = NIL;
172 #ifdef DBUG
173 fprintf(stderr, "L1_recv: %d (%d) << %s",
174 self->handle, ntohs(self->fromaddr.sin_port), buf);
175 #endif
176 return size;
177 }
178
179 int L1_send(itemlink *self, char *msg, int len, int flags)
180 {
181 snapshot;
182 sendto(self->handle, msg, len, flags,
183 (struct sockaddr *)&self->addr, sizeof(struct sockaddr_in));
184 #ifdef DBUG
185 fprintf(stderr, "%d (%d) >> %s",
186 self->handle, ntohs(self->addr.sin_port), rawmsg);
187 #endif
188 }
189 #endif
190
191 /* --- ReadLink --------------------------------------------------- */
192
ReadLink(char * inbuf)193 int ReadLink(char *inbuf)
194 {
195 int size = sizeof(fromaddr);
196
197 snapshot;
198 size = recvfrom(linkSocket, inbuf, MAXLINE, 0,
199 (struct sockaddr *)&fromaddr, &size);
200 inbuf[size] = NIL;
201 #ifdef DBUG
202 fprintf(stderr, "%d (%d) << %s", linkSocket, ntohs(fromaddr.sin_port), inbuf);
203 #endif
204 return size;
205 }
206
207 /* --- WriteLink -------------------------------------------------- */
208
209 #define UDPBUFFER 1024
210
WriteLinkRaw(itemlink * r,char * rawmsg)211 void WriteLinkRaw(itemlink *r, char *rawmsg)
212 {
213 snapshot;
214
215 #ifdef DBUG
216 fprintf(stderr, "%d (%d) >> %s",
217 linkSocket, ntohs(r->addr.sin_port), rawmsg);
218 #endif
219
220 sendto(linkSocket, rawmsg, StrLength(rawmsg), 0,
221 (struct sockaddr *)&r->addr, sizeof(struct sockaddr_in));
222 }
223
WriteLink(itemlink * r,int type,char * msg)224 void WriteLink(itemlink *r, int type, char *msg)
225 {
226 unsigned char buffer[UDPBUFFER];
227
228 snapshot;
229 StrFormatMax(buffer, sizeof(buffer), "%d %d %s\n", ++r->mymsgid, type, msg);
230 WriteLinkRaw(r, buffer);
231 }
232
WriteLinkf(itemlink * r,int type,char * format,...)233 void WriteLinkf(itemlink *r, int type, char *format, ...)
234 {
235 char buffer[MAXLINE];
236 va_list args;
237
238 snapshot;
239 va_start(args, format);
240 trio_vsnprintf(buffer, sizeof(buffer), format, args);
241 va_end(args);
242
243 WriteLink(r, type, buffer);
244 }
245
246 /* --- SendLink --------------------------------------------------- */
247 /* If queue is empty send directly, else queue it. Don't remove
248 * from queue until ACK is received. The message on top of the
249 * list is always the one being sent, the rest are stalled to
250 * ensure casuality.
251 */
252
QueueLink(itemlink * r,int type,char * msg)253 void QueueLink(itemlink *r, int type, char *msg)
254 {
255 char buffer[BIGGERBUFFER];
256 itemmsg *m;
257
258 snapshot;
259 StrFormatMax(buffer, sizeof(buffer), "%d %lu %s\n", ++r->mymsgid, type, msg);
260
261 m = NewEntry(itemmsg);
262 if (m) {
263 m->msg = StrDuplicate(buffer);
264
265 /* If first in queue ship it now */
266 if (EmptyList(&r->RemoteHead)) {
267 rtt_newpack(r);
268 WriteLinkRaw(r, buffer);
269
270 #ifdef UNRELIABLE
271 if (Rnd() < 0.2) /* Send duplicate */
272 WriteLinkRaw(r, buffer);
273 #endif
274
275 r->expires = now + rtt_start(r);
276 }
277
278 InsertLast(&r->RemoteHead, m);
279 }
280 }
281
SendLink(itemlink * r,int type,char * format,...)282 void SendLink(itemlink *r, int type, char *format, ...)
283 {
284 char buffer[BIGGERBUFFER];
285 va_list args;
286
287 snapshot;
288
289 va_start(args, format);
290 trio_vsnprintf(buffer, sizeof(buffer), format, args);
291 va_end(args);
292
293 QueueLink(r, type, buffer);
294 }
295
SendLinkAll(int type,char * format,...)296 void SendLinkAll(int type, char *format, ...)
297 {
298 char buffer[BIGGERBUFFER];
299 va_list args;
300 itemlink *r;
301
302 snapshot;
303
304 va_start(args, format);
305 trio_vsnprintf(buffer, sizeof(buffer), format, args);
306 va_end(args);
307
308 for (r = First(linkHead); r; r = Next(r)) {
309 if (!r->new)
310 QueueLink(r, type, buffer);
311 }
312 }
313
SendLinkBut(itemlink * rin,int type,char * format,...)314 void SendLinkBut(itemlink *rin, int type, char *format, ...)
315 {
316 char buffer[BIGGERBUFFER];
317 va_list args;
318 itemlink *r;
319
320 snapshot;
321
322 va_start(args, format);
323 trio_vsnprintf(buffer, sizeof(buffer), format, args);
324 va_end(args);
325
326 for (r = First(linkHead); r; r = Next(r)) {
327 if (!r->new && (r != rin))
328 QueueLink(r, type, buffer);
329 }
330 }
331
332 /* --- CheckLinkQueue --------------------------------------------- */
333
334 /*
335 * Whenever a message is sent it must wait for acknowledgement.
336 * When messages are sent they are put in a queue. Each linked
337 * bot has its own queue. When an ack is received the next message
338 * from the queue is sent.
339 */
340
CheckLinkQueue(void)341 void CheckLinkQueue(void)
342 {
343 itemlink *r;
344 itemmsg *m;
345
346 snapshot;
347
348 /* Called each second */
349 for (r = First(linkHead); r; r = Next(r)) {
350 m = First(&r->RemoteHead);
351 if (m) {
352 if (r->expires <= now) {
353 if (rtt_timeout(r)) {
354 /* Link is dead, remove it */
355 r = RemoveLink(r);
356 continue; /* for */
357 }
358 else {
359 /* Retransmit message */
360 WriteLinkRaw(r, m->msg);
361 r->expires = now + rtt_start(r);
362 }
363 }
364 }
365 }
366 }
367
FlushLinkQueue(itemlink * r)368 void FlushLinkQueue(itemlink *r)
369 {
370 snapshot;
371 FlushList(&r->RemoteHead, FreeMessage);
372 }
373
374 /* --- LinkDequeue ------------------------------------------------ */
375
LinkDequeue(itemlink * r,unsigned long msgid)376 bool LinkDequeue(itemlink *r, unsigned long msgid)
377 {
378 unsigned long mid;
379 int type;
380 itemmsg *m;
381
382 snapshot;
383
384 /* Remove from top of queue */
385 if ((m = First(&r->RemoteHead)) &&
386 (2 == StrScan(m->msg, "%d %lu", &mid, &type))) {
387
388 /* Duplicates of previously acknowledged message may exist */
389 if (mid == msgid) {
390 /* Wait to remove the rejected link until it acknowledges */
391 if (IBCP_REJECT == type) {
392 RemoveLink(r);
393 return TRUE;
394 }
395 else {
396 DeleteEntry(&r->RemoteHead, m, FreeMessage);
397
398 m = First(&r->RemoteHead);
399 if (m) {
400 /* Ship the next */
401 rtt_newpack(r);
402 WriteLinkRaw(r, m->msg);
403 r->expires = now + rtt_start(r);
404 }
405 }
406 }
407 }
408 return FALSE;
409 }
410
411
412 /* ----------------------------------------------------------------
413 *
414 * Level 2 routines
415 *
416 * ---------------------------------------------------------------- */
417
418 /* --- LinkQuit --------------------------------------------------- */
419
420 /*
421 * The QUIT message surpasses the queue. We don't care about
422 * acknowledgement - if the recipient received it fine; if not
423 * the connection will timeout eventually.
424 */
425
LinkQuit(void)426 void LinkQuit(void)
427 {
428 itemlink *r;
429
430 snapshot;
431
432 /* Equivalent to SendLinkAll(IBCP_QUIT, "Bored"); */
433 for (r = First(linkHead); r; r = Next(r))
434 WriteLink(r, IBCP_QUIT, "Bored");
435 }
436
437 /* --- LinkHello -------------------------------------------------- */
438
LinkHello(char * msg)439 itemlink *LinkHello(char *msg)
440 {
441 int ver, bottype;
442 ulong key;
443 itemlink *r = NULL;
444 char name[MINIBUFFER];
445
446 snapshot;
447 if (4 == StrScan(msg, "%d %d %s %lu", &ver, &bottype, name, &key))
448 {
449 /*
450 * We initiated the link. Now that we've got the info
451 * of the other end we add it and reply with our info.
452 */
453 r = AddLink(name, NULL, ntohl(fromaddr.sin_addr.s_addr),
454 ntohs(fromaddr.sin_port));
455 if (r)
456 {
457 r->bottype = bottype;
458 r->protoversion = ver;
459 /* We asked to link so we assume that the other end is authenticated */
460 r->passed = TRUE;
461 SendLink(r, IBCP_HELLO_REPLY, "%d %d %s %lu",
462 IBCP_VERSION, IBCP_BOT_DANCER, nickname, key ^ linkvalue);
463 }
464 }
465 return r;
466 }
467
468
469 /* --- LinkHelloReply --------------------------------------------- */
470
LinkHelloReply(itemlink * r,char * msg)471 void LinkHelloReply(itemlink *r, char *msg)
472 {
473 int ver, bottype;
474 ulong key;
475 char name[MINIBUFFER];
476
477 snapshot;
478 if (4 == StrScan(msg, "%d %d %s %lu", &ver, &bottype, name, &key)) {
479 if (r)
480 {
481 /*
482 * The other end initiated the link. We have already
483 * sent our info (in the HELLO message in ctcp.c) and
484 * now get the info of the initiater in return
485 */
486 r->bottype = bottype;
487 r->protoversion = ver;
488 if (name)
489 r->name = StrDuplicate(name);
490
491 if ((r->linkvalue ^ key) == r->tmpvalue)
492 {
493 r->passed = TRUE;
494 #if 0
495 SendLinkBut(r, IBCP_AUTH, "%ld %d %d %d %s",
496 ntohl(fromaddr.sin_addr.s_addr), ntohs(fromaddr.sin_port),
497 ver, bottype, name);
498 r->new = FALSE;
499 #endif
500 SendLink(r, IBCP_ACCEPT, "");
501
502 #if 0
503 /* Tell newcomer about everybody else in net */
504 for (rr = First(linkHead); rr; rr = Next(rr))
505 {
506 if (rr != r)
507 SendLink(r, IBCP_AUTH_LIST, "%ld %d %d %d %s",
508 ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
509 rr->protoversion, rr->bottype, rr->name);
510 }
511 SendLink(r, IBCP_AUTH_END, "1");
512 /* Logf(LINK, "Added %s from %s %d", r->name,
513 ntohl(r->addr.sin_addr.s_addr), ntons(r->addr.sin_port));
514 */
515 #endif
516 }
517 else
518 {
519 r->passed = FALSE;
520 SendLink(r, IBCP_REJECT, "No authentication");
521 /* Link will be removed in LinkDequeue() */
522 /* Logf(LINK, "Rejected..."); */
523 return;
524 }
525 }
526 }
527 }
528
529
530 /* --- LinkAuth --------------------------------------------------- */
531
LinkAuth(itemlink * r,char * msg)532 void LinkAuth(itemlink *r, char *msg)
533 {
534 itemlink *rr;
535 long addr;
536 int port, ver, bottype;
537 char name[MINIBUFFER];
538
539 snapshot;
540 if (5 == StrScan(msg, "%ld %d %d %d %s", &addr, &port, &ver, &bottype, name))
541 {
542 rr = AddLink(name, NULL, addr, port);
543 if (rr)
544 {
545 rr->bottype = bottype;
546 rr->protoversion = ver;
547 rr->passed = TRUE;
548 rr->new = FALSE; /* Add immediately */
549 }
550 }
551 }
552
LinkAuthList(itemlink * r,char * msg)553 void LinkAuthList(itemlink *r, char *msg)
554 {
555 itemlink *rr;
556 long addr;
557 int port, ver, bottype;
558 char name[MINIBUFFER];
559 /* char naddr[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:256.256.256.256"]; */
560
561 snapshot;
562 if (5 == StrScan(msg, "%ld %d %d %d %s", &addr, &port, &ver, &bottype, name))
563 {
564 rr = AddLink(name, NULL, addr, port);
565 if (rr)
566 {
567 rr->bottype = bottype;
568 rr->protoversion = ver;
569 rr->passed = TRUE;
570 rr->new = TRUE;
571 }
572 }
573 }
574
LinkAuthEnd(itemlink * r,char * msg)575 void LinkAuthEnd(itemlink *r, char *msg)
576 {
577 itemlink *rr, *xrr;
578
579 snapshot;
580 if (*msg ^ '0') {
581 /* Return our cluster */
582 for (rr = First(linkHead); rr; rr = Next(rr)) {
583 if ( !rr->new && (rr != r) )
584 SendLink(r, IBCP_AUTH_LIST, "%ld %d %d %d %s",
585 ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
586 rr->protoversion, rr->bottype, rr->name);
587 }
588 SendLink(r, IBCP_AUTH_END, "0");
589 }
590
591 /* Commit newly received links */
592 for (rr = First(linkHead); rr; rr = Next(rr)) {
593 if (rr->new) {
594 for (xrr = rr; xrr; xrr = Next(xrr)) {
595 if ( !xrr->new )
596 SendLink(xrr, IBCP_AUTH, "%ld %d %d %d %s",
597 ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
598 rr->protoversion, rr->bottype, rr->name);
599 }
600 rr->new = FALSE;
601 }
602 }
603 }
604
605 /* --- LinkAccept ------------------------------------------------- */
606
LinkAccept(itemlink * r)607 void LinkAccept(itemlink *r)
608 {
609 snapshot;
610 SendLink(r, IBCP_SYNC, "%ld %ld", TIMEREQUEST, now);
611 }
612
613 /* --- LinkSync --------------------------------------------------- */
614
LinkSync(itemlink * r,char * msg)615 void LinkSync(itemlink *r, char *msg)
616 {
617 long ct, then;
618
619 snapshot;
620 if (2 == StrScan(msg, "%ld %ld", &ct, &then)) {
621 if (ct == TIMEREQUEST) {
622 /* It is a request for common time */
623 SendLink(r, IBCP_SYNC, "%ld %ld", now - commontime, then);
624 }
625 else {
626 /* T_common_ref = T_now - (T_remote + T_round-trip/2) */
627 long cnow = now;
628 commontime = cnow - ct - (cnow - then) / 2;
629 SendLink(r, IBCP_USERS_REQUEST, "%lu", LatestUserUpdate());
630 }
631 }
632 }
633
634 /* --- LinkNickname ----------------------------------------------- */
635
LinkNickname(itemlink * r,char * msg)636 void LinkNickname(itemlink *r, char *msg)
637 {
638 snapshot;
639 if (r->name)
640 StrFree(r->name);
641 r->name = StrDuplicate(msg);
642 }
643
644 /* --- LinkMulticast ---------------------------------------------- */
645
LinkMulticast(itemlink * r,char * msg)646 void LinkMulticast(itemlink *r, char *msg)
647 {
648 char *text;
649
650 snapshot;
651 text = StrIndex(msg, ' ');
652 if (text) {
653 /*
654 * Multicasting from remote link is only forwarded
655 * to local listening clients
656 */
657 MulticastLocalf(atoi(msg), "[%s]%s", r->name, text);
658 }
659 }
660
661 /* --- LinkSendUsers ---------------------------------------------- */
662
663 #if 0
664 char *LevelType(int level)
665 {
666 snapshot;
667 if (level < LEVELRECOG)
668 return "UNKNOWN";
669 else if (level < LEVELCHANOP)
670 return "RECOGNIZED";
671 else if (level < LEVELTRUST)
672 return "CHANOP";
673 else if (level < LEVELEXPERT)
674 return "TRUSTED";
675 else if (level < LEVELBOT)
676 return "EXPERT";
677 else if (level < LEVELOWNER)
678 return "MAINTAINER";
679 else
680 return "OWNER";
681 }
682
683 void LinkSendUser(itemlink *r, itemuser *u)
684 {
685 char buffer[BIGGERBUFFER];
686 itemlist *t;
687
688 snapshot;
689 StrFormatMax(buffer, sizeof(buffer), "%s", LevelType(u->level));
690 if (u->flags.autoop)
691 StrAppendMax(buffer, sizeof(buffer), ",AUTO");
692 if (u->flags.banprotect)
693 StrAppendMax(buffer, sizeof(buffer), ",PROTECT");
694 /* u->flags.linkbot is local data and not shared */
695
696 SendLink(r, IBCP_DATA_USER, "BEGIN: NICK:%s PASS:%s PRIV:%s CTIME:%ld MTIME:%ld",
697 u->nick, u->passwd, buffer, u->created - commontime, u->modified - commontime);
698 SendLink(r, IBCP_DATA_USER, "EMAIL:\"%s\" COMMENT:\"%s\"",
699 u->realname, u->comment);
700
701 buffer[0] = (char)0;
702 for (t = First(u->domainhead); t; t = Next(t))
703 /* What is this? */
704 StrFormatMax(buffer, sizeof(buffer), "%s%s,",
705 (NULL == StrIndex((char *)t->pointer, '!')) ? "*!" : "",
706 (char *)t->pointer);
707 SendLink(r, IBCP_DATA_USER, "HOST:%s END:", buffer);
708 }
709
710 void LinkSendUserlist(itemlink *r)
711 {
712 itemuser *u;
713
714 snapshot;
715 for (u = First(userHead); u; u = Next(u))
716 LinkSendUser(r, u);
717 }
718
719 /* --- LinkUpdateUser --------------------------------------------- */
720
721 void LinkUpdateUser(itemlink *r, char *msg)
722 {
723 static itemuser user;
724 char buffer[BIGGERBUFFER];
725 char strtype[MINIBUFFER];
726 char strargs[BIGBUFFER];
727 int index = 0;
728
729 snapshot;
730 #ifdef HAVE_N_IN_SCANF
731 StrScan(&msg[index], "%s %n", buffer, &index);
732 #else
733 StrScan(&msg[index], "%s", buffer);
734 index = StrLength(buffer);
735 #endif
736
737 StrScan(buffer, "[^:]*1[:][^\n]", strtype, strargs);
738
739 if (StrEqual(strtype, "BEGIN"))
740 memset(&user, NIL, sizeof(user));
741 else if (StrEqual(strtype, "NICK"))
742 user.nick = StrDuplicate(strargs);
743 else if (StrEqual(strtype, "PASS"))
744 user.passwd = StrDuplicate(strargs);
745 /* Remember that time is relative to commontime */
746 else if (StrEqual(strtype, "END")) {
747 /* Insert user entry */
748 #if 0
749 AddUser(&user, buffer); /* <--- Must be UpdateUser() not AddUser() */
750 StrFormatMax(buffer, sizeof(buffer), "%s 0 %d %d 0", user.passwd, NULL,
751 user.modified, user.created);
752 AddNewData(&user, buffer);
753 AddDomain(&user, whatever);
754 #endif
755 if (user.nick)
756 StrFree(user.nick);
757 if (user.passwd)
758 StrFree(user.passwd);
759 }
760 }
761 #endif
762
763 /* --- LinkUsers -------------------------------------------------- */
764
765 char *SetUserFlags(uFlags *);
766
LinkUsersRequest(itemlink * r,char * msg)767 void LinkUsersRequest(itemlink *r, char *msg)
768 {
769 char buffer[3*BIGBUFFER];
770 itemuser *u;
771 itemlist *l;
772 time_t t;
773
774 snapshot;
775 if (1 == StrScan(msg, "%lu", &t) ) {
776 printf("update since %lu\n", t);
777
778 /* Ship all entries that are newer than 't' */
779 for (u = First(userHead); u; u = Next(u)) {
780 if (u->modified > t - 400) { /* !!! remove - 400 !!! */
781
782 /* Should send the same data as UserSave() */
783 SendLink(r, IBCP_USERS_LIST, "%s", WriteUserHead(buffer, sizeof(buffer), u));
784 for (l = First(u->domainhead); l; l = Next(l))
785 SendLink(r, IBCP_USERS_LIST, "!%s\n", (char *)l->pointer);
786 }
787 }
788 SendLink(r, IBCP_USERS_END, "");
789 }
790 }
791
LinkUsersUpdate(itemlink * r,char * msg)792 void LinkUsersUpdate(itemlink *r, char *msg)
793 {
794 snapshot;
795 printf("Should do the update here\n");
796 }
797
LinkUsersList(itemlink * r,char * msg)798 void LinkUsersList(itemlink *r, char *msg)
799 {
800 snapshot;
801 LinkUsersUpdate(r, msg);
802 /* Forward to rest of local cluster */
803 SendLinkBut(r, IBCP_USERS_UPDATE, msg);
804 }
805
LinkUsersEnd(itemlink * r,char * msg)806 void LinkUsersEnd(itemlink *r, char *msg)
807 {
808 snapshot;
809 /* SendLink(r, IBCP_AUTH_REQUEST, "");*/
810 printf("initiate AUTH... when installed\n");
811 }
812
813
814 /* --- LinkRemote ------------------------------------------------- */
815
LinkRemoteCmd(itemlink * r,char * msg)816 void LinkRemoteCmd(itemlink *r, char *msg)
817 {
818 char name[MINIBUFFER];
819 char cmd[MIDBUFFER];
820 char buffer[BIGBUFFER] = "";
821
822 snapshot;
823 if (2 <= StrScan(msg, "%s %s %[^\n]", name, cmd, buffer)) {
824 printf("remote '%s %s' from %s", cmd, buffer[0] ? buffer : "", name);
825 }
826 }
827
LinkRemoteAnswer(itemlink * r,char * msg)828 void LinkRemoteAnswer(itemlink *r, char *msg)
829 {
830 extern bool chat;
831 extern itemclient *client;
832 char name[MINIBUFFER];
833 char buffer[BIGBUFFER];
834 bool chit;
835 itemclient *klient;
836
837 snapshot;
838 if (2 == StrScan(msg, "%"MINIBUFFERTXT"s %"BIGBUFFERTXT"[^\n]", name, buffer)) {
839 printf("remote answer '%s' to %s", buffer, name);
840 chit = chat;
841 klient = client;
842 chat = (client = FindClientByNick(name)) ? TRUE : FALSE;
843 Send(name, buffer);
844 chat = chit;
845 client = klient;
846 }
847 }
848
849 /* --- LinkParse -------------------------------------------------- */
850
851 #define IDBACKTRACK 1000u
852
IsDuplicate(unsigned long this,unsigned long last)853 bool IsDuplicate(unsigned long this, unsigned long last)
854 {
855 snapshot;
856
857 /* This strange looking code works because we are dealing
858 * with unsigned arithmetic. Hopefully the compiler doesn't
859 * choose to optimize it away.
860 */
861 if (this <= last)
862 return (this - IDBACKTRACK <= last - IDBACKTRACK);
863 return FALSE;
864 }
865
LinkParse(char * line)866 void LinkParse(char *line)
867 {
868 itemlink *r;
869 char buffer[BIGBUFFER];
870 char out[BIGBUFFER];
871 char *msg;
872 int type, rc;
873 unsigned long msgid;
874
875 snapshot;
876 #if 1
877
878 if (2 <= StrScan(line, "%d %d %[^\n]", &msgid, &type, buffer)) {
879 msg = buffer;
880 r = FindLink(fromaddr.sin_addr.s_addr, fromaddr.sin_port);
881 if (NULL == r) {
882 if (type == IBCP_HELLO) {
883 /* We will only accept a HELLO from unknown destinations. */
884 /* And only if it contains data */
885 if (StrLength(msg) > 0) {
886 r = LinkHello(msg);
887 if (r) {
888 /* Acknowledge directly */
889 StrFormatMax(out, sizeof(out), "%d %d\n", msgid, IBCP_ACK);
890 WriteLinkRaw(r, out);
891 r->yourmsgid = msgid;
892 }
893 }
894 }
895
896 if (NULL == r)
897 return;
898 }
899
900 /* r is always set at this point */
901
902 if (IBCP_ACK == type) {
903 /* We got an acknowledgement. Dequeue message and send next */
904 LinkDequeue(r, msgid);
905 /* Don't acknowledge acknowledgements... bad karma */
906 return;
907 }
908
909 if (IsDuplicate(msgid, r->yourmsgid))
910 /* Ignore duplicates */
911 return;
912
913 rtt_stop(r);
914
915 if (StrLength(msg) > 0) {
916 /* If zero it's only an ack */
917
918 #if 1
919 #ifdef UNRELIABLE
920 if (Rnd() > 0.2) /* Don't acknowledge */
921 #endif
922 StrFormatMax(out, sizeof(out), "%d %d\n", msgid, IBCP_ACK);
923 WriteLinkRaw(r, out); /* &fromaddr */
924 /* bool wantpiggy; ulong piggymsg; */
925 #endif
926
927 /*
928 * Check if from authenticated bot. There are two ways to become
929 * authenticated: either by authentication at connect-time, or
930 * through validation by another bot.
931 */
932
933 if (r->passed)
934 {
935 switch (type)
936 {
937 case IBCP_QUIT: /* Link that decided to quit */
938 RemoveLink(r);
939 r = NULL;
940 break;
941 case IBCP_ACCEPT:
942 LinkAccept(r);
943 break;
944 case IBCP_REJECT: /* I was rejected by r */
945 RemoveLink(r);
946 r = NULL;
947 break;
948 case IBCP_SYNC: /* Establish or request common time */
949 LinkSync(r, msg);
950 break;
951 case IBCP_AUTH:
952 LinkAuth(r, msg);
953 break;
954 case IBCP_AUTH_LIST:
955 /* Not broadcasted until AUTH_END is received */
956 LinkAuthList(r, msg);
957 break;
958 case IBCP_AUTH_END:
959 LinkAuthEnd(r, msg);
960 break;
961
962 /* Handle userlist */
963 case IBCP_USERS_REQUEST:
964 LinkUsersRequest(r, msg);
965 break;
966 case IBCP_USERS_UPDATE:
967 LinkUsersUpdate(r, msg);
968 break;
969 case IBCP_USERS_LIST:
970 LinkUsersList(r, msg);
971 break;
972 case IBCP_USERS_END:
973 LinkUsersEnd(r, msg);
974 break;
975
976 case IBCP_REMOTE_CMD:
977 LinkRemoteCmd(r, msg);
978 break;
979 case IBCP_REMOTE_ANSWER:
980 LinkRemoteAnswer(r, msg);
981 break;
982
983 case IBCP_NICKNAME:
984 LinkNickname(r, msg);
985 break;
986
987 case IBCP_MULTICAST:
988 LinkMulticast(r, msg);
989 break;
990
991 default:
992 break;
993 }
994 }
995 else if (type == IBCP_HELLO_REPLY)
996 {
997 /*
998 * HELLO_REPLY is part of the authentication scheme and
999 * therefor we will only accept it if the link isn't
1000 * authenticated yet.
1001 */
1002 LinkHelloReply(r, msg);
1003 }
1004 r->yourmsgid = msgid;
1005 }
1006 r->lasttime = now;
1007 }
1008
1009 #else
1010
1011 unsigned long msgid;
1012 int type;
1013
1014 /* Skip escape code if present */
1015 if (*line == IBCP_ESC) line++;
1016
1017 msg = buffer;
1018 if ( 2 <= StrScan(line, "%d %lu %[^\n]", &type, &msgid, msg) ) {
1019
1020 r = FindLink(fromaddr.sin_addr.s_addr, fromaddr.sin_port);
1021
1022 if (type == IBCP_ACK) {
1023 /* We got an acknowledgement. Dequeue message and send next */
1024 if (r)
1025 LinkDequeue(r, msgid);
1026 /* Don't acknowledge acknowledgements... bad karma */
1027 return;
1028 }
1029
1030 /* Ignore duplicates */
1031 if (r && IsDuplicate(msgid, r->yourmsgid)) {
1032 printf("Ignored\n");
1033 return;
1034 }
1035
1036 #ifdef UNRELIABLE
1037 if (Rnd() > 0.2) /* Don't acknowledge */
1038 #endif
1039 WriteLink(&fromaddr, IBCP_ACK, "");
1040
1041 if (type == IBCP_HELLO) {
1042 LinkHello(r, msg);
1043 return;
1044 } else if (type == IBCP_HELLO_REPLY) {
1045 LinkHelloReply(r, msg);
1046 return;
1047 }
1048
1049 if (r) {
1050
1051 rtt_stop(r);
1052
1053 /*
1054 * Check if from authenticated bot. There are two ways to become
1055 * authenticated: either by authentication at connect-time, or
1056 * through validation by another bot
1057 */
1058
1059 /*if (r->passed)*/ {
1060 switch (type) {
1061
1062 case IBCP_QUIT: /* Link that decided to quit */
1063 RemoveLink(r);
1064 break;
1065
1066 case IBCP_ACCEPT:
1067 LinkAccept(r);
1068 break;
1069 case IBCP_REJECT: /* I was rejected by r */
1070 RemoveLink(r);
1071 break;
1072
1073 case IBCP_AUTH:
1074 LinkAuth(r, msg);
1075 break;
1076 case IBCP_AUTH_LIST:
1077 /* Not passed until AUTH_END is received */
1078 LinkAuthList(r, msg);
1079 break;
1080 case IBCP_AUTH_END:
1081 LinkAuthEnd(r, msg);
1082 break;
1083
1084 case IBCP_SYNC: /* Establish or request common time */
1085 LinkSync(r, msg);
1086 break;
1087
1088 /* Handle userlist */
1089 case IBCP_USERS_REQUEST:
1090 LinkUsersRequest(r, msg);
1091 break;
1092 case IBCP_USERS_UPDATE:
1093 LinkUsersUpdate(r, msg);
1094 break;
1095 case IBCP_USERS_LIST:
1096 LinkUsersList(r, msg);
1097 break;
1098 case IBCP_USERS_END:
1099 LinkUsersEnd(r, msg);
1100 break;
1101
1102 case IBCP_REMOTE_CMD:
1103 LinkRemoteCmd(r, msg);
1104 break;
1105 case IBCP_REMOTE_ANSWER:
1106 LinkRemoteAnswer(r, msg);
1107 break;
1108
1109 case IBCP_NICKNAME:
1110 LinkNickname(r, msg);
1111 break;
1112
1113 case IBCP_MULTICAST:
1114 LinkMulticast(r, msg);
1115 break;
1116
1117 default:
1118 break;
1119 }
1120 }
1121 r->yourmsgid = msgid;
1122 r->lasttime = now;
1123 }
1124 }
1125
1126 #endif
1127 }
1128