./ MultiCS.r82 / sockets.c
#include "common.h"

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>


#ifdef WIN32

#include <windows.h>
#include <sys/types.h>
#include <sys/_default_fcntl.h>
#include <sys/poll.h>
#include <cygwin/types.h>
#include <cygwin/socket.h>
#include <sys/errno.h>
#include <cygwin/in.h>
#include <sched.h>
#include <netdb.h>
#include <netinet/tcp.h>

#else

#include <sys/time.h>
#include <time.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <poll.h>
#include <fcntl.h>
#include <errno.h>

#endif


#include "debug.h"
#include "tools.h"
#include "sockets.h"

// CONVERTION
uint32_t hostname2ip( const char *hostname )
{
	struct hostent *phostent;
	unsigned int hostaddr;
	unsigned char *temp;

	phostent = gethostbyname(hostname);
	if (phostent==NULL) {
		//printf(" Error gethostbyname(%s)\n",hostname);
		return 0;
	}
	temp = ((unsigned char *) phostent->h_addr_list[0]);
	hostaddr = *(unsigned int*)temp;//   *(*temp<<24) + ( *(temp+1)<<16 ) + ( *(temp+2)<<8 ) + (*(temp+3));
	//printf("IP = %03d.%03d.%03d.%03d\n", *temp, *(temp+1), *(temp+2), *(temp+3));
	//if (hostaddr==0x7F000001) hostaddr=0;
	return hostaddr;
}

char *iptoa(char *dest, unsigned int ip )
{
  sprintf(dest,"%d.%d.%d.%d", 0xFF&(ip), 0xFF&(ip>>8), 0xFF&(ip>>16), 0xFF&(ip>>24));
  return dest;
}

char ip_string[3][0x40];
int ip_string_counter = 0;
char *ip2string( unsigned int ip )
{
	ip_string_counter++; if (ip_string_counter>2) ip_string_counter = 0;
	return iptoa(ip_string[ip_string_counter], ip );
}

////////////////////////////////////////////////////////////////////////////////
// SOCKETS FUNCTIONS
////////////////////////////////////////////////////////////////////////////////

int fdstatus_read(int s)
{
  fd_set readfds;
  int retval;
  struct timeval timeout;
  FD_ZERO(&readfds);
  FD_SET(s, &readfds);
  timeout.tv_usec = 0;
  timeout.tv_sec = 0;
  //do {
  retval = select(s+1, &readfds, NULL, NULL,&timeout); 
  //} while(retval<0 && errno==EINTR);
  return retval;
}

int fdstatus_readt(int s, int tim)
{
  fd_set readfds;
  int retval;
  struct timeval timeout;

	FD_ZERO(&readfds);
	FD_SET(s, &readfds);
	timeout.tv_usec = (tim%1000)*1000;
	timeout.tv_sec = tim/1000;
 // do {
	retval = select(s+1, &readfds, NULL, NULL,&timeout); 
  //} while(retval<0 && errno==EINTR);
  return retval;
}

int fdstatus_writet(int s, int tim)
{
  fd_set writefds;
  int retval;
  struct timeval timeout;

	FD_ZERO(&writefds);
	FD_SET(s, &writefds);
	timeout.tv_usec = (tim%1000)*1000;
	timeout.tv_sec = tim/1000;
  do {
	retval = select(s+1, NULL, &writefds, NULL,&timeout); 
  } while( (retval<0) && ( (errno==EINTR)||(errno==EAGAIN) ) );

  return retval;
}

int fdstatus_write(int s)
{
  fd_set writefds;
  int retval;
  struct timeval timeout;
  FD_ZERO(&writefds);
  FD_SET(s, &writefds);
  timeout.tv_sec = 0;
  timeout.tv_usec = 100;
  do {
	retval = select(s+1, NULL, &writefds, NULL,&timeout); 
  } while ( (retval<0) && ( (errno==EINTR)||(errno==EAGAIN) ) );
  return retval;
}


int fdstatus_accept(int s)
{
  fd_set fd;
  int retval;
  struct timeval timeout;

  FD_ZERO(&fd);
  FD_SET(s, &fd);
  timeout.tv_usec = 1000;
  timeout.tv_sec = 0;
  do {
	retval = select(s+1, &fd, NULL, NULL,&timeout); 
  } while(retval<0 && errno==EINTR);
  return retval;
}


