Newer
Older
tuved / src / socket.c
@Charlie Root Charlie Root on 15 Apr 2019 8 KB Sync
/*
  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);
  }