/* FILENAME: embtcp.h
 *
 * Copyright 2011 By InterNiche Technologies Inc. All rights reserved.
 *
 * This header file contains various definitions required for network
 * applications.
 *
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "iniche_types.h"


struct in_addr
{
   u_long s_addr;
};

#define  INADDR_ANY     0L

/*
 * Structure used by kernel to store most
 * addresses.
 */
struct sockaddr
{
   u_short sa_family;   /* address family */
   char    sa_data[14]; /* up to 14 bytes of direct address */
};

/* Berkeley style "Socket address" */
struct sockaddr_in
{
   short   sin_family;
   u_short sin_port;
   struct  in_addr  sin_addr;
   char    sin_zero[8];
};

/* size of the sockets arrays passed to select() */
#define FD_SETSIZE 12

typedef struct   /* the select socket array manager */
{ 
   unsigned fd_count;               /* how many are SET? */
   long     fd_array[FD_SETSIZE];   /* an array of SOCKETs */
} fd_set;

/* FD_ZERO, FD_CLR, FD_SET, and FD_ISSET are implemented as macros:
 *
 * FD_ZERO(set)
 * FD_CLR(so, set)
 * FD_SET(so, set)
 * FD_ISSET(so, set)
 *
 * Data types:
 *
 * set = fd_set * (pointer to file descriptor set)
 * so = long (specifies the socket id)
 */
#define FD_ZERO(set)      (((fd_set *)(set))->fd_count = 0)
#define FD_CLR(so, set)   ifd_clr((long)(so), (fd_set *)(set))
#define FD_SET(so, set)   ifd_set((long)(so), (fd_set *)(set))
#define FD_ISSET(so, set) ifd_isset((long)(so), (fd_set *)(set))

void ifd_clr(long so, fd_set *set);
void ifd_set(long so, fd_set *set);
int  ifd_isset(long so, fd_set *set);

#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
#define PF_INET AF_INET
#define SOCK_STREAM 1 /* stream socket */
#define SOCK_DGRAM  2 /* datagram socket */

#define IPPROTO_IP   0
#define IPPROTO_ICMP 1
#define IPPROTO_TCP  6
#define IPPROTO_UDP 17

#define MSG_OOB      0x01 /* process out-of-band data */
#define MSG_PEEK     0x02 /* peek at incoming message */
#define MSG_DONTWAIT 0x20 /* this message should be nonblocking */

/*
 * Option flags per-socket.
 */
#define SO_DEBUG       0x00001     /* turn on debugging info recording */
#define SO_ACCEPTCONN  0x00002     /* socket has had listen() */
#define SO_REUSEADDR   0x00004     /* allow local address reuse */
#define SO_KEEPALIVE   0x00008     /* keep connections alive */
#define SO_DONTROUTE   0x00010     /* just use interface addresses */
#define SO_BROADCAST   0x00020     /* permit sending of broadcast msgs */
#define SO_USELOOPBACK 0x00040     /* bypass hardware when possible */
#define SO_LINGER      0x00080     /* linger on close if data present */
#define SO_OOBINLINE   0x00100     /* leave received OOB data in line */
#define SO_TCPSACK     0x00200     /* Allow TCP SACK (Selective acknowledgment) */
#define SO_WINSCALE    0x00400     /* Set scaling window option */ 
#define SO_TIMESTAMP   0x00800     /* Set TCP timestamp option */ 
#define SO_BIGCWND     0x01000     /* Large initial TCP Congenstion window */ 
#define SO_HDRINCL     0x02000     /* user access to IP hdr for SOCK_RAW */
#define SO_NOSLOWSTART 0x04000     /* suppress slowstart on this socket */
#define SO_FULLMSS     0x08000     /* force packets to all be MAX size */

/*
 * Additional options, not kept in so_options.
 */
#define SO_SNDBUF      0x1001      /* send buffer size */
#define SO_RCVBUF      0x1002      /* receive buffer size */
#define SO_SNDLOWAT    0x1003      /* send low-water mark */
#define SO_RCVLOWAT    0x1004      /* receive low-water mark */
#define SO_SNDTIMEO    0x1005      /* send timeout */
#define SO_RCVTIMEO    0x1006      /* receive timeout */
#define SO_ERROR       0x1007      /* get error status and clear */
#define SO_TYPE        0x1008      /* get socket type */
#define SO_HOPCNT      0x1009      /* Hop count to get to dst   */
#define SO_MAXMSG      0x1010      /* get TCP_MSS (max segment size) */