int SetSocketTimeout(int connectSocket, int milliseconds)
{
    struct timeval tv;

	tv.tv_sec = milliseconds / 1000 ;
	tv.tv_usec = ( milliseconds % 1000) * 1000  ;

	setsockopt (connectSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof tv);
	setsockopt (connectSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof tv);
	return 0;
}

/* Disable the Nagle (TCP No Delay) algorithm */
int SetSocketNoDelay(int sock)
{
	int val = 1;
	if ( setsockopt( sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) < 0) return -1; 
	return 0;
}

int SetSocketKeepalive(int sock)
{
	int val = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) < 0) return -1; 
/*
	val = 60;
	if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&val, sizeof(val)) < 0) return -1;
	val = 30;
	if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (void*)&val, sizeof(val)) < 0) return -1;
	val = 4;
	if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (void*)&val, sizeof(val)) < 0) return -1;
*/
	return 0;
}

void SetSoketNonBlocking(int fd)
{
	int flags = fcntl( fd, F_GETFL );
	fcntl( fd, F_SETFL, flags|O_NONBLOCK );
}

/*
int SetSocketPriority(int sock)
{
	setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void *)&cfg->netprio, sizeof(ulong));
}
*/

int SetSocketReuseAddr(int sock)
{
	int reuse = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int))< 0) return 0; else return 1;
}


///////////////////////////////////////////////////////////////////////////////
// UDP CONNECTION
///////////////////////////////////////////////////////////////////////////////

int CreateServerSockUdp(int port, uint32_t ip)
{
	int sock;
	sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sock==-1) {
		printf("socket() failed\n");
		return -1;
	}

	struct sockaddr_in saddr;
	memset((char *)&saddr, 0, sizeof(saddr));
	saddr.sin_family = PF_INET;
	if (ip) saddr.sin_addr.s_addr = ip; else saddr.sin_addr.s_addr = htonl( INADDR_ANY );
	if (port) saddr.sin_port = htons(port);

	int reuse = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int))< 0) {
		close(sock);
		printf("setsockopt() failed\n");
		return -1;
	}

	if ( bind( sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) == -1 ) {
		close(sock);
		//if (errno==99) pthread_exit(0); /////////////////////////// XXX
		//printf("bind() failed\n");
		return -1;
	}

	return sock;
}

int CreateClientSockUdp(int port, uint32_t ip)
{
	int sock = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
	if (sock==-1) {
		printf("failed to create udp socket (errno=%d)\n",errno);
		return -1;
	}
	if (port && ip) {
		struct sockaddr_in saddr;
		saddr.sin_family = PF_INET;
		saddr.sin_port = htons(port);
		saddr.sin_addr.s_addr = ip;
		if ( connect(sock,(struct sockaddr *)&saddr,sizeof(struct sockaddr_in)) != 0) {
			close(sock);
			return -1;
		}
	}
	return sock;
}


///////////////////////////////////////////////////////////////////////////////
// TCP CONNECTION
///////////////////////////////////////////////////////////////////////////////

int CreateServerSockTcp(int port, uint32_t ip)
{
	int sock;
	sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if ( sock==-1 ) {
		printf("socket() failed\n");
		return -1;
	}

	struct sockaddr_in saddr;
	saddr.sin_family = PF_INET;
	if (ip) saddr.sin_addr.s_addr = ip; else saddr.sin_addr.s_addr = INADDR_ANY;
	saddr.sin_port = htons(port);

	int reuse=1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int))< 0) {
		close(sock);
		printf("setsockopt(SO_REUSEADDR) failed\n");
		return -1;
	}

	if ( bind(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr))==SOCKET_ERROR ) {
		close(sock);
		//if (errno==99) pthread_exit(0);
		//printf("bind() failed (Port:%d)\n",port);
		return -1;
	}

	if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
		close(sock);
		printf("listen() failed\n");
		return -1;
	}
	return sock;
}

