// Written by Matt Conover in December 2004
#ifndef SOCK_H
#define SOCK_H

#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#define GetLastSocketError WSAGetLastError
#define EWOULDBLOCK WSAEWOULDBLOCK
#else // UNIX

#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>

#define GetLastError() errno
#define GetLastSocketError() errno
#define closesock(sock) close(sock)
#define ioctlsocket(sock, cmd, arg) ioctl(sock, cmd, arg)

typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;

#define INVALID_HANDLE_VALUE -1
#define SOCKET_ERROR -1

#endif // WIN32

#define MAX_SOCKETS 256

typedef struct _SOCK {
	int id;
	SOCKET socket;
	struct _SOCK *forward_socket; // forward anything from 'socket' to here
	int is_udp;
	int is_listening;
	int is_connecting;
	int is_connected; // the final state of both listening and connecting sockets
	unsigned long dst_addr;
	unsigned short dst_port;
	char *buf;
	int buf_size;
} SOCK;

void sock_new_sockets(SOCK socks[], unsigned int socks_size);
int sock_get_socket(SOCK socks[], unsigned int socks_size, int use_udp);
int sock_get_listening_socket(SOCK socks[], unsigned int socks_size, int use_udp);
int sock_get_nonblocking_listening_socket(SOCK socks[], unsigned int socks_size, int use_udp);
int sock_get_connecting_socket(SOCK socks[], unsigned int socks_size);
int sock_get_nonblocking_connecting_socket(SOCK socks[], unsigned int socks_size);
int sock_connect(SOCK *sock, SOCKADDR_IN *dst_addr);
int sock_convert_to_nonblocking_socket(SOCK *sock);
int sock_accept_client(SOCK socks[], unsigned int socks_size, SOCKET listen_sock, SOCKADDR_IN *client_addr);
int sock_accept_nonblocking_client(SOCK socks[], unsigned int socks_size, SOCKET listen_sock, SOCKADDR_IN *client_addr);
SOCKET sock_get_max_socket(SOCK socks[], unsigned int socks_size);
int sock_send(SOCK *sock, char *buf, unsigned int buf_size);
int sock_recv(SOCK *sock, char *buf, unsigned int buf_size, int recv_exact);
void sock_close_socket(SOCK *sock);
void sock_close_sockets(SOCK socks[], unsigned int socks_size);

#endif // SOCK_H
