/*************************************************************************\
* "$RCSfile: socket.h,v $"
***************************************************************************
* Information by CVS or VSS:
*     Last check in on: $Date: 2013-03-08 07:02:41 $
*     by                $Author: goebel $
*     Revision        : $Revision: 1.14 $
*
* CVS: $Source: /Daten/Projekte/CVS/Lib/GBIT_Lib/include/socket.h,v $
**************************************************************************/
/*!
\file socket.h
\brief Socket API Header
\author (c) 2004 - 2013 IMAGO Technologies GmbH

$Revision: 1.12 $
$Date: 2012-07-23 12:49:41 $
\addtogroup Socket Socket API
\{
*/
/*************************************************************************/

#ifndef _SOCKET_H_
#define _SOCKET_H_

//!@cond SHOWALL

#define  htons(a) _swap4(a)
#define  htonl(a) _swap4(_packlh2(a, a))
#define  ntohl(a) htonl(a)
#define  ntohs(a) htons(a)

#define  bzero(ptr,sz)       mmZeroInit(ptr,sz)
#define  bcopy(src,dst,sz)   mmCopy(dst,src,sz)

typedef char           INT8;
typedef short          INT16;
typedef int            INT32;
typedef unsigned char  UINT8;
typedef unsigned short UINT16;
typedef unsigned int   UINT32;
typedef unsigned int   uint;
typedef void *         HANDLE;
typedef UINT32         IPN;             // IP Address in NETWORK format
typedef HANDLE         SOCKET;

//-----------------------------------------------------------------------
// IP Address Related Equates
//
#define IN_CLASSA(x)       (((UINT32)(x) & 0x00000080) == 0)
#define IN_CLASSB(x)       (((UINT32)(x) & 0x000000c0) == 0x00000080)
#define IN_CLASSC(x)       (((UINT32)(x) & 0x000000e0) == 0x000000c0)
#define IN_CLASSD(x)       (((UINT32)(x) & 0x000000f0) == 0x000000e0)
#define IN_MULTICAST(x)    IN_CLASSD(x)
#define IN_EXPERIMENTAL(x) (((UINT32)(x) & 0x000000f0) == 0x000000f0)
#define IN_LOOPBACK(x)     (((UINT32)(x) & 0x000000ff) == 0x0000007f)
//!@endcond
#define INADDR_ANY         0x00000000     //! 0.0.0.0
#define INADDR_BROADCAST   0xffffffff     //! 255.255.255.255

//
// Used by fdSelect()
//
//! Time-out value
struct timeval
{
	INT32 tv_sec;	//!< Seconds
	INT32 tv_usec;	//!< Micro seconds
};

//! Used by poll()
typedef struct _fdpollitem
{
	HANDLE fd;				//!< Socket handle
	UINT16 eventsRequested;	//!< Flags for requested events
	UINT16 eventsDetected;	//!< Flags for detected events
} FDPOLLITEM;

#define FD_SETSIZE 16		//!< Maximum number of sockets in fd_set structure

//! The fd_set structure is used by various sockets functions, such as the select() function.
typedef struct _fd_set
{
	uint    count;			//!< Number of sockets in the set
	HANDLE  fd[FD_SETSIZE];	//!< Array of sockets that are in the set
} fd_set;

//
// select() functions / macros
//
//! Add a file descriptor to a file descriptor set
#define FD_SET(n, p)  {if((p)->count<FD_SETSIZE){(p)->fd[(p)->count++]=n;}}
//! Copy a file descriptor set
#define FD_COPY(f, t) memcpy(t, f, sizeof(fd_set))
//! Clear (initialize) a file descriptor set
#define FD_ZERO(p)    ((p)->count=0)

//!@cond SHOWALL

//
// Socket address families
//
#define AF_TASK         1			// Intertask Communication
#define AF_INET         2			// Internet: UDP, TCP, etc.
#define PF_INET         AF_INET

//! Maximum queue length specifiable by listen.
#define SOMAXCONN       8

//!@endcond

