//
//sockserv.c
//
//Sock server. Lists, polls and maintains all sockets.
//
//
//-UserX 2001/11/11
#include <stdlib.h>
#ifdef __FreeBSD__
#include <string.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1