/* * Copyright (C) 1999 Peter Amstutz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of *the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ #include #include "../config.h" #ifdef HAVE_SYS_SELECT_H # include #else # include # include #endif #include #include #include #include #include #include #include #include "tcpcore.h" #include "relay.h" #include "log.h" int rl_idcounter = 0; void rlSetDisconnectFunc(Relay_rl * rl, void (*handler) (Relay_rl *, int)) { rl->logofffunc = handler; } void rlRegisterHandler(Relay_rl * rl, char *pkttype, void (*handler) (Relay_rl *, int, char *, int)) { if(rl->hbegin == NULL) { rl->hbegin = (Handlerlist_rl *) malloc(sizeof(Handlerlist_rl)); rl->hend = rl->hbegin; rl->hend->prev = NULL; } else { rl->hend->next = (Handlerlist_rl *) malloc(sizeof(Handlerlist_rl)); rl->hend->next->prev = rl->hend; rl->hend = rl->hend->next; } rl->hend->next = NULL; rl->hend->type[0] = pkttype[0]; rl->hend->type[1] = pkttype[1]; rl->hend->func = handler; } void rlRemoveHandler(Relay_rl * rl, char *pkttype) { register Handlerlist_rl *hcur; for(hcur = rl->hbegin; hcur; hcur = hcur->next) { if(pkttype[0] == hcur->type[0] && pkttype[1] == hcur->type[1]) { if(hcur->prev) hcur->prev->next = hcur->next; if(hcur->next) hcur->next->prev = hcur->prev; if(rl->hbegin == hcur) rl->hbegin = hcur->next; if(rl->hend == hcur) rl->hend = hcur->prev; free(hcur); } } } void rlDisconnect(Relay_rl *rl, int id) { register Connectlist_rl* ccur; for(ccur=rl->cbegin; ccur; ccur=ccur->next) { if(ccur->id == id) { if(rl->cbegin==ccur) rl->cbegin=ccur->next; if(rl->cend==ccur) rl->cend=ccur->prev; if(ccur->prev) ccur->prev->next=ccur->next; if(ccur->next) ccur->next->prev=ccur->prev; rl->logofffunc(rl, ccur->id); close(ccur->socket); free(ccur); break; } } } Relay_rl *rlInit(short unsigned int port) { Relay_rl *rl = (Relay_rl *) malloc(sizeof(Relay_rl)); rl->hbegin = NULL; rl->hend = NULL; rl->cbegin = NULL; rl->cend = NULL; if(port != 0xffff) { rl->listensock = tcpListen(port); if(rl->listensock < 0) { free(rl); return NULL; } } else { rl->listensock = -1; return rl; } return rl; } int rlAddConnection(Relay_rl * rl, int sock) { if(rl->cbegin == NULL) { rl->cbegin = (Connectlist_rl *) malloc(sizeof(Connectlist_rl)); rl->cend = rl->cbegin; rl->cend->prev = NULL;; } else { rl->cend->next = (Connectlist_rl *) malloc(sizeof(Connectlist_rl)); rl->cend->next->prev = rl->cend; rl->cend = rl->cend->next; } rl->cend->next = NULL; rl->cend->socket = sock; rl->cend->id = ++rl_idcounter; rl->cend->buffstate = 0; rl->cend->qstart = 0; rl->cend->qend = 0; return rl->cend->id; } void rlMain(Relay_rl * rl, struct timeval *tv) { Connectlist_rl *ccur, *nxt; Handlerlist_rl *hcur; fd_set rfds; int max = 0, pktsize; short int sizeinfo; char input[32768]; int rt; unsigned i; FD_ZERO(&rfds); /* Watch stdin */ FD_SET(fileno(stdin), &rfds); if(rl->listensock>-1) { FD_SET(rl->listensock, &rfds); max=rl->listensock; } for(ccur=rl->cbegin; ccur; ccur=ccur->next) { FD_SET(ccur->socket, &rfds); if(ccur->socket>max) max=ccur->socket; } if((rt=select(max+1, &rfds, NULL, NULL, tv))) { if(rt==-1) { if(errno==EINTR) return; else { logPrintf(INTERESTING, "Error while waiting for data: %s\n", strerror(errno)); exit(-1); } } if(rl->listensock>-1 && FD_ISSET(rl->listensock, &rfds)) { rlAddConnection(rl, tcpGetNewConnection(rl->listensock)); } for(ccur=rl->cbegin; ccur; ccur=nxt) { nxt = ccur->next; if(FD_ISSET(ccur->socket, &rfds)) { pktsize=recv(ccur->socket, input, FREEQSPACE(ccur->qstart, ccur->qend, sizeof(ccur->buffer)), 0); if(pktsize <= 0) { if(pktsize == -1) { if(errno == EINTR) return; logPrintf(CRITICAL, "Error while receiving data from socket %i: %s\n", ccur->socket, strerror(errno)); } if(rl->cbegin==ccur) rl->cbegin=ccur->next; if(rl->cend==ccur) rl->cend=ccur->prev; if(ccur->prev) ccur->prev->next=ccur->next; if(ccur->next) ccur->next->prev=ccur->prev; rl->logofffunc(rl, ccur->id); nxt = ccur->next; free(ccur); continue; } for(i=0;ibuffer[ccur->qend++]=input[i]; ccur->qend%=sizeof(ccur->buffer); } nextpkt: if(USEDQSPACE(ccur->qstart, ccur->qend, sizeof(ccur->buffer))>=2) { memcpy(&sizeinfo, &(ccur->buffer[ccur->qstart]), 2); sizeinfo=ntohs(sizeinfo); if(USEDQSPACE(ccur->qstart, ccur->qend, sizeof(ccur->buffer)) - 2 >= sizeinfo) { ccur->qstart+=2; for(i=0;ibuffer[ccur->qstart++]; ccur->qstart%=sizeof(ccur->buffer); } logPrintf(SPAM, "Received packet %c%c of length %i\n", input[0], input[1], sizeinfo); for(hcur=rl->hbegin; hcur; hcur=hcur->next) { if(hcur->type[0]==input[0] && hcur->type[1]==input[1]) { hcur->func(rl, ccur->id, input, sizeinfo); } } } else goto bail; goto nextpkt; bail: ; } } } } } void rlSend(Relay_rl * rl, int who, void *message, int len) { register Connectlist_rl *ccur; for(ccur = rl->cbegin; ccur; ccur = ccur->next) { if(ccur->id == who) { tcpSendPacket(ccur->socket, message, len); break; } } } void rlSendTyped(Relay_rl * rl, int who, char *type, void *message, int len) { register Connectlist_rl *ccur; for(ccur = rl->cbegin; ccur; ccur = ccur->next) { if(ccur->id == who) { tcpSendTypedPacket(ccur->socket, type, message, len); break; } } } /* who is either an array of id's to send to of length who[0], or who[0] is zero and it is sent to all know id's */ void rlBroadcast(Relay_rl * rl, int *who, void *message, int len) { register Connectlist_rl *ccur; if(who[0]) { register unsigned i; for(i = 1; i <= who[0]; i++) { for(ccur = rl->cbegin; ccur; ccur = ccur->next) { if(ccur->id == who[i]) { tcpSendPacket(ccur->socket, message, len); } } } } else { for(ccur = rl->cbegin; ccur; ccur = ccur->next) { tcpSendPacket(ccur->socket, message, len); } } } void rlBroadcastTyped(Relay_rl * rl, int *who, char *type, void *message, int len) { register Connectlist_rl *ccur; if(who[0]) { register unsigned i; for(i = 1; i <= who[0]; i++) { for(ccur = rl->cbegin; ccur; ccur = ccur->next) { if(ccur->id == who[i]) { tcpSendTypedPacket(ccur->socket, type, message, len); } } } } else { for(ccur = rl->cbegin; ccur; ccur = ccur->next) { tcpSendTypedPacket(ccur->socket, type, message, len); } } }