int CreateClientSockTcp(uint32_t netip, int port)
{
	int sock = socket(PF_INET,SOCK_STREAM,0);
	if( sock<0 ) {
		//printf("Invalid Socket\n");
		return -1;
	}

	struct sockaddr_in saddr;
	memset(&saddr,0, sizeof(saddr));
	saddr.sin_family = PF_INET;
	saddr.sin_port = htons(port);
	saddr.sin_addr.s_addr = netip;
	if ( connect(sock,(struct sockaddr *)&saddr,sizeof(struct sockaddr_in)) != 0 ) {
		close(sock);
		return -1;
	}
	return sock;
}


///////////////////////////////////////////////////////////////////////////////
// NON BLOCKED TCP CONNECTION
///////////////////////////////////////////////////////////////////////////////

int CreateClientSockTcp_nonb(unsigned int netip, int port)
{
	int ret, flags, error;
	socklen_t len;
	int sockfd;
	struct sockaddr_in saddr;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if( sockfd<0 ) return -1;

	flags = fcntl(sockfd,F_GETFL);
	if (flags<0) {
		close(sockfd);
		return -1;
 	}
	if ( fcntl(sockfd,F_SETFL,flags|O_NONBLOCK)<0 ) {
		close(sockfd);
		return -1;
	}

	memset(&saddr,0, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(port);
	saddr.sin_addr.s_addr = netip;

	do {
		ret = connect( sockfd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in) );
	} while ( ret && (errno==EINTR) );

	if (ret) {
		if (errno==EINPROGRESS || errno==EALREADY) {
			struct pollfd pfd;
			pfd.fd = sockfd;
			pfd.events = POLLOUT;
			errno = 0;
			do {
				ret = poll(&pfd, 1, 1000);
			} while (ret < 0 && errno == EINTR);
			if (ret < 0) {
				close(sockfd);
				return -1;
			}
			else if (ret == 0) {
				errno = ETIMEDOUT;
				close(sockfd);
				return -1;
			}
			else {
				if ( pfd.revents && (pfd.revents & POLLOUT) ) {
					len = sizeof(error);
					if ( getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) ) {
						close(sockfd);
						return -1;
					}
					if (error) {
						errno = error;
						close(sockfd);
						return -1;
					}
				}
				else {
					errno = ECONNABORTED;
					close(sockfd);
					return -1;
				}
			}
		}
		else if (errno!=EISCONN) {
			close(sockfd);
			return -1;
		}
	}

	flags &=~ O_NONBLOCK;
	fcntl(sockfd, F_SETFL, flags);	/* restore file status flags */

	return sockfd;
}

int CreateServerSockTcp_nonb(int port, uint32_t ip)
{
	struct protoent *ptrp;
	int p_proto;
	if ((ptrp = getprotobyname("tcp"))) p_proto = ptrp->p_proto; else p_proto = 6;

	int sock;
	sock = socket(AF_INET, SOCK_STREAM, p_proto);
	if ( sock<0 ) {
		printf("socket() failed\n");
		return -1;
	}

	int flgs=fcntl(sock,F_GETFL);
	if(flgs<0) {
		close(sock);
		printf("socket: fcntl GETFL failed\n");
		return -1;
	}

	if ( fcntl(sock,F_SETFL,flgs|O_NONBLOCK)<0 ) {
		close(sock);
		printf("socket: fcntl SETFL failed\n");
		return -1;
	}

	int reuse=1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int))< 0) {
		close(sock);
		printf("setsockopt(SO_REUSEADDR) failed\n");
		return -1;
	}

	struct sockaddr_in saddr;
	saddr.sin_family = AF_INET;
	if (ip) saddr.sin_addr.s_addr = ip; else saddr.sin_addr.s_addr = INADDR_ANY;
	saddr.sin_port = htons(port);
	if ( bind(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr))==SOCKET_ERROR ) {
		close(sock);
		//if (errno==99) pthread_exit(0);
		//printf("bind() failed (Port:%d, errno=%d)\n",port,errno);
		return -1;
	}

	if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
		close(sock);
		printf("listen() failed\n");
		return -1;
	}
	return sock;
}