//! Structure used for manipulating linger option.
struct linger
{
	int l_onoff;	//!< Option on/off
	int l_linger;	//!< Linger time
};

//! Socket Types
enum eSOCK_TYPE
{
	SOCK_STREAM =       1,			//!< Stream socket
	SOCK_DGRAM =        2,			//!< Datagram socket
	SOCK_RAW =          3,			//!< Raw-protocol interface
	SOCK_STREAMNC =     4			//!< Non-copy stream socket
};

//! Protocols
enum eIPPROTO
{
	IPPROTO_IP =        0,			//!< IP Placeholder
	IPPROTO_ICMP =      1,			//!< ICMP
	IPPROTO_IGMP =      2,			//!< IGMP
	IPPROTO_TCP =       6,			//!< TCP
	IPPROTO_UDP =       17			//!< UDP
};

//! Option flags per-socket.
enum eSO_FLAGS
{
	SO_DEBUG =          0x0001,		//!< Turn on debugging info recording
	SO_ACCEPTCONN =     0x0002,		//!< Socket has had listen()
	SO_REUSEADDR =      0x0004,		//!< Allow local address reuse
	SO_KEEPALIVE =      0x0008,		//!< Keep connections alive
	SO_DONTROUTE =      0x0010,		//!< Just use interface addresses
	SO_BROADCAST =      0x0020,		//!< Permit sending of broadcast messages
	SO_USELOOPBACK =    0x0040,		//!< Bypass hardware when possible
	SO_LINGER =         0x0080,		//!< Linger on close if data present
	SO_OOBINLINE =      0x0100,		//!< Leave received OOB data in line
	SO_REUSEPORT =      0x0200,		//!< Allow local address & port reuse
	SO_TIMESTAMP =      0x0400		//!< Timestamp received datagram traffic
};

//! Used by shutdown()
enum eSHUT
{
	SHUT_RD =           0,			//!< Read side of connection
	SHUT_WR =           1,			//!< Write side of connection
	SHUT_RDWR =         2			//!< Both sides of connection
};

//! Additional options (not flags)
enum eSO_OPTIONS
{
	SO_SNDBUF =         0x1001,		//!< Send buffer size
	SO_RCVBUF =         0x1002,		//!< Receive buffer size
	SO_SNDLOWAT =       0x1003,		//!< Send low-water mark
	SO_RCVLOWAT =       0x1004,		//!< Receive low-water mark
	SO_SNDTIMEO =       0x1005,		//!< Send timeout
	SO_RCVTIMEO =       0x1006,		//!< Receive timeout
	SO_ERROR =          0x1007,		//!< Get error status and clear
	SO_TYPE =           0x1008,		//!< Get socket type
	SO_PRIVSTATE =      0x1009,		//!< Get/deny privileged state
	SO_IFDEVICE =       0x100a,		//!< Broadcast IO device
	SO_BLOCKING =       0x100b,		//!< Blocking is default
	SO_TXTIMESTAMP =    0x100c,		//!< Register a call-out function to timestamp transmitted payload data
	SOL_SOCKET =        0xFFFF		//!< Level used for above options
};

//! IP Level (#IPPROTO_IP) Socket Options
enum eIP_LEVEL
{
	IP_OPTIONS =        1,			//!< Get/set IP Options (20 byte max)
	IP_HDRINCL =        2,			//!< IP Header included with data (raw only)
	IP_TOS =            3,			//!< IP tos & preced.
	IP_TTL =            4			//!< IP ttl
};

//! TCP Level (#IPPROTO_TCP) Socket Options
enum eTCP_LEVEL
{
	TCP_NODELAY =       0x01,		//!< Don't delay send to combine packet data
	TCP_MAXSEG =        0x02,		//!< Adjust MSS (down only)
	TCP_NOPUSH =        0x04,		//!< Don't send just to finish a data block
	TCP_NOOPT =         0x08,		//!< Don't use TCP options
	TCP_SACKPERMITTED = 0x10,		//!< RFC 2018 - SACK is permitted
	TCP_MAXRTT =        0x20		//!< Set maximum RTT value used in calculation
};

