/* tuved - Socket Server (c) 2007 Christopher Olsen $Id: socket.c,v 1.30 2008/02/05 01:27:29 reddawg Exp $ */ #include <stdarg.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #include <stdio.h> #include <fcntl.h> #include "tuved.h" myConnections_t *connections = 0x0; int listenerFD = 0x0; int highSock = 0x0; int sStartListener() { int optVal = 0x1; struct sockaddr_in myAddr; // my address information if ((listenerFD = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } if (setsockopt(listenerFD, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } myAddr.sin_family = AF_INET; // host byte order myAddr.sin_port = htons(MYPORT); // short, network byte order myAddr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(myAddr.sin_zero, '\0', sizeof myAddr.sin_zero); if (bind(listenerFD, (struct sockaddr *)&myAddr, sizeof(struct sockaddr)) == -1) { perror("bind"); exit(1); } if (listen(listenerFD, BACKLOG) == -1) { perror("listen"); exit(1); } fcntl(listenerFD, F_SETFL, fcntl(listenerFD, F_GETFL, 0) | O_NONBLOCK); sAddConnection(listenerFD,"127.0.0.1"); writeLog(2,"Listener FD: [%i]\n",listenerFD); return(0x0); } ssize_t sReadSocket(int socketFD,void *buffer,size_t length) { ssize_t recLen = 0x0; recLen = read(socketFD,buffer,length); if (recLen <= 2) recLen = 0x0; return(recLen); } int sGetConnection() { int newFD = 0x0; // New Socket; socklen_t sin_size; struct sockaddr_in remoteAddr; struct hostent *hp; sin_size = sizeof(struct sockaddr_in); if ((newFD = accept(listenerFD, (struct sockaddr *)&remoteAddr, &sin_size)) == -1) { perror("accept"); } /* Add Socket */ hp = gethostbyaddr((char *)&remoteAddr.sin_addr,sizeof(remoteAddr.sin_addr),AF_INET); sAddConnection(newFD,(hp ? hp->h_name : inet_ntoa(remoteAddr.sin_addr))); /* Return */ return(0x0); } int sAddConnection(int socketFD,char *host) { myConnections_t *tmpConnection = 0x0; writeLog(2,"Adding Socket: [%i]\n",socketFD); userCount++; if (connections == 0x0) { connections = (myConnections_t *)calloc(1,sizeof(myConnections_t)); connections->prev = 0x0; connections->next = 0x0; connections->fd = socketFD; connections->signedOn = time(NULL); sprintf(connections->host, "%s", host); } else { tmpConnection = (myConnections_t *)calloc(1,sizeof(myConnections_t)); //memset(tmpConnection,0x0,sizeof(myConnections_t)); tmpConnection->fd = socketFD; tmpConnection->prev = connections; tmpConnection->next = connections->next; tmpConnection->signedOn = time(NULL); sprintf(tmpConnection->host, "%s", host); if (connections->next != 0x0) connections->next->prev = tmpConnection; connections->next = tmpConnection; } writeLog(2,"Socket Added\n"); return(0x0); } myConnections_t *sFindConnection(int fd) { myConnections_t *tmpConnection = 0x0; for (tmpConnection = connections->next;tmpConnection != 0x0;tmpConnection = tmpConnection->next) { if (tmpConnection->fd == fd) return(tmpConnection); } return(0x0); } int sCleanConnections() { myConnections_t *tmpConnection = 0x0; myConnections_t *delConnection = 0x0; char output[256]; for (tmpConnection = connections->next;tmpConnection != 0x0;tmpConnection = tmpConnection->next) { if (tmpConnection->userInfo.status == -1) { // Set temporary pointer to connection so we can free it later delConnection = tmpConnection; // Hard close the socket so it doesn't linger close(tmpConnection->fd); writeLog(2,"Removed User: [%s]\n",tmpConnection->userInfo.username); // If connection has a previous pointer which it always should adjust it's next pointer to match current next if (tmpConnection->prev != 0x0) tmpConnection->prev->next = tmpConnection->next; // If connection has a next pointer which it may not adjust it to point to match our current previous if (tmpConnection->next != 0x0) tmpConnection->next->prev = tmpConnection->prev; // Adjust tmpConnection to match our previous pointer which should always happen if (tmpConnection->prev != 0x0) tmpConnection = tmpConnection->prev; else tmpConnection = tmpConnection->next; userCount--; if (delConnection->userInfo.ident == 2) { sprintf(output,"DELETE FROM active WHERE userid = %lld",delConnection->userInfo.uid); dbQuery(output,0); } //Free the bad connection free(delConnection); writeLog(2,"Remove Completed\n"); } } return(0x0); } int sRemoveConnection(int socketFD) { myConnections_t *tmpConnection = 0x0; char output[256]; writeLog(2,"Removing Socket: %i\n",socketFD); for (tmpConnection = connections->next;tmpConnection != 0x0;tmpConnection = tmpConnection->next) { if (tmpConnection->fd == socketFD) { tmpConnection->prev->next = tmpConnection->next; if (tmpConnection->next != 0x0) tmpConnection->next->prev = tmpConnection->prev; writeLog(2,"Removed Socket: [%i]\n",tmpConnection->fd); userCount--; if (tmpConnection->userInfo.ident == 2) { sprintf(output,"DELETE FROM active WHERE userid = %lld",tmpConnection->userInfo.uid); dbQuery(output,0); } free(tmpConnection); return(0x0); } } writeLog(2,"Error: No Socket Removed\n"); return(-1); } int sGetConnections(fd_set *readset) { int retVal = 0; myConnections_t *tmpConnection = 0x0; FD_ZERO(readset); // FD_SET(listenerFD,readset); highSock = 0; if (connections != 0x0) { for (tmpConnection = connections;tmpConnection != 0x0;tmpConnection = tmpConnection->next) { FD_SET(tmpConnection->fd,readset); if (tmpConnection->fd > highSock) highSock = tmpConnection->fd; } retVal = 1; } return(retVal); } /************************************ * * * Send ping broadcast to all users * * * ************************************/ int sSendPing(time_t ping) { myConnections_t *tmpConnection = 0x0; char sPing[32]; for (tmpConnection = connections->next;tmpConnection != 0x0;tmpConnection = tmpConnection->next) { if (tmpConnection->userInfo.pfailed < MAX_PING) { if (tmpConnection->userInfo.pong < ping) { tmpConnection->userInfo.pfailed++; tmpConnection->userInfo.pong = ping; if (tmpConnection->userInfo.ident >= 0x1) { sprintf(sPing,"PING %li\r\n", time(NULL)); send(tmpConnection->fd,sPing,strlen(sPing),MSG_NOSIGNAL); } } } else { send(tmpConnection->fd,"TIMEOUT\r\n",sizeof("TIMEOUT\r\n"),MSG_NOSIGNAL); tuveDelUserChans(tmpConnection,"TIMEOUT"); tmpConnection->userInfo.status = -1; } } return(0x0); } /* End sSendPing() */ int sSendData(myConnections_t *con,char const * __restrict fmt, ...) { int len = 0; char data[2048]; va_list ap; if (con == 0x0) { writeLog(1,"Error Sending Data"); return(0x1); } else if (con->userInfo.status == -1) { writeLog(3,"User: %s Socket Not Avail\n",con->userInfo.username); return(0x1); } va_start(ap,fmt); len = vsnprintf(data,2046,fmt,ap); va_end(ap); //data[len++] = '\r'; data[len++] = '\n'; send(con->fd,data,len,MSG_NOSIGNAL); return(0x0); } int sProcessConnections(fd_set *readset) { myConnections_t *tmpConnection = 0x0; for (tmpConnection = connections;tmpConnection != 0x0;tmpConnection = tmpConnection->next) { if (FD_ISSET(tmpConnection->fd,readset) != 0x0) { if (tmpConnection->fd == listenerFD) { sGetConnection(); writeLog(2,"Listen Socket Was Ready?\n"); } else { if (tuveGetData(tmpConnection) == -1) { close(tmpConnection->fd); tuveDelUserChans(tmpConnection,"SIG PIPE"); sRemoveConnection(tmpConnection->fd); } } } } return(0x0); }