/******************************************************/
/* Copyright (C) 2008 Arch Rock Corporation 2008      */
/* License Agreement: refer to LICENSE.txt            */
/*                                                    */
/******************************************************/

#ifndef _SOCKET_H
#define _SOCKET_H    1

#include <netinet/in.h>
#include <event.h>

/*! IPv6 Socket address and port */
typedef struct sockaddr_in6 {
  /*! Transport layer port */
  uint16_t sin6_port;
  /*! IPv6 address */
  in6_addr_t sin6_addr;
  /*! IPv6 flow information. Reserved.*/
  uint8_t sin6_flowinfo;
  /*! Reserved. */
  uint8_t sin6_flags;
} sockaddr_in6_t;

#define s6_addr    in6_u.u6_addr8
#define s6_addr16  in6_u.u6_addr16
#define s6_addr32  in6_u.u6_addr32

/*! Socket types.*/
enum SockTypeEnums{
  /*! Provides sequenced, reliable, two-way, connection-based byte
    streams.  */
  SOCK_STREAM=1,
  /*! Supports datagrams (connectionless, unreliable messages of
    a fixed maximum length bounded by link layer) */
  SOCK_DGRAM,
  /*! Supports datagrams (connectionless, unreliable messages of
    a fixed maximum length bounded supported by link layer fragmentation.) 
    This is not currently supported. */
  SOCK_DGRAM_FRAG,
};

/*! AF INET Protocol Family */
enum AFEnums{
  /*! IPv4 Internet protocols */
  AF_INET=10,
  /*! IPv6 Internet protocols */
  AF_INET6,
};

/*! A system call to create an endpoint for communication 
 *  and return a descriptor if the total limit has not been reached.
 *  
 *  @param[in] domain specifies a communication domain or the
 *                    protocol family which will be used for 
 *                    communication.  See #AFEnums.
 *  @param[in] type specifies the communication semantics.  
 *                  See #SockTypeEnums.
 *  @param[in] protocol Not supported.
 *  \return On success, a socket descriptor for the new socket is
 *          returned.  On error, -1 is returned, and \em errno is
 *          set appropriately.
 *
 *  \par Errors: 
 *     EINVAL unknown protocol, or protocol family not available.
 *  \par
 *     ENFILE the system limit on the total number of open sockets
 *            with this protocol has been reached.
*/
int16_t socket(int16_t domain, int16_t type, int16_t protocol);


/*! A system call to send a message on a socket to another socket.
 *  The socket must be in a connected state (so that the intended  
 *  recipient is known).  
 *
 *  When completed, the system has copied \em buf up to \em len number of 
 *  bytes into its internal queue for in order transmission
 *  of the byte stream.
 *
 *  @param[in] s socket descriptor of the sending socket.
 *  @param[in] buf buffer that contains the message. The system will
 *             copy the message into the user provided buffer queue
 *             established in \em tcpbind.
 *  @param[in] len length of the message in bytes.
 *  @param[in] flags reserved for future use.
 *  \return 0 is returend on success. 
 *          On error, -1 is returned, and errno is set appropriately.
 *
 *  \par Errors:
 *     EINVAL invalid argument passed.
 *     ESIZE no buffer space to accomodate message
 *     ENOTCONN the socket is not connected
 */
int16_t send(int16_t s, const void *buf, int16_t len, int16_t flags);

/*! A system call to send a message on a socket to another socket.
 *  The socket must be in a connectionless state with the intended  
 *  recipient specified as an argument.
 *
 *  When completed, the system has copied \em buf up to \em len number of 
 *  bytes into its internal queue for transmission.
 *
 *  @param[in] s socket descriptor of the sending socket.
 *  @param[in] buf buffer that contains the message. The system will
 *             copy the message into the user provided buffer queue
 *             established in \em udpbind.
 *  @param[in] len length of the message in bytes.
 *  @param[in] flags reserved for future use.
 *  @param[in] to recipient address in socket address structure
 *
 *  \return On error, -1 is returned, and errno is set appropriately.
 *
 *  \par Errors:
 *     EINVAL invalid argument passed.
 *     ESIZE no buffer space to accomodate message at this time.
 */
int16_t sendto(int16_t s, const void *buf, int16_t len, int16_t flags,
	       const sockaddr_in6_t *to);


typedef struct udp_recvfrom
{
  /*! returns the same socket id during call time */
  int16_t sockid;
  /*! points to the received message stored in the queue. */
  void * payload;
  /*! length of the message in number of bytes. */
  uint8_t len;
  /*! the socket address of the message's sender. */
  sockaddr_in6_t *from;
}udp_recvfrom_t;