// >0 : received ok
// =0 : disconnected
// =-1 : error
// =-2 : timeout
int recv_nonb(int sock,uint8_t *buf,int len,int timeout)
{
	int ret;
    int index = 0;
	uint32_t now = GetTickCount();
	uint32_t last = now + timeout;
	while (1) {
		struct pollfd pfd;
		pfd.fd = sock;
		pfd.events = POLLIN | POLLPRI;
		ret = poll(&pfd, 1, last-now);
		if (ret>0) {
			if ( pfd.revents & (POLLIN|POLLPRI) ) {
				ret = recv( sock, buf+index, len-index, MSG_NOSIGNAL|MSG_DONTWAIT );
				if (ret>0) {
					index+=ret;
					if (index==len) return index;
				}
				else if (ret==0) return 0; // disconected
				else if ( (ret==-1)&&(errno!=EAGAIN)&&(errno!=EWOULDBLOCK)&&(errno!=EINTR) ) return -1; // error
			}
			if ( pfd.revents & (POLLHUP|POLLNVAL) ) return 0; // disconnected
		}
		else if (ret==0) return -2; // timeout
		else if ( (errno!=EINTR)&&(errno!=EAGAIN) ) return -1; // error

		now = GetTickCount();
		if (now>last) return -2; // timeout
	}
}

int send_nonb00(int sock,uint8_t *buf,int len,int to)
{
	if (sock<=0) return FALSE;
	int remain = len;
	uint8_t *ptr = buf;
	while (remain) {
		struct pollfd pfd;
		pfd.fd = sock;
		pfd.events = POLLOUT;
		int ret = poll(&pfd, 1, 100);
		if (ret==0) return FALSE;
		else if ( (ret==-1)&&(errno!=EINTR)&&(errno!=EAGAIN) ) return FALSE;
		else if ( pfd.revents & POLLOUT ) {
			int got = send( sock, (void *) ptr, (size_t) remain, MSG_NOSIGNAL|MSG_DONTWAIT);
			if (got >= 0) {
				remain -= got;
				ptr    += got;
			} else if (
				errno != EWOULDBLOCK &&
				errno != EAGAIN      &&
				errno != EINTR
			) {
				debugf(getdbgflag(DBG_ERROR,0,0)," send_nonb(%d): error(%d) (sent %d from %d)\n", sock, errno, len-remain,len );
				return FALSE;
			}
		}
		else if ( pfd.revents & (POLLHUP|POLLERR|POLLNVAL) ) return FALSE;
	}
	return TRUE;
}

int send_nonb(int sock,uint8_t *buf,int len,int to)
{
	if (sock<=0) return FALSE;
	int remain = len;
	uint8_t *ptr = buf;

	int got = send( sock, (void *) ptr, (size_t) remain, MSG_NOSIGNAL|MSG_DONTWAIT);
	if (got >= 0) {
				remain -= got;
				ptr    += got;
	} else if (
		errno != EWOULDBLOCK &&
		errno != EAGAIN      &&
		errno != EINTR
	) {
		//debugf(getdbgflag(DBG_ERROR,0,0)," send_nonb(%d): error(%d) (sent %d from %d)\n", sock, errno, len-remain,len );
		return FALSE;
	}

	while (remain) {
		struct pollfd pfd;
		pfd.fd = sock;
		pfd.events = POLLOUT;
		int ret = poll(&pfd, 1, 100);
		if (ret==0) return FALSE;
		else if ( (ret==-1)&&(errno!=EINTR)&&(errno!=EAGAIN) ) return FALSE;
		else if ( pfd.revents & POLLOUT ) {
			int got = send( sock, (void *) ptr, (size_t) remain, MSG_NOSIGNAL|MSG_DONTWAIT);
			if (got >= 0) {
				remain -= got;
				ptr    += got;
			} else if (
				errno != EWOULDBLOCK &&
				errno != EAGAIN      &&
				errno != EINTR
			) {
				//debugf(getdbgflag(DBG_ERROR,0,0)," send_nonb(%d): error(%d) (sent %d from %d)\n", sock, errno, len-remain,len );
				return FALSE;
			}
		}
		else if ( pfd.revents & (POLLHUP|POLLERR|POLLNVAL) ) return FALSE;
	}
	return TRUE;
}