/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    linuxtcpsocketserver.h
 * @date    17.07.2015
 * @author  Alexandre Poirot <alexandre.poirot@legrand.fr>
 * @license See attached LICENSE.txt
 ************************************************************************/

#ifndef JSONRPC_CPP_LINUXTCPSOCKETSERVERCONNECTOR_H_
#define JSONRPC_CPP_LINUXTCPSOCKETSERVERCONNECTOR_H_

#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include "../abstractthreadedserver.h"

namespace jsonrpc {
  /**
   * This class is the Linux/UNIX implementation of TCPSocketServer.
   * It uses the POSIX socket API and POSIX thread API to performs its job.
   * Each client request is handled in a new thread.
   */
  class LinuxTcpSocketServer : public AbstractThreadedServer {
  public:
    /**
     * @brief LinuxTcpSocketServer, constructor of the Linux/UNIX
     * implementation of class TcpSocketServer
     * @param ipToBind The ipv4 address on which the server should
     * bind and listen
     * @param port The port on which the server should bind and listen
     */
    LinuxTcpSocketServer(const std::string &ipToBind, const unsigned int &port, size_t threads = 1);

    virtual ~LinuxTcpSocketServer();

    virtual bool InitializeListener();
    virtual int CheckForConnection();
    virtual void HandleConnection(int connection);

  protected:
    std::string ipToBind;
    unsigned int port;
    int socket_fd;
    struct sockaddr_in address;

    /**
     * @brief A method that wait for the client to close the tcp session
     *
     * This method wait for the client to close the tcp session in order to avoid
     * the server to enter in TIME_WAIT status.
     * Entering in TIME_WAIT status with too many clients may occur in a DOS
     * attack
     * since server will not be able to use a new socket when a new client
     * connects.
     * @param fd The file descriptor of the socket that should be closed by the
     * client
     * @param timeout The maximum time the server will wait for the client to
     * close the tcp session in microseconds.
     * @returns A boolean indicating the success or the failure of the operation
     */
    bool WaitClientClose(const int &fd, const int &timeout = 100000);
    /**
     * @brief A method that close a socket by reseting it
     *
     * This method reset the tcp session in order to avoid enter in TIME_WAIT
     * state.
     * @param fd The file descriptor of the socket that should be reset
     * @returns The return value of POSIX close() method
     */
    int CloseByReset(const int &fd);
    /**
     * @brief A method that cleanly close a socket by avoid TIME_WAIT state
     *
     * This method uses WaitClientClose and ClodeByReset to clenly close a tcp
     * session with a client
     * (avoiding TIME_WAIT to avoid DOS attacks).
     * @param fd The file descriptor of the socket that should be cleanly closed
     * @returns The return value of POSIX close() method
     */
    int CleanClose(const int &fd);
  };

} /* namespace jsonrpc */
#endif /* JSONRPC_CPP_LINUXTCPSOCKETSERVERCONNECTOR_H_ */