//! Read/Write Flags
enum eMSG_FLAGS
{
	MSG_OOB =           0x0001,		//!< Read OOB data (not supported)
	MSG_PEEK =          0x0002,		//!< Get Rx data but leave in queue
	MSG_WAITALL =       0x0004,		//!< Wait for data to fill buffers
	MSG_DONTWAIT =      0x0008,		//!< Don't wait for resources
	MSG_DONTROUTE =     0x0010		//!< Won't route if not local to sub-net
};

//
//! \defgroup ERRC Error codes
//! \{
//! \brief Socket error codes
#define INVALID_SOCKET (HANDLE)0xFFFFFFFF   //!< Used by socket() and accept()
#define SOCKET_ERROR   -1			//!< Used by the rest
#define ENXIO           6			//!< Device not configured
#define EBADF           9			//!< Bad file descriptor
#define ENOMEM          12			//!< Cannot allocate memory
#define EACCES          13			//!< Permission denied
#define EINVAL          22			//!< Invalid argument
#define EMFILE          24			//!< Too many open files

// non-blocking and interrupt i/o
#define EWOULDBLOCK     35			//!< Operation would block
#define EINPROGRESS     36			//!< Operation now in progress
#define EALREADY        37			//!< Operation already in progress

// ipc/network software -- argument errors
#define ENOTSOCK        38			//!< Socket operation on non-socket

#define EMSGSIZE        40			//!< Message too long
#define EPROTOTYPE      41			//!< Protocol wrong type for socket
#define ENOPROTOOPT     42			//!< Protocol not available
#define ESOCKTNOSUPPORT 44			//!< Socket type not supported
#define EOPNOTSUPP      45			//!< Operation not supported
#define EPFNOSUPPORT    46			//!< Protocol family not supported
#define EADDRINUSE      48			//!< Address already in use
#define EADDRNOTAVAIL   49			//!< Can't assign requested address

// ipc/network software -- operational errors
#define ECONNABORTED    53			//!< Software caused connection abort
#define ECONNRESET      54			//!< Connection reset by peer
#define ENOBUFS         55			//!< No buffer space available
#define EISCONN         56			//!< Socket is already connected
#define ENOTCONN        57			//!< Socket is not connected
#define ESHUTDOWN       58			//!< Can't send after socket shutdown
#define ETIMEDOUT       60			//!< Operation timed out
#define ECONNREFUSED    61			//!< Connection refused
#define EHOSTDOWN       64			//!< Host is down

//! \}

//!@cond SHOWALL
//
// DNS Response codes
// (Codes under 16 are from a DNS reply packet)
//
#define NOERROR         0			// (DNS) no error
#define FORMERR         1			// (DNS) format error
#define SERVFAIL        2			// (DNS) server failure
#define NXDOMAIN        3			// (DNS) non existent domain
#define NOTIMP          4			// (DNS) not implemented
#define REFUSED         5			// (DNS) query refused
#define OVERFLOW        16			// buffer overflow
#define MEMERROR        17			// memory allocation error
#define SOCKETERROR     18			// internal socket error
#define NODNSREPLY      19			// DNS Server did not respond

//!@endcond

/*! @brief The HOSTENT structure is used by functions to store information
	about a given host, such as host name, IP address, and so forth.

	An application should never attempt to modify this structure or to free
	any of its components.
*/
struct hostent
{
	char *h_name;					//!< Official CNAME of host
	int  h_addrtype;				//!< Address Type (AF_INET)
	int  h_length;					//!< Address Length (4)
	int  h_addrcnt;					//!< Number of IP addresses found
	IPN  h_addr[8];					//!< List of up to 8 IPaddr (network format)
};

typedef struct hostent HOSTENT;

//! Internet host address
struct in_addr
{
	UINT32  s_addr;					//!< 32 bit long IP address, net order
};

//!@cond SHOWALL

typedef struct in_addr *LPIN_ADDR;