/* ...And some netport additions to setsockopt: */
#define SO_RXDATA      0x1011      /* get count of bytes in sb_rcv */
#define SO_TXDATA      0x1012      /* get count of bytes in sb_snd */
#define SO_MYADDR      0x1013      /* return my IP address */
#define SO_NBIO        0x1014      /* set socket into NON-blocking mode */
#define SO_BIO         0x1015      /* set socket into blocking mode */
#define SO_NONBLOCK    0x1016      /* set/get blocking mode via optval param */
#define SO_CALLBACK    0x1017      /* set/get zero_copy callback routine */

/*
 * TCP User-settable options (used with setsockopt).
 * TCP-specific socket options use the 0x2000 number space.
 */

#define TCP_ACKDELAYTIME 0x2001    /* Set time for delayed acks */
#define TCP_NOACKDELAY   0x2002    /* suppress delayed ACKs */
#define TCP_MAXSEG       0x2003    /* set maximum segment size */
#define TCP_NODELAY      0x2004    /* Disable Nagle Algorithm */

#define SOL_SOCKET       -1 /* compatability parm for set/get sockopt */
#define IP_OPTIONS        1 /* buf/ip_opts; set/get IP options */
#define IP_TOS            3 /* int; IP type of service and preced. */
#define IP_TTL_OPT        4 /* int; IP time to live */

#define ENOBUFS         1
#define ETIMEDOUT       2
#define EISCONN         3
#define EOPNOTSUPP      4
#define ECONNABORTED    5
#define EWOULDBLOCK     6
#define ECONNREFUSED    7
#define ECONNRESET      8
#define ENOTCONN        9
#define EALREADY       10
#define EINVAL         11
#define EMSGSIZE       12
#define EPIPE          13
#define EDESTADDRREQ   14
#define ESHUTDOWN      15
#define ENOPROTOOPT    16
#define EHAVEOOB       17
#define ENOMEM         18
#define EADDRNOTAVAIL  19
#define EADDRINUSE     20
#define EAFNOSUPPORT   21
#define EINPROGRESS    22
#define ELOWER         23
#define ENOTSOCK       24
#define EIEIO          27
#define ETOOMANYREFS   28
#define EFAULT         29
#define ENETUNREACH    30

/* ENP_xxx family of errors returned by various APIs */
#define ENP_PARAM           -10 /* bad parameter */
#define ENP_LOGIC           -11 /* sequence of events that shouldn't happen */
#define ENP_NOCIPHER        -12 /* No corresponding cipher found for the cipher id */
#define ENP_NOMEM           -20 /* malloc or calloc failed */
#define ENP_NOBUFFER        -21 /* ran out of free packets */
#define ENP_RESOURCE        -22 /* ran out of other queue-able resource */
#define SEND_DROPPED        ENP_RESOURCE /* full queue or lack of resource */
#define ENP_BAD_STATE       -23 /* TCP layer error */
#define ENP_TIMEOUT         -24 /* TCP layer error */
#define ENP_NOFILE          -25 /* expected file was missing */
#define ENP_FILEIO          -26 /* file IO error */
#define ENP_SENDERR         -30 /* send to net failed at low layer */
#define ENP_NOARPREP        -31 /* no ARP for a given host */
#define ENP_BAD_HEADER      -32 /* bad header at upper layer (for upcalls) */
#define ENP_NO_ROUTE        -33 /* can't find a reasonable next IP hop */
#define ENP_NO_IFACE        -34 /* can't find a reasonable interface */
#define ENP_HARDWARE        -35 /* detected hardware failure */
#define ENP_CBRD_FAILED     -36 /* cb_read() function failed */
#define ENP_CBWR_FAILED     -37 /* cb_write() function failed */
#define ENP_COALESCE_FAILED -38 /* a packet coalesce operation failed */
#define ENP_DUPLICATE       -39 /* duplicate detected */

/* conditions that are not really fatal OR success */
#define ENP_SEND_PENDING      1 /* packet queued pending an ARP reply */
#define ENP_NOT_MINE          2 /* packet was not of interest */
#define ENP_ONGOING           3 /* initialization in progress */

#define SOCKET_ERROR -1   /* error return from send(), sendto(), et.al. */
#define INVALID_SOCKET -1

/* t_shutdown "how" parameter values */
#define SHUT_RD   0 /* shutdown "read" half */
#define SHUT_WR   1 /* shutdown "write" half */
#define SHUT_RDWR 2 /* shutdown both "read" and "write" */

/*
 * Structure used for manipulating linger option.
 */
struct linger
{
   int l_onoff;  /* option on/off */
   int l_linger; /* linger time (seconds) */
};

