#ifdef RCS
static char rcsid[]="$Id: link.c,v 1.1.1.1 2000/11/13 02:42:45 holsta Exp $";
#endif
/******************************************************************************
* Internetting Cooperating Programmers
* ----------------------------------------------------------------------------
*
* ____ PROJECT
* | _ \ __ _ _ __ ___ ___ _ __
* | | | |/ _` | '_ \ / __/ _ \ '__|
* | |_| | (_| | | | | (_| __/ |
* |____/ \__,_|_| |_|\___\___|_| the IRC bot
*
* All files in this archive are subject to the GNU General Public License.
*
* $Source: /cvsroot/dancer/dancer/src/link.c,v $
* $Revision: 1.1.1.1 $
* $Date: 2000/11/13 02:42:45 $
* $Author: holsta $
* $State: Exp $
* $Locker: $
*
* ---------------------------------------------------------------------------
*****************************************************************************/
/*
* - Exchange of userlist not implemented.
* - Problems when linking more than two clusters of linkbots
* together (only one cluster gets to know about the other
* cluster)
*/
/*
* Define to test reliability. If defined it will skip acks
* and send duplicates at random. Don't do this at home, kids.
*/
#undef UNRELIABLE
#include "dancer.h"
#include "trio.h"
#include "strio.h"
#include "list.h"
#include "user.h"
#include "transfer.h"
#include "link.h"
#include "command.h"
#include "function.h"
#include <stdarg.h>
#include <sys/socket.h>
#define TIMEREQUEST (-1)
extern time_t now;
extern int linkSocket;
extern struct sockaddr_in fromaddr;
extern itemuser *userHead;
extern itemlink *linkHead;
extern char nickname[];
extern ulong linkvalue;
extern long levels[];
time_t commontime = 0; /* Reference zero time */
/* ----------------------------------------------------------------
*
* Level 1 routines
*
* ---------------------------------------------------------------- */
/*
* Various routines to provide reliable message passing. The rtt_XXX
* routines are taken from chapter 8.4 of "Unix Network Programming"
* by Stevens. Didn't bother to add the comments.
*/
#ifdef UNRELIABLE
int exp_backoff[] = {1, 1, 1, 1, 1};
#else
int exp_backoff[] = {1, 2, 4, 8, 16};
#endif
int whatever[] = {1, 1};
#define RTT_RXTMIN 2
#define RTT_RXTMAX 120
#define RTT_MAXNREXMT (sizeof(exp_backoff)/sizeof(exp_backoff[0]))
void rtt_init(itemlink *r)
{
snapshot;
r->rtt_rtt = r->rtt_srtt = 0;
r->rtt_rttdev = 1.5;
r->rtt_nxtrto = 0;
}
inline void rtt_newpack(itemlink *r)
{
snapshot;
r->rtt_nrexmt = 0;
}
/* Returns timeout value */
int rtt_start(itemlink *r)
{
int rexmt;
snapshot;
if (r->rtt_nrexmt > 0) {
r->rtt_currto *= exp_backoff[r->rtt_nrexmt];
return (r->rtt_currto);
}
gettimeofday(&r->time_start, NULL);
if (r->rtt_nxtrto > 0) {
r->rtt_currto = r->rtt_nxtrto;
r->rtt_nxtrto = 0;
return (r->rtt_currto);
}
rexmt = (int)(r->rtt_srtt + (2.0 * r->rtt_rttdev) + 0.5);
if (rexmt < RTT_RXTMIN)
rexmt = RTT_RXTMIN;
else if (rexmt > RTT_RXTMAX)
rexmt = RTT_RXTMAX;
return (r->rtt_currto = rexmt);
}
void rtt_stop(itemlink *r)
{
long diff;
float err;
snapshot;
if (r->rtt_nrexmt > 0)
r->rtt_nxtrto = r->rtt_currto;
else {
r->rtt_nxtrto = 0;
gettimeofday(&r->time_stop, NULL);
diff = r->time_stop.tv_sec - r->time_start.tv_sec;
if (r->time_stop.tv_usec < r->time_start.tv_usec)
diff--;
r->rtt_rtt = (float)diff;
/* Use integer version instead */
err = r->rtt_rtt - r->rtt_srtt;
r->rtt_srtt += err/8;
if (err < 0.0)
err = -err;
r->rtt_rttdev += (err - r->rtt_rttdev) / 4;
}
}
int rtt_timeout(itemlink *r)
{
snapshot;
rtt_stop(r);
return (++r->rtt_nrexmt >= RTT_MAXNREXMT);
}
/*
* msgid, type, msg, \n
*/
#if 0
int L1_recv(struct Socket *self, char *buf, int len, int flags)
{
int size = sizeof(self->fromaddr);
snapshot;
size = recvfrom(self->handle, buf, len, flags,
(struct sockaddr *)&(self->fromaddr), &size);
buf[size] = NIL;
#ifdef DBUG
fprintf(stderr, "L1_recv: %d (%d) << %s",
self->handle, ntohs(self->fromaddr.sin_port), buf);
#endif
return size;
}
int L1_send(itemlink *self, char *msg, int len, int flags)
{
snapshot;
sendto(self->handle, msg, len, flags,
(struct sockaddr *)&self->addr, sizeof(struct sockaddr_in));
#ifdef DBUG
fprintf(stderr, "%d (%d) >> %s",
self->handle, ntohs(self->addr.sin_port), rawmsg);
#endif
}
#endif
/* --- ReadLink --------------------------------------------------- */
int ReadLink(char *inbuf)
{
int size = sizeof(fromaddr);
snapshot;
size = recvfrom(linkSocket, inbuf, MAXLINE, 0,
(struct sockaddr *)&fromaddr, &size);
inbuf[size] = NIL;
#ifdef DBUG
fprintf(stderr, "%d (%d) << %s", linkSocket, ntohs(fromaddr.sin_port), inbuf);
#endif
return size;
}
/* --- WriteLink -------------------------------------------------- */
#define UDPBUFFER 1024
void WriteLinkRaw(itemlink *r, char *rawmsg)
{
snapshot;
#ifdef DBUG
fprintf(stderr, "%d (%d) >> %s",
linkSocket, ntohs(r->addr.sin_port), rawmsg);
#endif
sendto(linkSocket, rawmsg, StrLength(rawmsg), 0,
(struct sockaddr *)&r->addr, sizeof(struct sockaddr_in));
}
void WriteLink(itemlink *r, int type, char *msg)
{
unsigned char buffer[UDPBUFFER];
snapshot;
StrFormatMax(buffer, sizeof(buffer), "%d %d %s\n", ++r->mymsgid, type, msg);
WriteLinkRaw(r, buffer);
}
void WriteLinkf(itemlink *r, int type, char *format, ...)
{
char buffer[MAXLINE];
va_list args;
snapshot;
va_start(args, format);
trio_vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
WriteLink(r, type, buffer);
}
/* --- SendLink --------------------------------------------------- */
/* If queue is empty send directly, else queue it. Don't remove
* from queue until ACK is received. The message on top of the
* list is always the one being sent, the rest are stalled to
* ensure casuality.
*/
void QueueLink(itemlink *r, int type, char *msg)
{
char buffer[BIGGERBUFFER];
itemmsg *m;
snapshot;
StrFormatMax(buffer, sizeof(buffer), "%d %lu %s\n", ++r->mymsgid, type, msg);
m = NewEntry(itemmsg);
if (m) {
m->msg = StrDuplicate(buffer);
/* If first in queue ship it now */
if (EmptyList(&r->RemoteHead)) {
rtt_newpack(r);
WriteLinkRaw(r, buffer);
#ifdef UNRELIABLE
if (Rnd() < 0.2) /* Send duplicate */
WriteLinkRaw(r, buffer);
#endif
r->expires = now + rtt_start(r);
}
InsertLast(&r->RemoteHead, m);
}
}
void SendLink(itemlink *r, int type, char *format, ...)
{
char buffer[BIGGERBUFFER];
va_list args;
snapshot;
va_start(args, format);
trio_vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
QueueLink(r, type, buffer);
}
void SendLinkAll(int type, char *format, ...)
{
char buffer[BIGGERBUFFER];
va_list args;
itemlink *r;
snapshot;
va_start(args, format);
trio_vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
for (r = First(linkHead); r; r = Next(r)) {
if (!r->new)
QueueLink(r, type, buffer);
}
}
void SendLinkBut(itemlink *rin, int type, char *format, ...)
{
char buffer[BIGGERBUFFER];
va_list args;
itemlink *r;
snapshot;
va_start(args, format);
trio_vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
for (r = First(linkHead); r; r = Next(r)) {
if (!r->new && (r != rin))
QueueLink(r, type, buffer);
}
}
/* --- CheckLinkQueue --------------------------------------------- */
/*
* Whenever a message is sent it must wait for acknowledgement.
* When messages are sent they are put in a queue. Each linked
* bot has its own queue. When an ack is received the next message
* from the queue is sent.
*/
void CheckLinkQueue(void)
{
itemlink *r;
itemmsg *m;
snapshot;
/* Called each second */
for (r = First(linkHead); r; r = Next(r)) {
m = First(&r->RemoteHead);
if (m) {
if (r->expires <= now) {
if (rtt_timeout(r)) {
/* Link is dead, remove it */
r = RemoveLink(r);
continue; /* for */
}
else {
/* Retransmit message */
WriteLinkRaw(r, m->msg);
r->expires = now + rtt_start(r);
}
}
}
}
}
void FlushLinkQueue(itemlink *r)
{
snapshot;
FlushList(&r->RemoteHead, FreeMessage);
}
/* --- LinkDequeue ------------------------------------------------ */
bool LinkDequeue(itemlink *r, unsigned long msgid)
{
unsigned long mid;
int type;
itemmsg *m;
snapshot;
/* Remove from top of queue */
if ((m = First(&r->RemoteHead)) &&
(2 == StrScan(m->msg, "%d %lu", &mid, &type))) {
/* Duplicates of previously acknowledged message may exist */
if (mid == msgid) {
/* Wait to remove the rejected link until it acknowledges */
if (IBCP_REJECT == type) {
RemoveLink(r);
return TRUE;
}
else {
DeleteEntry(&r->RemoteHead, m, FreeMessage);
m = First(&r->RemoteHead);
if (m) {
/* Ship the next */
rtt_newpack(r);
WriteLinkRaw(r, m->msg);
r->expires = now + rtt_start(r);
}
}
}
}
return FALSE;
}
/* ----------------------------------------------------------------
*
* Level 2 routines
*
* ---------------------------------------------------------------- */
/* --- LinkQuit --------------------------------------------------- */
/*
* The QUIT message surpasses the queue. We don't care about
* acknowledgement - if the recipient received it fine; if not
* the connection will timeout eventually.
*/
void LinkQuit(void)
{
itemlink *r;
snapshot;
/* Equivalent to SendLinkAll(IBCP_QUIT, "Bored"); */
for (r = First(linkHead); r; r = Next(r))
WriteLink(r, IBCP_QUIT, "Bored");
}
/* --- LinkHello -------------------------------------------------- */
itemlink *LinkHello(char *msg)
{
int ver, bottype;
ulong key;
itemlink *r = NULL;
char name[MINIBUFFER];
snapshot;
if (4 == StrScan(msg, "%d %d %s %lu", &ver, &bottype, name, &key))
{
/*
* We initiated the link. Now that we've got the info
* of the other end we add it and reply with our info.
*/
r = AddLink(name, NULL, ntohl(fromaddr.sin_addr.s_addr),
ntohs(fromaddr.sin_port));
if (r)
{
r->bottype = bottype;
r->protoversion = ver;
/* We asked to link so we assume that the other end is authenticated */
r->passed = TRUE;
SendLink(r, IBCP_HELLO_REPLY, "%d %d %s %lu",
IBCP_VERSION, IBCP_BOT_DANCER, nickname, key ^ linkvalue);
}
}
return r;
}
/* --- LinkHelloReply --------------------------------------------- */
void LinkHelloReply(itemlink *r, char *msg)
{
int ver, bottype;
ulong key;
char name[MINIBUFFER];
snapshot;
if (4 == StrScan(msg, "%d %d %s %lu", &ver, &bottype, name, &key)) {
if (r)
{
/*
* The other end initiated the link. We have already
* sent our info (in the HELLO message in ctcp.c) and
* now get the info of the initiater in return
*/
r->bottype = bottype;
r->protoversion = ver;
if (name)
r->name = StrDuplicate(name);
if ((r->linkvalue ^ key) == r->tmpvalue)
{
r->passed = TRUE;
#if 0
SendLinkBut(r, IBCP_AUTH, "%ld %d %d %d %s",
ntohl(fromaddr.sin_addr.s_addr), ntohs(fromaddr.sin_port),
ver, bottype, name);
r->new = FALSE;
#endif
SendLink(r, IBCP_ACCEPT, "");
#if 0
/* Tell newcomer about everybody else in net */
for (rr = First(linkHead); rr; rr = Next(rr))
{
if (rr != r)
SendLink(r, IBCP_AUTH_LIST, "%ld %d %d %d %s",
ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
rr->protoversion, rr->bottype, rr->name);
}
SendLink(r, IBCP_AUTH_END, "1");
/* Logf(LINK, "Added %s from %s %d", r->name,
ntohl(r->addr.sin_addr.s_addr), ntons(r->addr.sin_port));
*/
#endif
}
else
{
r->passed = FALSE;
SendLink(r, IBCP_REJECT, "No authentication");
/* Link will be removed in LinkDequeue() */
/* Logf(LINK, "Rejected..."); */
return;
}
}
}
}
/* --- LinkAuth --------------------------------------------------- */
void LinkAuth(itemlink *r, char *msg)
{
itemlink *rr;
long addr;
int port, ver, bottype;
char name[MINIBUFFER];
snapshot;
if (5 == StrScan(msg, "%ld %d %d %d %s", &addr, &port, &ver, &bottype, name))
{
rr = AddLink(name, NULL, addr, port);
if (rr)
{
rr->bottype = bottype;
rr->protoversion = ver;
rr->passed = TRUE;
rr->new = FALSE; /* Add immediately */
}
}
}
void LinkAuthList(itemlink *r, char *msg)
{
itemlink *rr;
long addr;
int port, ver, bottype;
char name[MINIBUFFER];
/* char naddr[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:256.256.256.256"]; */
snapshot;
if (5 == StrScan(msg, "%ld %d %d %d %s", &addr, &port, &ver, &bottype, name))
{
rr = AddLink(name, NULL, addr, port);
if (rr)
{
rr->bottype = bottype;
rr->protoversion = ver;
rr->passed = TRUE;
rr->new = TRUE;
}
}
}
void LinkAuthEnd(itemlink *r, char *msg)
{
itemlink *rr, *xrr;
snapshot;
if (*msg ^ '0') {
/* Return our cluster */
for (rr = First(linkHead); rr; rr = Next(rr)) {
if ( !rr->new && (rr != r) )
SendLink(r, IBCP_AUTH_LIST, "%ld %d %d %d %s",
ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
rr->protoversion, rr->bottype, rr->name);
}
SendLink(r, IBCP_AUTH_END, "0");
}
/* Commit newly received links */
for (rr = First(linkHead); rr; rr = Next(rr)) {
if (rr->new) {
for (xrr = rr; xrr; xrr = Next(xrr)) {
if ( !xrr->new )
SendLink(xrr, IBCP_AUTH, "%ld %d %d %d %s",
ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
rr->protoversion, rr->bottype, rr->name);
}
rr->new = FALSE;
}
}
}
/* --- LinkAccept ------------------------------------------------- */
void LinkAccept(itemlink *r)
{
snapshot;
SendLink(r, IBCP_SYNC, "%ld %ld", TIMEREQUEST, now);
}
/* --- LinkSync --------------------------------------------------- */
void LinkSync(itemlink *r, char *msg)
{
long ct, then;
snapshot;
if (2 == StrScan(msg, "%ld %ld", &ct, &then)) {
if (ct == TIMEREQUEST) {
/* It is a request for common time */
SendLink(r, IBCP_SYNC, "%ld %ld", now - commontime, then);
}
else {
/* T_common_ref = T_now - (T_remote + T_round-trip/2) */
long cnow = now;
commontime = cnow - ct - (cnow - then) / 2;
SendLink(r, IBCP_USERS_REQUEST, "%lu", LatestUserUpdate());
}
}
}
/* --- LinkNickname ----------------------------------------------- */
void LinkNickname(itemlink *r, char *msg)
{
snapshot;
if (r->name)
StrFree(r->name);
r->name = StrDuplicate(msg);
}
/* --- LinkMulticast ---------------------------------------------- */
void LinkMulticast(itemlink *r, char *msg)
{
char *text;
snapshot;
text = StrIndex(msg, ' ');
if (text) {
/*
* Multicasting from remote link is only forwarded
* to local listening clients
*/
MulticastLocalf(atoi(msg), "[%s]%s", r->name, text);
}
}
/* --- LinkSendUsers ---------------------------------------------- */
#if 0
char *LevelType(int level)
{
snapshot;
if (level < LEVELRECOG)
return "UNKNOWN";
else if (level < LEVELCHANOP)
return "RECOGNIZED";
else if (level < LEVELTRUST)
return "CHANOP";
else if (level < LEVELEXPERT)
return "TRUSTED";
else if (level < LEVELBOT)
return "EXPERT";
else if (level < LEVELOWNER)
return "MAINTAINER";
else
return "OWNER";
}
void LinkSendUser(itemlink *r, itemuser *u)
{
char buffer[BIGGERBUFFER];
itemlist *t;
snapshot;
StrFormatMax(buffer, sizeof(buffer), "%s", LevelType(u->level));
if (u->flags.autoop)
StrAppendMax(buffer, sizeof(buffer), ",AUTO");
if (u->flags.banprotect)
StrAppendMax(buffer, sizeof(buffer), ",PROTECT");
/* u->flags.linkbot is local data and not shared */
SendLink(r, IBCP_DATA_USER, "BEGIN: NICK:%s PASS:%s PRIV:%s CTIME:%ld MTIME:%ld",
u->nick, u->passwd, buffer, u->created - commontime, u->modified - commontime);
SendLink(r, IBCP_DATA_USER, "EMAIL:\"%s\" COMMENT:\"%s\"",
u->realname, u->comment);
buffer[0] = (char)0;
for (t = First(u->domainhead); t; t = Next(t))
/* What is this? */
StrFormatMax(buffer, sizeof(buffer), "%s%s,",
(NULL == StrIndex((char *)t->pointer, '!')) ? "*!" : "",
(char *)t->pointer);
SendLink(r, IBCP_DATA_USER, "HOST:%s END:", buffer);
}
void LinkSendUserlist(itemlink *r)
{
itemuser *u;
snapshot;
for (u = First(userHead); u; u = Next(u))
LinkSendUser(r, u);
}
/* --- LinkUpdateUser --------------------------------------------- */
void LinkUpdateUser(itemlink *r, char *msg)
{
static itemuser user;
char buffer[BIGGERBUFFER];
char strtype[MINIBUFFER];
char strargs[BIGBUFFER];
int index = 0;
snapshot;
#ifdef HAVE_N_IN_SCANF
StrScan(&msg[index], "%s %n", buffer, &index);
#else
StrScan(&msg[index], "%s", buffer);
index = StrLength(buffer);
#endif
StrScan(buffer, "[^:]*1[:][^\n]", strtype, strargs);
if (StrEqual(strtype, "BEGIN"))
memset(&user, NIL, sizeof(user));
else if (StrEqual(strtype, "NICK"))
user.nick = StrDuplicate(strargs);
else if (StrEqual(strtype, "PASS"))
user.passwd = StrDuplicate(strargs);
/* Remember that time is relative to commontime */
else if (StrEqual(strtype, "END")) {
/* Insert user entry */
#if 0
AddUser(&user, buffer); /* <--- Must be UpdateUser() not AddUser() */
StrFormatMax(buffer, sizeof(buffer), "%s 0 %d %d 0", user.passwd, NULL,
user.modified, user.created);
AddNewData(&user, buffer);
AddDomain(&user, whatever);
#endif
if (user.nick)
StrFree(user.nick);
if (user.passwd)
StrFree(user.passwd);
}
}
#endif
/* --- LinkUsers -------------------------------------------------- */
char *SetUserFlags(uFlags *);
void LinkUsersRequest(itemlink *r, char *msg)
{
char buffer[3*BIGBUFFER];
itemuser *u;
itemlist *l;
time_t t;
snapshot;
if (1 == StrScan(msg, "%lu", &t) ) {
printf("update since %lu\n", t);
/* Ship all entries that are newer than 't' */
for (u = First(userHead); u; u = Next(u)) {
if (u->modified > t - 400) { /* !!! remove - 400 !!! */
/* Should send the same data as UserSave() */
SendLink(r, IBCP_USERS_LIST, "%s", WriteUserHead(buffer, sizeof(buffer), u));
for (l = First(u->domainhead); l; l = Next(l))
SendLink(r, IBCP_USERS_LIST, "!%s\n", (char *)l->pointer);
}
}
SendLink(r, IBCP_USERS_END, "");
}
}
void LinkUsersUpdate(itemlink *r, char *msg)
{
snapshot;
printf("Should do the update here\n");
}
void LinkUsersList(itemlink *r, char *msg)
{
snapshot;
LinkUsersUpdate(r, msg);
/* Forward to rest of local cluster */
SendLinkBut(r, IBCP_USERS_UPDATE, msg);
}
void LinkUsersEnd(itemlink *r, char *msg)
{
snapshot;
/* SendLink(r, IBCP_AUTH_REQUEST, "");*/
printf("initiate AUTH... when installed\n");
}
/* --- LinkRemote ------------------------------------------------- */
void LinkRemoteCmd(itemlink *r, char *msg)
{
char name[MINIBUFFER];
char cmd[MIDBUFFER];
char buffer[BIGBUFFER] = "";
snapshot;
if (2 <= StrScan(msg, "%s %s %[^\n]", name, cmd, buffer)) {
printf("remote '%s %s' from %s", cmd, buffer[0] ? buffer : "", name);
}
}
void LinkRemoteAnswer(itemlink *r, char *msg)
{
extern bool chat;
extern itemclient *client;
char name[MINIBUFFER];
char buffer[BIGBUFFER];
bool chit;
itemclient *klient;
snapshot;
if (2 == StrScan(msg, "%"MINIBUFFERTXT"s %"BIGBUFFERTXT"[^\n]", name, buffer)) {
printf("remote answer '%s' to %s", buffer, name);
chit = chat;
klient = client;
chat = (client = FindClientByNick(name)) ? TRUE : FALSE;
Send(name, buffer);
chat = chit;
client = klient;
}
}
/* --- LinkParse -------------------------------------------------- */
#define IDBACKTRACK 1000u
bool IsDuplicate(unsigned long this, unsigned long last)
{
snapshot;
/* This strange looking code works because we are dealing
* with unsigned arithmetic. Hopefully the compiler doesn't
* choose to optimize it away.
*/
if (this <= last)
return (this - IDBACKTRACK <= last - IDBACKTRACK);
return FALSE;
}
void LinkParse(char *line)
{
itemlink *r;
char buffer[BIGBUFFER];
char out[BIGBUFFER];
char *msg;
int type, rc;
unsigned long msgid;
snapshot;
#if 1
if (2 <= StrScan(line, "%d %d %[^\n]", &msgid, &type, buffer)) {
msg = buffer;
r = FindLink(fromaddr.sin_addr.s_addr, fromaddr.sin_port);
if (NULL == r) {
if (type == IBCP_HELLO) {
/* We will only accept a HELLO from unknown destinations. */
/* And only if it contains data */
if (StrLength(msg) > 0) {
r = LinkHello(msg);
if (r) {
/* Acknowledge directly */
StrFormatMax(out, sizeof(out), "%d %d\n", msgid, IBCP_ACK);
WriteLinkRaw(r, out);
r->yourmsgid = msgid;
}
}
}
if (NULL == r)
return;
}
/* r is always set at this point */
if (IBCP_ACK == type) {
/* We got an acknowledgement. Dequeue message and send next */
LinkDequeue(r, msgid);
/* Don't acknowledge acknowledgements... bad karma */
return;
}
if (IsDuplicate(msgid, r->yourmsgid))
/* Ignore duplicates */
return;
rtt_stop(r);
if (StrLength(msg) > 0) {
/* If zero it's only an ack */
#if 1
#ifdef UNRELIABLE
if (Rnd() > 0.2) /* Don't acknowledge */
#endif
StrFormatMax(out, sizeof(out), "%d %d\n", msgid, IBCP_ACK);
WriteLinkRaw(r, out); /* &fromaddr */
/* bool wantpiggy; ulong piggymsg; */
#endif
/*
* Check if from authenticated bot. There are two ways to become
* authenticated: either by authentication at connect-time, or
* through validation by another bot.
*/
if (r->passed)
{
switch (type)
{
case IBCP_QUIT: /* Link that decided to quit */
RemoveLink(r);
r = NULL;
break;
case IBCP_ACCEPT:
LinkAccept(r);
break;
case IBCP_REJECT: /* I was rejected by r */
RemoveLink(r);
r = NULL;
break;
case IBCP_SYNC: /* Establish or request common time */
LinkSync(r, msg);
break;
case IBCP_AUTH:
LinkAuth(r, msg);
break;
case IBCP_AUTH_LIST:
/* Not broadcasted until AUTH_END is received */
LinkAuthList(r, msg);
break;
case IBCP_AUTH_END:
LinkAuthEnd(r, msg);
break;
/* Handle userlist */
case IBCP_USERS_REQUEST:
LinkUsersRequest(r, msg);
break;
case IBCP_USERS_UPDATE:
LinkUsersUpdate(r, msg);
break;
case IBCP_USERS_LIST:
LinkUsersList(r, msg);
break;
case IBCP_USERS_END:
LinkUsersEnd(r, msg);
break;
case IBCP_REMOTE_CMD:
LinkRemoteCmd(r, msg);
break;
case IBCP_REMOTE_ANSWER:
LinkRemoteAnswer(r, msg);
break;
case IBCP_NICKNAME:
LinkNickname(r, msg);
break;
case IBCP_MULTICAST:
LinkMulticast(r, msg);
break;
default:
break;
}
}
else if (type == IBCP_HELLO_REPLY)
{
/*
* HELLO_REPLY is part of the authentication scheme and
* therefor we will only accept it if the link isn't
* authenticated yet.
*/
LinkHelloReply(r, msg);
}
r->yourmsgid = msgid;
}
r->lasttime = now;
}
#else
unsigned long msgid;
int type;
/* Skip escape code if present */
if (*line == IBCP_ESC) line++;
msg = buffer;
if ( 2 <= StrScan(line, "%d %lu %[^\n]", &type, &msgid, msg) ) {
r = FindLink(fromaddr.sin_addr.s_addr, fromaddr.sin_port);
if (type == IBCP_ACK) {
/* We got an acknowledgement. Dequeue message and send next */
if (r)
LinkDequeue(r, msgid);
/* Don't acknowledge acknowledgements... bad karma */
return;
}
/* Ignore duplicates */
if (r && IsDuplicate(msgid, r->yourmsgid)) {
printf("Ignored\n");
return;
}
#ifdef UNRELIABLE
if (Rnd() > 0.2) /* Don't acknowledge */
#endif
WriteLink(&fromaddr, IBCP_ACK, "");
if (type == IBCP_HELLO) {
LinkHello(r, msg);
return;
} else if (type == IBCP_HELLO_REPLY) {
LinkHelloReply(r, msg);
return;
}
if (r) {
rtt_stop(r);
/*
* Check if from authenticated bot. There are two ways to become
* authenticated: either by authentication at connect-time, or
* through validation by another bot
*/
/*if (r->passed)*/ {
switch (type) {
case IBCP_QUIT: /* Link that decided to quit */
RemoveLink(r);
break;
case IBCP_ACCEPT:
LinkAccept(r);
break;
case IBCP_REJECT: /* I was rejected by r */
RemoveLink(r);
break;
case IBCP_AUTH:
LinkAuth(r, msg);
break;
case IBCP_AUTH_LIST:
/* Not passed until AUTH_END is received */
LinkAuthList(r, msg);
break;
case IBCP_AUTH_END:
LinkAuthEnd(r, msg);
break;
case IBCP_SYNC: /* Establish or request common time */
LinkSync(r, msg);
break;
/* Handle userlist */
case IBCP_USERS_REQUEST:
LinkUsersRequest(r, msg);
break;
case IBCP_USERS_UPDATE:
LinkUsersUpdate(r, msg);
break;
case IBCP_USERS_LIST:
LinkUsersList(r, msg);
break;
case IBCP_USERS_END:
LinkUsersEnd(r, msg);
break;
case IBCP_REMOTE_CMD:
LinkRemoteCmd(r, msg);
break;
case IBCP_REMOTE_ANSWER:
LinkRemoteAnswer(r, msg);
break;
case IBCP_NICKNAME:
LinkNickname(r, msg);
break;
case IBCP_MULTICAST:
LinkMulticast(r, msg);
break;
default:
break;
}
}
r->yourmsgid = msgid;
r->lasttime = now;
}
}
#endif
}
syntax highlighted by Code2HTML, v. 0.9.1