struct sockaddr
{
	UINT8   sin_len;				// total length
	UINT8   sin_family;				// address family
	UINT16  sin_port;				// port
	struct  in_addr sin_addr;
	INT8    sin_zero[8];			// fixed length address value
};

#define sockaddr_in sockaddr
typedef struct sockaddr SA;
typedef struct sockaddr *PSA;

#define FDSTATUS_TYPE           0	// get socket type
#define FDSTATUS_TYPE_SOCKET    1
#define FDSTATUS_TYPE_PIPE      2
#define FDSTATUS_RECV           1	// get socket rcv status
#define FDSTATUS_SEND           2	// get socket snd status

//!@endcond

#define POLLINFTIM              -1		//!< Infinite timeout
#define POLLIN                  0x01	//!< Socket readable (or read error pending)
#define POLLOUT                 0x02	//!< Socket writable (or send error pending)
#define POLLPRI                 0x04	//!< Socket OOB readable (or error pending)
#define POLLNVAL                0x08	//!< Socket or request type invalid

//!@cond SHOWALL

// Call-out function prototype
typedef void (*TimestampFxn)(UINT8 *pIpHdr);

#ifdef __cplusplus
extern "C" {
#endif

// File Descriptor Functions
int fdOpenSession(HANDLE hTask);
void fdCloseSession(HANDLE hTask);
int fdClose(HANDLE fd);
int fdShare(HANDLE fd);
int fdError();
int fdSelect(int width, fd_set *readfds, fd_set *writefds,
			 fd_set *exceptfds, struct timeval *timeout);
void fdSelectAbort(HANDLE hTask);
int fdStatus(SOCKET s, int request, int *results);
int fdPoll(FDPOLLITEM items[], uint itemcnt, INT32 timeout);
void FD_CLR(HANDLE hEntry, fd_set *pSet);
int  FD_ISSET(HANDLE hEntry, fd_set *pSet);

// Socket Oriented Functions
SOCKET socket(int addrfamily, int type, int protocol);
SOCKET GBIT_socket(HANDLE pGBit, int addrfamily, int type, int protocol);
SOCKET accept(SOCKET s, struct sockaddr *address, int *address_len);
int bind(SOCKET s, struct sockaddr *address, int address_len);
int connect(SOCKET s, struct sockaddr *address, int address_len);
int listen(SOCKET s, int maxcon);
int recv(SOCKET s, void *pbuf, int size, int flags);
int recvblock(SOCKET s, void *pbuf, int size, int flags);
int recvfrom(SOCKET s, void *pbuf, int size, int flags, struct sockaddr *address, int *address_len);
int recvblockfrom(SOCKET s, void *pbuf, int size, int flags, struct sockaddr *address, int *address_len);
int send(SOCKET s, const void *pbuf, int size, int flags);
int sendto(SOCKET s, const void *pbuf, int size, int flags, struct sockaddr *address, int address_len);
int sendblockto(SOCKET s, const void *pbuf, int totalsize, int packetsize, int flags, struct sockaddr *address, int address_len);
int send2D(SOCKET s, const void *pbuf, int lineLen, int lineCnt, int linePitch, int flags);
int setsockopt(SOCKET s, int level, int option_name, void *option_value, int option_length);
int getsockopt(SOCKET s, int level, int option_name, void *option_value, int *option_length);
int shutdown(SOCKET s, int how);
int poll(FDPOLLITEM items[], uint itemcnt, INT32 timeout);
int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout);
int socketerror();
int closesocket(SOCKET s);
static inline int socketclose(SOCKET s) {return closesocket(s);}
IPN inet_addr(const char *);
int inet_aton(const char *, struct in_addr *);
char *inet_ntoa(struct in_addr in);
int gethostname(char *pNameBuf, int size);
int gethostbyname(char *Name, void *pScrapBuf, int size);
int getsockname(SOCKET s, PSA pName, int *plen);
int getpeername(SOCKET s, struct sockaddr *pName, int *plen);
int socketGetTxSpace(SOCKET s);

#ifdef __cplusplus
}
#endif
//!@endcond
#endif
//! \}
/*************************************************************************/
