Skip to content
Snippets Groups Projects
server.cpp 3.28 KiB
Newer Older
#include "server.hpp"
#include <sys/socket.h>

Server::Server() { setup(DEFAULT_PORT); }

Server::Server(const int &port) { setup(port); }

Server::~Server() { close(mastersocket_fd); }

void Server::setup(int port) {
  mastersocket_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (mastersocket_fd < 0) {
    perror("Error creating socket");
  }
  FD_ZERO(&masterfds);
  FD_ZERO(&tmpfds);

  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htons(INADDR_ANY);
  server_addr.sin_port = htons(port);

  bzero(input_buffer, INPUT_BUFFER_SIZE); // no random data in input buffer
}

void Server::initializeSocket() {
  int opt_value = 1;
  int rc = setsockopt(mastersocket_fd, SOL_SOCKET, SO_REUSEADDR,
                      (char *)&opt_value, sizeof(int));
  if (rc < 0) {
    perror("setsocketopt() failed");
    stop();
  }
}

void Server::bindSocket() {
  int rc = bind(mastersocket_fd, (struct sockaddr *)&server_addr,
                sizeof(server_addr));
  if (rc < 0) {
    perror("bind() failed");
  }
  FD_SET(mastersocket_fd, &masterfds);
  maxfd = mastersocket_fd;
}

void Server::startListen() {
  int rc = listen(mastersocket_fd, 3);
  if (rc < 0) {
    perror("listen() failed");
  }
}

void Server::stop() { close(mastersocket_fd); }

void Server::handleNewConnection() {
  socklen_t addrLen = sizeof(client_addr);
  tempsocket_fd =
      accept(mastersocket_fd, (struct sockaddr *)&client_addr, &addrLen);
  if (tempsocket_fd < 0) {
    perror("accept() failed");
  } else {
    FD_SET(tempsocket_fd, &masterfds);
    if (tempsocket_fd > maxfd) {
      maxfd = tempsocket_fd;
    }
  }
  newConnectionCallback(tempsocket_fd);
}

void Server::recvInputFromExisting(int fd) {
  int nbytesrecv = recv(fd, input_buffer, INPUT_BUFFER_SIZE, 0);

  if (nbytesrecv <= 0) {
    if (nbytesrecv == 0) {
      disconnectCallback((uint16_t)fd);
      close(fd);
      FD_CLR(fd, &masterfds);
      return;
    } else {
      perror("recv() failed");
    }
    close(fd);
    FD_CLR(fd, &masterfds);
    return;
  }
  receiveCallback(fd, input_buffer);

  // clear input buffer
  bzero(&input_buffer, INPUT_BUFFER_SIZE);
}

void Server::start() {
  tmpfds = masterfds;
  int sel = select(maxfd + 1, &tmpfds, NULL, NULL, NULL);
  if (sel < 0) {
    perror("select() failed");
    stop();
  }

  // loop over the set of file descriptors and see if we can act
  for (int i = 0; i <= maxfd; i++) {
    if (FD_ISSET(i, &tmpfds)) {
      // there is something to be done
      if (mastersocket_fd == i) {
        // we have a new connection
        handleNewConnection();
      } else {
        // new data on existing connection
        recvInputFromExisting(i);
      }
    }
  }
}

void Server::init() {
  initializeSocket();
  bindSocket();
  startListen();
}

void Server::onInput(receiveCallbackType cb) { receiveCallback = cb; }

void Server::onConnect(newConnectionCallbackType cb) {
  newConnectionCallback = cb;
}

void Server::onDisconnect(disconnectCallbackType cb) {
  disconnectCallback = cb;
}

uint16_t Server::sendMessage(Connector conn, char *messageBuffer) {
  return send(conn.source_fd, messageBuffer, strlen(messageBuffer), 0);
}

uint16_t Server::sendMessage(Connector conn, const char *messageBuffer) {
  return send(conn.source_fd, messageBuffer, strlen(messageBuffer), 0);
}