/*
 * socket.h - socket descriptor and API definition.
 * 
 * Authors  Alain Greiner    (2016,2017,2018,2019,2020)
 *
 * Copyright (c) UPMC Sorbonne Universites
 *
 * This file is part of ALMOS-MKH
 *
 * ALMOS-MKH is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-MKH is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _SOCKET_H_
#define _SOCKET_H_

#include <kernel_config.h>
#include <hal_kernel_types.h>
#include <xlist.h>
#include <remote_buf.h>
#include <remote_busylock.h>

/****************************************************************************************
 * This defines the three commands that can be requested by a client thread to
 * a TX server thread. These commands are registered in the socket descriptor.
 ****************************************************************************************/

typedef enum sock_cmd_e
{
    SOCKET_TX_CONNECT = 20,   /*! request 3 steps handshake (TCP socket only)           */
    SOCKET_TX_SEND    = 21,   /*! request to send data      (TCP or UDP socket)         */
    SOCKET_TX_CLOSE   = 22,   /*! request 3 steps handshake (TCP socket only)           */
}
sock_cmd_t;

/***************************************************************************************** 
 * This structure defines a socket descriptor. In order to parallelize the transfers,
 * the set of all registered sockets is split in several subsets.
 * The number of subsets is the number of  NIC channels. 
 * The distribution key is computed from the (remote_addr/remote_port) couple.
 * This computation is done by the NIC hardware for RX packets, 
 * and by the dev_nic_connect() function for the TX packets.
 *
 * A socket is attached to the NIC_TX[channel] & NIC_RX[channel] chdevs.
 * Each socket descriptor allows the TX and TX server threads to access various buffers:
 * - the user "send" buffer contains the data to be send by the TX server thread.
 * - the kernel "receive" buffer contains the data received by the RX server thread.
 * - the kernel "r2t" buffer allows the RX server thread to make direct requests
 *   to the associated TX server (to implement the TCP 3 steps handshake).
 *
 * The synchronisation mechanism between the clients threads and the servers threads
 * is different for TX and RX transfers:
 *
 * 1) For a TX transfer, it can exist only one client thread for a given socket,
 *    the transfer is always initiated by the local process, and all TX commands
 *    (CONNECT/SEND/CLOSE) are blocking for the client thread. The user buffer is
 *    used by TCP to handle retransmissions when required.in case of re
 *    The client thread registers the command in the thread descriptor, registers itself
 *    in the socket descriptor, unblocks the TX server thread from the BLOCKED_CLIENT 
 *    condition, blocks itself on the BLOCKED_IO condition, and deschedules. 
 *    When the command is completed, the TX server thread unblocks the client thread.
 *    The TX server blocks itself on the BLOCKED_CLIENT condition, when there is no
 *    pending commands and the R2T queue is empty. It is unblocked when a client
 *    register a new command, or when the TX server thread register a mew request
 *    in the R2T queue.
 *    The tx_valid flip-flop is SET by the client thread to signal a valid command. 
 *    It is RESET by the server thread when the command is completed: For a SEND, 
 *    all bytes have been sent (UDP) or acknowledged (TCP).
 *
 * 2) For an RX transfer, it can exist only one client thread for a given socket,
 *    but the transfer is initiated by the remote process, and the  RECV command
 *    is not really blocking: the data can arrive before the local RECV command is
 *    executed, and the server thread does not wait to receive all requested data
 *    to deliver data to client thread. Therefore each socket contains a receive
 *    buffer (rx_buf) handled as a single-writer/single-reader fifo.
 *    The client thread consumes data from the rx_buf when possible. It blocks on the
 *    BLOCKED_IO condition and deschedules when the rx_buf is empty.
 *    It is unblocked by the RX server thread when new data is available in the rx_buf.
 *    The RX server blocks itself on the BLOCKED_ISR condition When the NIC_RX packets
 *    queue is empty. It is unblocked by the hardware when new packets are available.
 * 
 * Note : the socket domains and types are defined in the "shared_socket.h" file.
 ****************************************************************************************/

typedef enum udp_socket_state_e
{
    UDP_STATE_UNBOUND   = 0,
    UDP_STATE_BOUND     = 1,
    UDP_STATE_CONNECT   = 2,
}
udp_socket_state_t;

typedef enum tcp_socket_state_e
{
    TCP_STATE_UNBOUND    = 10,
    TCP_STATE_BOUND      = 11,
    TCP_STATE_LISTEN     = 12,
    TCP_STATE_SYN_SENT   = 13,
    TCP_STATE_SYN_RCVD   = 14,
    TCP_STATE_ESTAB      = 15,
    TCP_STATE_FIN_WAIT1  = 16,
    TCP_STATE_FIN_WAIT2  = 17,
    TCP_STATE_CLOSING    = 18,
    TCP_STATE_TIME_WAIT  = 19,
    TCP_STATE_CLOSE_WAIT = 20,
    TCP_STATE_LAST_ACK   = 21,
}
tcp_socket_state_t;

