// //sockserv.c // //Sock server. Lists, polls and maintains all sockets. // // //-UserX 2001/11/11 #include #ifdef __FreeBSD__ #include #endif #include "net/sockserv.h" #include "base/array.h" #include "base/dblock.h" //#include "core.h" #include "net/noderef.h" #include "net/nodeserv.h" //#include "protocol.h" #include "net/protocfg.h" #include "base/logger.h" #include "base/str.h" #include "misc/global.h" #include "ui/ui.h" //typedef struct sd_set { // int size; // SOCKET socks[0]; //} DataBlock *sdRead = NULL; DataBlock *sdWrite = NULL; #define SDREAD ((fd_set *)sdRead->data) #define SDWRITE ((fd_set *)sdWrite->data) SockArrayHandle *SocksListening = NULL; SockArrayHandle *SocksOpen = NULL; void (*addinsock)(SockHandle *, int *) = NULL; SockHandle *blanksockhandleptr = NULL; void sockservInit(void (*addfunc)(SockHandle *, int *)) { //todo: verify functions passed to arrayMake if(SocksListening == NULL) { SocksListening = (SockArrayHandle *) arrayMake(sizeof(SockHandle *), 0, &blanksockhandleptr, (ArrayFuncCreate) sockMakeAt, (ArrayFuncDelete) sockFree); } if(SocksOpen == NULL) { SocksOpen = (SockArrayHandle *) arrayMake(sizeof(SockHandle *), 0, &blanksockhandleptr, (ArrayFuncCreate) sockMakeAt, (ArrayFuncDelete) sockFree); } if(addfunc == NULL) { LOGERROR("sockservInit: NULL passed for addfunc."); abort(); } addinsock = addfunc; } // void sockservPoll(int shortdelay){ #ifdef _WINDOZE_ struct timeval tv = {0, 200000}; //should increase responsiveness of tray control #else struct timeval tv = {1, 0}; #endif SOCKET maxpoll = 0; int i; //a little inefficient in terms of space used but should work (hopefully) work on any platform. if(SocksListening == NULL || SocksOpen == NULL) { return; } if(nextdhdelay >= 0) { //drop wait time down to 1/10th of a second after dh computations tv.tv_sec = 0; tv.tv_usec = 100000; } if(shortdelay != 0) { tv.tv_sec = 0; tv.tv_usec = 1000; } sdRead = dblockResize(sdRead, sizeof(fd_set) + sizeof(SOCKET) * (SocksListening->size + SocksOpen->size)); sdWrite = dblockResize(sdWrite, sizeof(fd_set) + sizeof(SOCKET) * SocksOpen->size); FD_ZERO(SDREAD); FD_ZERO(SDWRITE); for(i = 0; i < SocksOpen->size; i++) { if(SocksOpen->data[i] != NULL) { switch(SocksOpen->data[i]->status) { case SOCK_STATUS_OK: case SOCK_STATUS_OPENING: if(SocksOpen->data[i]->Socket != SOCKET_ERROR) { FD_SET(SocksOpen->data[i]->Socket, SDREAD); if(SocksOpen->data[i]->IOPipe.outBuffer->size != 0) { FD_SET(SocksOpen->data[i]->Socket, SDWRITE); } if(SocksOpen->data[i]->Socket > maxpoll) { maxpoll = SocksOpen->data[i]->Socket; } } break; } } } for(i = 0; i < SocksListening->size; i++) { if(SocksListening->data[i] != NULL) { switch(SocksListening->data[i]->status) { case SOCK_STATUS_LISTENING: if(SocksListening->data[i]->Socket != SOCKET_ERROR) { FD_SET(SocksListening->data[i]->Socket, SDREAD); if(SocksListening->data[i]->Socket > maxpoll) { maxpoll = SocksListening->data[i]->Socket; } } break; } } } maxpoll++; select(maxpoll, ((fd_set *)&sdRead->data), ((fd_set *)&sdWrite->data), NULL, &tv); } void sockservAddSock(SockArrayHandle *sah, SockHandle *sh) { int i; for(i = 0; i < sah->size; i++) { if(sah->data[i] == NULL) { sah->data[i] = sh; return; } } arrayAddElements((ArrayHandle *)sah, 1); sah->data[sah->size - 1] = sh; } void sockservAddOpen(SockHandle *sh) { sockservAddSock(SocksOpen, sh); } void sockservAddListening(SockHandle *sh) { sockservAddSock(SocksListening, sh); } void sockservProcessOpen(void) { int i; for(i = 0; i < SocksOpen->size; i ++) { if(SocksOpen->data[i] != NULL) { if(SocksOpen->data[i]->Socket != SOCKET_ERROR) { if(FD_ISSET(SocksOpen->data[i]->Socket, SDREAD)) { sockRead(SocksOpen->data[i]); } if(FD_ISSET(SocksOpen->data[i]->Socket, SDWRITE)) { sockWrite(SocksOpen->data[i]); } } switch(SocksOpen->data[i]->status) { case SOCK_STATUS_CLOSING: case SOCK_STATUS_CLOSED: LOGDEBUG (stringJoin("sockservProcessOpen:Close:", ptrToString(SocksOpen->data[i]))); sockClose(SocksOpen->data[i]); sockFree(SocksOpen->data[i]); SocksOpen->data[i] = NULL; break; } } } } void sockservProcessListening(void) { SockHandle *sh; int i; int result; for(i = 0; i < SocksListening->size; i ++) { if(SocksListening->data[i] != NULL) { if(FD_ISSET(SocksListening->data[i]->Socket, SDREAD)) { sh = sockAccept(SocksListening->data[i]); if(sh != NULL) { addinsock(sh, &result); if(result == 0) { sockservAddOpen(sh); } } } } } } void sockservProcess(int shortdelay) { if(SocksListening == NULL || SocksOpen == NULL) { return; } sockservPoll(shortdelay); sockservProcessOpen(); sockservProcessListening(); } NodeRef *sockservPickNode(void) { NodeRef *nr = nodeservPickNode(); int i; for(i = 0; i < nodeservTotalNodeRefs(); i++, nr = nodeservPickNextNode(nr)) { if(ignoreself == 0 || stringCaseCompare(nr->HostName, hostname) != 0) { if(protocolFilter(nr->Protocol) != 0) { return nr; } } } noderefFree(nr); return NULL; } //connect to random node //todo: change when noderef info improves SockHandle *sockservConnect(void) { SockHandle *sh; NodeRef *nr = NULL; // int i; int er; nr = sockservPickNode(); if(nr == NULL) { return NULL; } sh = sockMake(); //trying a new node on a failed connection is actually a bad idea. //If the IRC server goes down it will keep looping around nodes until //they crash/choke. //Once the proper network is up (that is no IRC server) trying again //will be handled elsewhere. // for(i = 0; i < totalNodes(); i++, nr = pickNextNode(nr)) { // for(i = 0; i <= retries; i++, noderefFree(nr), nr = sockservPickNode()) { sockInit(sh); er = sockSetNodeRef(sh, nr); if(er == SOCK_ERR_NONE) { er = sockOpen(sh); // if(er == SOCK_ERR_NONE) { // break; // } } // } noderefFree(nr); if(er != SOCK_ERR_NONE) { sockFree(sh); return NULL; } sockservAddOpen(sh); return sh; } SockHandle *sockservListen(NodeRef *nr) { SockHandle *sh; int er; if(nr->PortNum == 0) { return NULL; } sh = sockMake(); if(sh == NULL) { return(NULL); } er = sockSetLocalNodeRef(sh, nr); if(er != SOCK_ERR_NONE) { sockFree(sh); return NULL; } er = sockListen(sh); if(er != SOCK_ERR_NONE) { sockClose(sh); sockFree(sh); return NULL; } sockservAddListening(sh); return sh; } int sockservStartListen(void) { int i; int failures = 0; //sockservInit(); if(SocksListening == NULL) { return -1; } //close any open listening sockets for(i = 0; i < SocksListening->size; i++) { if(SocksListening->data[i] != NULL) { LOGDEBUG(stringJoinMany( "sockservStartListen:Close:(", intToString(i), ")", ptrToString(SocksListening->data[i]), NULL)); sockClose(SocksListening->data[i]); sockFree(SocksListening->data[i]); SocksListening->data[i] = NULL; } } for(i = 0; i < LNRA->size; i++) { LOGDEBUG(stringJoinMany( "sockservStartListen:Listen:(", intToString(i), ")", ptrToString(&LNRA->data[i]), NULL)); if(!sockservListen(&LNRA->data[i])) { #ifdef _WINDOZE_ char *s = stringJoinMany(_("Unable to bind listening connection to socket: "), intToString(LNRA->data[i].PortNum), NULL); uiDialog(_("Unable to bind socket"), s, UIDIALOG_OK, UIDIALOG_OK); stringFree(s); #endif failures++; } } return failures; }