#define ESUCCESS          0 /* The call was successfull */
#define EFAILURE         -1 /* The call failed */

#define TPS               20  /* cticks per second */

/* timer definitions */
extern u_long cticks;
#define CTICKS          cticks

/* convert little/big endian - these should be efficient, 
 * inline code or MACROs
 */
#define htonl(l) (((((l) >> 24) & 0x000000ff)) | \
		  ((((l) >>  8) & 0x0000ff00)) | \
		  (((l) & 0x0000ff00) <<  8) | \
		  (((l) & 0x000000ff) << 24))
#define ntohl(l) htonl(l)
#define htons(s) ((((s) >> 8) & 0xff) | \
		  (((s) << 8) & 0xff00))
#define ntohs(s) htons(s)

/* Macro for passing IP addresses to printf octet at a time. usage: 
 * printf("address=%u.%u.%u.%u\n", PUSH_IPADDR(ip)); Since we store IP 
 * addresses in net endian, it's endian sensitive. 
 */
#define  PUSH_IPADDR(ip)\
   (unsigned)(ip&0xff),\
   (unsigned)((ip>>8)&0xff),\
   (unsigned)((ip>>16)&0xff),\
   (unsigned)(ip>>24)

/* Global variables */
extern bool_t iniche_net_ready;
extern bool_t iniche_init_done;
extern bool_t iniche_os_ready;

/*******************************************************************/
/*                           sockets API                           */
/*******************************************************************/

long t_socket(int, int, int);
int  t_bind(long, struct sockaddr *, int);
int  t_listen(long, int);
long t_accept(long, struct sockaddr *, int *);
int  t_connect(long, struct sockaddr *, int);
int  t_getpeername(long, struct sockaddr *, int *);
int  t_getsockname(long, struct sockaddr *, int *);
int  t_setsockopt(long, int, int, void *, int);
int  t_getsockopt(long, int, int, void *, int);
int  t_recv(long, char *, int, int);
int  t_send(long, char *, int, int);
int  t_recvfrom(long, char *, int, int, struct sockaddr *, int *);
int  t_sendto (long, char *, int, int, struct sockaddr *, int);
int  t_shutdown (long, int);
int  t_socketclose (long);
int  t_errno(long s);
int  t_select(fd_set *, fd_set *, fd_set *, long); 

/* ASCII strings <-> network byte-ordered addresses */
int   inet_pton(int af, const char * src, void * dst);
const char *inet_ntop(int af, const void *addr, char *str, size_t size);

/* maximum length of interface name, including NUL (e.g., "et1") */
#define IF_NAMELEN 4

/* RFC 3493 interface-related data structures and functions
 *
 * if_nameindex() returns all interface names and indices
 * if_freenameindex() frees memory from if_nameindex() calls.
 *
 */
struct if_nameindex
{
   unsigned int   if_index;  /* 1, 2, ... */
   char          *if_name;   /* null terminated name */
};

struct if_nameindex *if_nameindex(void);
void  if_freenameindex(struct if_nameindex *ptr);
char *if_indextoname(unsigned int ifindex, char *ifname);
unsigned int if_nametoindex(const char *ifname);

/* timer-related macros (assume 2's complement arithmetic) */

/* addition
 * useage: expiration_time = start_time + timer_duration
 */
#define TIME_ADD(t1,t2) ((t1) + (t2))

/*
 * subtraction 
 * useage: elapsed_time = now - start_time 
 *         start_time = now - duration
 */
#define TIME_SUB(t1,t2) ((long)(((t1)) - (t2)))

/*
 * compare times 
 * useage: if ((t1 - t2) > duration) 
 * 
 * Result: positive integer if t1 > t2
 *         negative integer if t1 < t2
 *         0 if t1 = t2;        
 */
#define TIME_CMP(t1,t2) (int)((t1) - (t2))

/* macro to determine if a timer has expired 
 * e (expiration_time) = unsigned long int
 * n (now (i.e., current value of system clock)) = unsigned long int
 *
 * Result: 0 = timer not expired, 1 = timer expired  
 */
#define TIME_EXP(e,n) (bool_t)(((int)((e) - (n))) <= 0) 

/*******************************************************************/
/*                           DHCP client                           */
/*******************************************************************/

/* length of data portion of vendor class identifier option */
#define DHCP_VENDCLASS_MAXLEN 32

/* list of reason codes indicating results of UPNP/DHCP/auto-conf
 * address acquisition process
 *
 * 0=address not available (IPv4 address of interface is 0.0.0.0)
 * 1=interface configured to use (non-zero) static address
 * 2=interface configured to use auto-IP address (169.254.1.0-169.254.254.255)
 * 3=interface configured to use address obtained via DHCP
 */