/*!  A system call that gives a UDP socket the local address,
 *   a user allocated buffer for message queuing, and a callback
 *   for reception notification.
 *  
 *   When completed, the system binds socket \em s to \em my_addr,
 *   \em recvfrom handler for packet reception notification and listening
 *   on the address is started automatically. These bindings will be 
 *   cleared when the socket is closed.
 * 
 *   @param[in] s socket descriptor of the socket
 *   @param[in] my_addr local address to bind to the socket
 *   @param[in] buf user allocated heap memory to be used 
 *                  for buffering. (only for SOCK_DGRAM_FRAG)
 *   @param[in] buflen length of \em buf in bytes.(only for SOCK_DGRAM_FRAG)
 *   @param[in] recvfrom a callback handler that signals a UDP
 *                packet reception destined to \em my_addr.
 *                If NULL is passed, call will fail.
 *   @param[out] recvfrom_cbargs storing the recvfrom arguments
 *               for the callback.  If NULL, only notification
 *               will be generated.
 *   @param[in]  context user context
 *   \return On success, zero is returned.  On error, -1 is returned
 *           and errno is set appropriately.
 *
 *   \par Errors: 
 *      EINVAL invalid argument passed.
 *   \par
 *      EFAULT  bad address. 
 *   
 *  \note \em recvfrom_cbargs needs to be copied if user wants
 *        to retain its information across callbacks.
 *
 *  \section socket Callback Descriptions
 *  \subsection udpbind udpbind
 *     @param[in] event Type is UDPBIND in #EventsEnum.
 *     @param[in] cbargs is \em recvfrom_cbargs in udpbind().
 *     @param[in] context is \em context in udpbind().
 *  \return None.
 */
int16_t udpbind(int16_t s, const sockaddr_in6_t *my_addr,
		void *buf, int16_t buflen,
		void (*recvfrom)(event_t event,
				 void * cbargs,
				 void * context),
		udp_recvfrom_t *recvfrom_cbargs,
		void * context);


typedef struct tcp_event{
  /*! Returns the same socket id during call time */
  int16_t socket;
  /*! Reflect the state of the underlying TCP session. */
  int8_t type;
  /* Points to the received message stored in the queue. */
  void * recvbuf;
  /* Number of bytes received. */
  int16_t recvlen; 
  /*! The socket address of the message's sender. */
  sockaddr_in6_t addr;
}tcp_event_t;

enum TcpStatesEnum{
  /*! Incoming TCP connection.
   *  addr in tcp_event_t contains the IP address of the
   *  peer initiating the connection.
   */
  ACCEPT=1,
  /*! TCP connection established. */
  CONNECTED,
  /*! TCP connection has incoming data. */
  RECV,
  /*! TCP connection is closed. */  
  CLOSED,
};


/*!  A system call that gives a TCP socket the local address,
 *   a user allocated buffer for message queuing, and a callback
 *   handler for interacting with the TCP stack.
 *  
 *   The system binds the socket \em s to \em my_addr,
 *   the corresponding callback handlers, 
 *   and the user-provided heap memory for 
 *   transmission queuing.  Listening on the address is
 *   automatically started.  These bindings will be
 *   cleared when the socket is closed.
 * 
 *   @param[in] s socket descriptor of the socket
 *   @param[in] my_addr local address to bind to the socket
 *   @param[in] buf user allocated heap memory to be used 
 *                  for buffering 
 *   @param[in] buflen length of \em buf in bytes.
 *   @param[in] tcp_handler a callback handler to interact
 *                 with the different states of a TCP session.
 *                 If NULL is passed, call will fail.
 *   @param[out] tcp_event argument for the \em tcp_handler notification.
 *                         if NULL is passed, call will fail.
 *   @param[in] context user context
 *   \return On success, zero is returned.  On error, -1 is returned
 *           and errno is set appropriately.
 *
 *   \par Errors: 
 *      EINVAL invalid argument passed.
 *   \par
 *      EFAULT  bad address. 
 *   
 *  \section socket Callback Descriptions
 *  \subsection tcpbind tcpbind
 *     @param[in] event Type is TCPBIND in #EventsEnum.
 *     @param[in] cbargs is \em tcp_event in tcpbind().
 *     @param[in] context is \em context in tcpbind().
 *  \return None.
 */
int16_t tcpbind(int16_t s, const sockaddr_in6_t *my_addr,
		void * buf, int16_t buflen,
		void (*tcp_handler)(event_t event,
				    void * cbargs,
				    void * context),
		tcp_event_t *tcp_event ,
		void * context);


/*! A system call that connects the socket referred to by the
 *  socket descriptor to an destination IP address.  Only
 *  the type SOCK_STREAM is supported for this call.
 *
 *  This is a non-blocking connect call.  Actual establishment
 *  of the connection or failure will be notified later.
 *
 *  \pre  This call must be invoked after tcpbind().
 *  \post The system tries to initiate a connection to 
 *        the destination.
 *  \param[in] s socket descriptor
 *  \param[in] to destination IP address 
 *  \return 0 if the system agrees to make a connection.  
 *            On error, -1 is returned, and errno is set
 *            appropriately.
 *
 *  \par Errors:
 *     EINVAL invalid argument passed
 *  \par
 *     EBUSY  underlying socket is busy (already connected).
 *    
 */
int16_t connect(int16_t s, const sockaddr_in6_t *to);

/*! A system call that accept an incoming connection on the
 *  socket referred to by the
 *  socket descriptor to an destination IP address.  Only
 *  the type SOCK_STREAM is supported for this call.
 *
 *  \pre  This call should be invoked after tcpbind() 
 *        has notified that the socket has changed to
 *        the ACCEPT state.
 *  \post The system will try to service the incoming connection to 
 *        the destination.
 *  \param[in] s socket descriptor
 *  \param[in] to destination IP address 
 *  \return 0 if the system agrees to make a connection.  
 *            On error, -1 is returned, and errno is set
 *            appropriately.
 *
 *  \par Errors:
 *     EINVAL invalid argument passed
 *  \par
 *     EBUSY  underlying socket is busy (already connected).
 *    
 */
int16_t accept(int16_t s, const sockaddr_in6_t *to);


#endif //_SOCKET_H