typedef struct socket_s
{
    remote_busylock_t lock;          /*! lock protecting socket state                  */
    uint32_t          domain;        /*! domain : AF_LOCAL / AF_INET                   */
    uint32_t          type;          /*! type : SOCK_DGRAM / SOCK_STREAM               */
    pid_t             pid;           /*! owner process identifier                      */
    uint32_t          state;         /*! see above                                     */
    uint32_t          local_addr;    /*! local  socket IP address                      */
    uint32_t          remote_addr;   /*! remote socket IP address                      */
    uint32_t          local_port;    /*! local  socket port number                     */
    uint32_t          remote_port;   /*! remote socket port number                     */
    uint32_t          nic_channel;   /*! derived from (remote_addr,remote_port)        */

    xlist_entry_t     tx_list;       /*! sockets attached to same NIC_TX chdev         */
    xptr_t            tx_client;     /*! extended pointer on TX client thread          */
    sock_cmd_t        tx_cmd;        /*! command type (CONNECT/SEND/CLOSE)             */
    uint8_t         * tx_buf;        /*! pointer on user buffer in user space          */
    uint32_t          tx_len;        /*! number of bytes to be sent in command         */
    uint32_t          tx_todo;       /*! number of bytes not yet sent                  */
    uint32_t          tx_error;      /*! signal a TX command error                     */

    xlist_entry_t     rx_list;       /*! sockets attached to same NIC_RX chdev         */
    xptr_t            rx_client;     /*! extended pointer on RX client thread          */
    remote_buf_t      rx_buf;        /*! embedded receive buffer descriptor            */

    remote_buf_t      r2tq;          /*! RX_to_TX requests queue descriptor            */

    remote_buf_t      crqq;          /*! connection requests queue descriptor          */         
    /* the following fields defines the TCB used for a TCP connection                  */

    uint32_t          tx_una;        /*! first unack byte in TX_data stream            */
    uint32_t          tx_nxt;        /*! next byte to send in TX_data stream           */
    uint32_t          tx_wnd;        /*! number of acceptable bytes in TX_data stream  */

    uint32_t          rx_nxt;        /*! next expected byte in RX_data stream          */
    uint32_t          rx_wnd;        /*! number of acceptable bytes in RX_data stream  */
    uint32_t          rx_irs;        /*! initial sequence number in RX_data stream     */
}
socket_t;

/****************************************************************************************
 * This function returns a printable string for a client_to_tx_server command type.
 ****************************************************************************************
 * type   :  SOCKET_TX_CONNECT / SOCKET_TX_SEND / SOCKET_TX_CLOSE 
 ***************************************************************************************/
char * socket_cmd_str( uint32_t type );

/****************************************************************************************
 * This function returns a printable string for an UDP or TCP socket state.
 ****************************************************************************************
 * state  :  UDP_STATE_*** / TCP_STATE*** 
 ***************************************************************************************/
char * socket_state_str( uint32_t state );

/****************************************************************************************
 * This function allocates memory in the cluster defined by the <cxy> argument for a
 * socket descriptor defined by the <domain> and <type> aruments, for the associated
 * file descriptor, and for the various kernel buffers descriptors contained in the
 * socket descriptor : "rx_buf" (receive buffer), "r2tq" (RX to RX requests queue), and 
 * "crqq" (connect requests queue). It initialises the socket desccriptor static fields,
 * (other than local_addr, local_port, remote_addr, remote_port).
 * It registers the file descriptor in the reference process fd_array[], set the socket
 * the socket state to UNBOUND, and returns the file identifier in the <fdid> argument.
 ****************************************************************************************
 * @ cxy     : [in]  target cluster identifier.
 * @ domain  : [in]  socket protocol family (must be AF_INET).
 * @ type    : [in]  socket type (SOCK_DGRAM / SOCK_STREAM).
 * @ socket  : [out] buffer for a local pointer on created socket.
 * @ fdid    : [out] buffer for file identifier.
 * @ return 0 if success / return -1 if failure (no memory).
 ***************************************************************************************/
error_t socket_create( cxy_t              cxy,
                       uint32_t           domain,
                       uint32_t           type,
                       struct socket_s ** socket,
                       uint32_t         * fdid );
                       
/****************************************************************************************
 * This functions releases all memory allocated to a socket identified by the <fdid>
 * argument. This include the file descriptor, the socket descriptor, and all buffers
 * referenced by the socket descriptor.
 ****************************************************************************************
 * @ fdid   : [in]  file descriptor index.
 ***************************************************************************************/
void socket_destroy( uint32_t fdid );

/****************************************************************************************
 * This functions registers the socket defined by the <socket_xp> argument into the
 * lists of sockets attached to the NIC_TX and NIC_TX chdevs identified by the
 * <nic_channel> argument.
 ****************************************************************************************
 * @ socket_xp   : [in]  extended pointer on socket descriptor
 * @ nic_channel : [in]  NIC channel index.
 ***************************************************************************************/
void socket_link_to_servers( xptr_t    socket_xp,
                             uint32_t  nic_channel );
 
#endif	/* _SOCKET_H_ */