#define UPNP_ZERO_ADDR     0
#define UPNP_STATIC_ADDR   1
#define UPNP_AUTOCONF_ADDR 2
#define UPNP_DHCP_ADDR     3

/* FUNCTION: in_addrconf_acquire()
 * 
 * This function starts the address acquisition process for the specified 
 * interface using the protocols specified in the 'flags' parameter.
 *
 * PARAM1: char * - Name of interface
 * PARAM2: uint32_t - Bitmask indicating protocols that are utilized 
 *                    in the address acquisition process (NETF_DHCPC and/or 
 *                    NETF_AUTOIP)
 *
 * RETURNS: This function returns EFAILURE if the interface name isn't 
 *          valid; otherwise, it returns ESUCCESS.
 */
int in_addrconf_acquire(char *name, uint32_t flags);

/* FUNCTION: in_addrconf_release()
 * 
 * This function terminates the use of the specified protocols for address 
 * acquisition on the specified interface.  The interface address
 * configuration data structures are cleared out.
 *
 * PARAM1: char * - Name of interface
 * PARAM2: uint32_t - Bitmask indicating protocols that will no longer be 
 *                    utilized in the address acquisition process (NETF_DHCPC 
 *                    and/or NETF_AUTOIP)
 * PARAM3: bool_t - enable (TRUE) or disable (FALSE) restoration of 
 *                  previously configured static address (only utilized
 *                  when all address configuration protocols have been
 *                  disabled on the link)
 *
 * RETURNS: This function returns EFAILURE if the interface name isn't 
 *          valid; otherwise, it returns ESUCCESS.
 */
int in_addrconf_release(char *name, uint32_t flags, bool_t restore_static);

/*******************************************************************/
/*                           DNS client                            */
/*******************************************************************/

#define MAXDNSSERVERS    3 /* maximum number of DNS servers */
#define MAXDNSNAME      96 /* maximum length of name */

/* maximum number of IPv4 addresses returned from gethostbyname() (via 
 * struct hostent)
 */
#define MAX_IPV4_ADDRS 6
/* maximum number of aliases returned from gethostbyname() (via struct 
 * hostent) 
 */
#define MAX_ALIASES 6

/* hostent data structure, used to provide resolution information to caller 
 * of gethostbyname() 
 */
struct hostent
{
   char *h_name;       /* canonical name; points to 'realname' */
   char **h_aliases;   /* alias addresses; points to 'aliases' */
   int h_addrtype;     /* address type (AF_INET for IPv4) */
   int h_length;       /* length of address (4 for IPv4)  */
   char **h_addr_list; /* list of addresses from name server */
   char realname[MAXDNSNAME]; /* canonical name */
   ip_addr addr4[MAX_IPV4_ADDRS];       /* list of IPv4 addresses for name */
                                        /* (network byte order) */
   ip_addr *addr4p[MAX_IPV4_ADDRS + 1]; /* point to entries in 'addr4'; */
                                        /* last pointer is NULL */
   char *aliases[MAX_ALIASES];          /* list of aliases for name */
};

/* FUNCTION: dnc_init()
 * 
 * This function initializes the DNS client module.
 *
 * PARAM1: none
 *
 * RETURNS: This function can return any one of the following values:
 * 
 * (a) ENP_PARAM, if the configuration provided is not correct
 * (b) ENP_RESOURCE, if the DNS client couldn't allocate memory for the
 *     table, or if any of the t_socket(), t_bind(), and t_setsockopt()
 *     calls failed
 * (c) ESUCCESS, if the DNS client was initialized successfully
 */
int dnc_init(void);

/* FUNCTION: gethostbyname()
 * 
 * This function is used to obtain the IPv4 address corresponding to a
 * name.
 *
 * PARAM1: char * - Name that needs be resolved (to an IPv4 address)
 *
 * RETURNS: This function NULL if the resolution fails.  Otherwise, it
 *          returns a pointer to a dynamically allocated hostent data
 *          structure containing (among other things) the IPv4 address 
 *          that corresponds to the name.
 */
struct hostent *gethostbyname(char *name);
/* free hostent structure */
void dnc_free_hostent(struct hostent *hep);
void dnc_shutdown(void);

/*******************************************************************/
/*                       ping application                          */
/*******************************************************************/

