
#ifndef SOC_LIB2_H
#define SOC_LIB2_H

#ifndef PLATFORM_KIND
#define Posix_Platform  0 
#define Mingw_Platform  1
#define MsVisC_Platform 2

#ifdef __MINGW32__
#define PLATFORM_KIND Mingw_Platform
#elif defined(__WIN32) || defined(WIN32)
#define PLATFORM_KIND MsVisC_Platform
#else
#define PLATFORM_KIND Posix_Platform    /* Posix/Linux/Unix, Microsoft MinGW or MSVisC. */ 
#endif
#endif

#if (PLATFORM_KIND==Posix_Platform)
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <net/if.h>
#include <stdint.h>
#include <errno.h>
#define closesocket close
#define ioctlsocket ioctl
#define WSAEINTR EINTR
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAECONNREFUSED ECONNREFUSED
#define WSAECONNABORTED ECONNABORTED
#define WSAEAGAIN EAGAIN
#define WSAEPROTO EPROTO
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#else //Posix
#include <windows.h>
#include <winbase.h>
#include <winuser.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#ifndef R_OK
#define R_OK 2
#endif
#define WSAEAGAIN WSATRY_AGAIN
#define WSAEPROTO WSAEPROTONOSUPPORT
typedef unsigned long in_addr_t;
#define IFNAMSIZ MAX_ADAPTER_NAME_LENGTH
#define IFHWADDRLEN MAX_ADAPTER_ADDRESS_LENGTH
#endif // Posix

#ifndef ulong
#define ulong unsigned long int
#endif
#ifndef ushort
#define ushort unsigned short int
#endif
#ifndef uint
#define uint unsigned int
#endif

typedef enum _NetConnectionType {
  NET_CONN_NONE = 0,
  NET_CONN_FILE,
  NET_CONN_INET,
  NET_CONN_SERV,
  NET_CONN_FILE_SERV
} NetConnectionType;

typedef struct NetAsync NetAsync;
struct NetAsync {
  NetConnectionType type;

  char *name;
  unsigned int ip;
  unsigned short port;

  char *remote;
  unsigned short remote_port;
  int socket;
  int state; // -1 = error, 0 = unconnected, 1 = connected

  void (*cb)( char *buf, uint len, void *user_data );
  void (*conn)( NetAsync *child, void *user_data );
  void *user_data;
  char *inbuf;
  uint inbuf_len;
  char *outbuf;
  uint outbuf_len;
  uint use_signals;

  NetAsync *parent;
  NetAsync *children;
  NetAsync *next;
};

// socket address handling
int net_sockaddr_by_name( struct sockaddr_in *sa, const char *name, ushort port );
int net_sockaddr_by_ip( struct sockaddr_in *sa, in_addr_t ip, ushort port );

/* create a socket on which I can listen and accept connections */
int createListeningSocketOnPort( unsigned short port );
int net_server_new( unsigned short port );

/* returns a new socket no. from listening to socket s if successful, 0 otherwise */
int acceptConnect( int sockfd );
int net_server_accept_connection( int server, char *remote, uint remotelen,
				  ushort *remoteport );

/* returns socket if successful, 0 otherwise */
int makeConnect( const char *hostname, unsigned short port );
int net_connection_new( const char *hostname, unsigned short port );
int net_connection_new_by_ip( unsigned int ip, unsigned short port );
int net_connection_new_by_sockaddr( struct sockaddr_in *sa );

/* returns socket if successful, 0 otherwise */
int makeInetConnect( unsigned int inetaddr, unsigned short port );

/* returns bytes sent if successful, -1 otherwise */
int send_soc( int sockfd, char *line );
int net_connection_send( int sockfd, char *line, int len );

/* returns bytes recieved if successful, -1 otherwise */
int recv_soc( int sockfd, char *line, int len );
int net_connection_recv( int sockfd, char *buf, uint len, int maxiter );

NetAsync *net_async_new_client( const char *host, unsigned short port,
				void (*cb)( char *buf, uint n, void *user_data ),
				void *user_data, uint inbuf_len );
NetAsync *net_async_new_server( unsigned short port,
				void (*conn)( NetAsync *child, void *user_data ),
				void (*cb)( char *buf, uint n, void *user_data ),
				void *user_data, uint inbuf_len );
void net_async_make_async( NetAsync *na );
void net_async_send( NetAsync *na, char *bytes, uint len );
void net_async_delete( NetAsync *na );
int net_async_iteration( NetAsync *na );
void net_async_server_close( NetAsync *na );
int net_async_block_for( NetAsync *na, unsigned long timeout );


// returns a new socket no. from listening to socket s if successful, 0 otherwise
int net_datagram_listener( ushort port, int allow_broadcast );

// Sends data to a host using a UDP
// Returns: 0 if successful; something else on error.
int net_datagram_send( int sockfd, char *buf, int len, char *hname, ushort port,
		       struct sockaddr_in *save );
// Receives data using a UDP.  If src is set, the source
//  address is stored in the location src points to.  The address is
//  caller owned.
// Returns: the number of bytes received, -1 on error.
int net_datagram_receive( int sockfd, char *buf, int len,
			  struct sockaddr_storage *from, int maxiter );

// Tests if a datagram socket has a packet waiting to be received.
// Returns: 1 if there is packet waiting, 0 otherwise.
int net_datagram_will_block( int sockfd );

// Join a multicast group by supplying an ip address
// Returns 1 on success, 0 on failure
int net_mcast_join_by_ip( int sockfd, in_addr_t inetaddr );

// Loin a multicast group by supplying a group name
// returns 1 on success, 0 on failure
int net_mcast_join( int sockfd, char *mcast_group );

// Leave a multicast group by supplying an ip address
// returns 1 on success, 0 on failure
int net_mcast_leave_by_ip( int sockfd, in_addr_t inetaddr );

// Leave a multicast group by supplying a group name
// returns 1 on success, 0 on failure
int net_mcast_leave( int sockfd, char *mcast_group );

int net_mcast_is_loopback( int sockfd );

int net_mcast_set_loopback( int sockfd, int enabled );

// Creates a multicast socket listening on port
// returns a new socket on success, 0 on failure
int net_mcast_listener( ushort port );

// get interface name and address
int net_get_interface( char *name, int nlen, char *hwaddr, int halen );

#endif /* SOC_LIB2_H */