/*
 * ping_init() initializes the ping application module.
 * ping_send() initiates a (one-ping only) ping session.
 * The callback function is invoked only upon the receipt of a ping 
 * response, or upon the occurence of a timeout.  In the latter case, 
 * the packet parameter is NULL.  The callback will also be invoked 
 * if the ping module is shutdown via ping_close(), and the packet 
 * parameter will be NULL.
 * ping_close() terminates the ping module.
 *
 */

/* list of reasons provided via callback routine */
#define PING_TIMEOUT        0 /* no response received */
#define PING_MODULE_STOPPED 1 /* ping module has been (administratively) */
                              /* shutdown */
#define PING_RESP_RCVD      2 /* ping response received */
/* data inserted into outgoing ping request (sequence of 0xAA) */
#define PING_DATA_BYTE 0xAA

/* FUNCTION: ping_init()
 * 
 * This function initializes the ping module.  It allocates a buffer
 * that will contain the ping session table, and also sets the size
 * of the session table.
 *
 * PARAM1: none
 *
 * RETURNS: This function can return any one of the following values:
 * (a) ENP_RESOURCE, if the session table could not be allocated
 * (b) ENP_PARAM, if the size of the table is not greater than
 *     zero
 * (c) ESUCCESS, if the table has been successfully setup
 */
int ping_init(void);

/* ping application client's callback function */
typedef void (*PING_CBKFN)(ip_addr src, char *buffer, int length, 
                           uint16_t id, uint16_t seq, bool_t match, 
                           int reason);

/* FUNCTION: ping_send()
 * 
 * This function creates and transmits an ICMP Echo packet.
 *
 * PARAM1: ip_addr - IPv4 destination address (host byte order)
 * PARAM2: char * - Pointer to data (for insertion into Data portion of 
 *                  ICMP Echo packet) (may be NULL)
 * PARAM3: int - Length of data (pointed to by 'data')
 * PARAM4: uint16_t - value of Identifier field in ICMP Echo packet
 *                    (host byte order)
 * PARAM5: uint16_t - value of Sequence Number field in ICMP Echo packet
 *                    (host byte order)
 * PARAM6: PING_CBKFN - callback function (to be invoked) when an ICMP
 *                      Echo Reply is received
 * PARAM7: void *     (void *)(-1) for silent, otherwise must be NULL
 *
 * RETURNS: This function can return any one of the following values:
 * (a) ENP_LOGIC, if it is invoked and the ping application module is
 *     disabled
 * (b) ENP_PARAM, if the length parameter is invalid
 * (c) ENP_DUPLICATE, if a matching session already exists
 * (d) ENP_RESOURCE, if the session table is full or a packet buffer
 *     cannot be allocated
 * (e) ENP_CBRD_FAILED, if any of the attempts to add or update data
 *     into the packet buffer failed
 * (f) return code from ip_write() (if less than ESUCCESS (0))
 * (g) ESUCCESS, if packet was successfully provided to the IP layer
 */
int  ping_send(ip_addr dest, char *data, int length, uint16_t id,
               uint16_t seq, PING_CBKFN cbkp, void *pio);
void ping_close(void);


/*************************************************************************/
/*                       Tasking-related definitions                     */
/*************************************************************************/

#define IN_SEM                      void

struct task
{ 
   xTaskHandle tk_task;          /* FreeRTOS task handle */
   IN_SEM      *tk_semaphore;    /* per-task semaphore */
};

typedef struct task  TASK;

#define TK_THIS               ((TASK *)NULL)
#define SYS_SHORT_SLEEP       2
#define INFINITE_DELAY        0x7FFFFFFF  /* Maximum settable delay period  */

#define TK_INIT_OS()

#define TK_START_OS()         { \
                                iniche_os_ready = TRUE; \
                                vTaskStartScheduler(); \
                              }

#define TK_CREATE(code, name, stack, param, prio, taskp)    \
         tk_new((code), (stack), (name), (prio), 0, (void *)(param), (taskp))

#define TK_YIELD()            vTaskDelay(SYS_SHORT_SLEEP)
#define TK_SLEEP(n)           tk_sleep(n)
#define TK_DELETE(tk)         tk_del(tk)
#define TK_SUSPEND(tk)        tk_suspend(tk)
#define TK_RESUME(tk)         tk_wake(tk)

extern void tk_wake(TASK *);           /* mark a task to run */
extern void tk_suspend(TASK *tk);      /* suspend a task */
extern void tk_sleep(uint32_t);
extern void tk_del(TASK *);
extern int  tk_new(void (*start)(void *), int stksiz, char *name,
                   u_int priority, uint32_t flags, void *arg, TASK **taskp);
extern void dtrap(void);
extern void panic(char *msg);

