./ MultiCS.r69 / sockets.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


#ifdef WIN32
#include <windows.h>
#include <mstcpip.h>
#else
#endif

#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>


#include "common.h"
#include "tools.h"
#include "sockets.h"

// CONVERTION
uint32 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  ;

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


/* 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;
}

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

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

int CreateServerSockUdp(int port)
{
  int reuse=1;
  int sock;
  struct sockaddr_in saddr;

  sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  if (sock==INVALID_SOCKET) {
    printf("Error in INP int creation\n");
    return(INVALID_SOCKET);
  }
  saddr.sin_family = PF_INET;
  saddr.sin_addr.s_addr = htonl( INADDR_ANY );
  saddr.sin_port = htons(port);

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

  if ( bind( sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) == -1 ) {
    printf("Error in bind INP int\n");
    close(sock);
    return(INVALID_SOCKET);
  }

  return( sock );
}

int CreateClientSockUdp()
{
  int sock;
  sock = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
  if (sock==INVALID_SOCKET) {
    printf("failed to create udp socket (errno=%d)\n",errno);
    return INVALID_SOCKET;
  }
  return sock;
}


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

int CreateServerSockTcp(int port)
{
  int sock;
  struct sockaddr_in saddr;
 // Set up server
  saddr.sin_family = PF_INET;
  saddr.sin_addr.s_addr = INADDR_ANY;
  saddr.sin_port = htons(port);
  sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  if ( sock==INVALID_SOCKET )
  {
    printf("socket() failed\n");
    return INVALID_SOCKET;
  }

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

  if ( bind(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr))==SOCKET_ERROR )
  {
    close(sock);
    printf("bind() failed (Port:%d)\n",port);
    return INVALID_SOCKET;
  }
  if (listen(sock, 1) == SOCKET_ERROR)
  {
    close(sock);
    printf("listen() failed\n");
    return INVALID_SOCKET;
  }
  return sock;
}


int CreateClientSockTcp(unsigned int netip, int port)
{
  int sock;
  struct sockaddr_in saddr;
         
  sock = socket(PF_INET,SOCK_STREAM,0);
  if( sock<0 ) {
    //printf("Invalid Socket\n");
    return INVALID_SOCKET;
  }

  int optVal = TRUE;
  if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, sizeof(int))==-1) {
#ifdef WIN32
    closesocket(sock);
#else
    close(sock);
#endif
    return INVALID_SOCKET;
  }

  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 INVALID_SOCKET;
  }
  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 INVALID_SOCKET;

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

	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 INVALID_SOCKET;
			}
			else if (ret == 0) {
				errno = ETIMEDOUT;
				close(sockfd);
				return INVALID_SOCKET;
			}
			else {
				if ( pfd.revents && (pfd.revents & POLLOUT) ) {
					len = sizeof(error);
					if ( getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) ) {
						close(sockfd);
						return INVALID_SOCKET;
					}
					if (error) {
						errno = error;
						close(sockfd);
						return INVALID_SOCKET;
					}
				}
				else {
					errno = ECONNABORTED;
					close(sockfd);
					return INVALID_SOCKET;
				}
			}
		}
		else if (errno!=EISCONN) {
			close(sockfd);
			return INVALID_SOCKET;
		}
	}

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

	return sockfd;
}

int CreateServerSockTcp_nonb(int port)
{
  int sock;
  struct sockaddr_in saddr;
 // Set up server
  saddr.sin_family = AF_INET;
  saddr.sin_addr.s_addr = INADDR_ANY;
  saddr.sin_port = htons(port);

  struct protoent *ptrp;
  int p_proto;
  if ((ptrp = getprotobyname("tcp"))) p_proto = ptrp->p_proto; else p_proto = 6;

  sock = socket(AF_INET, SOCK_STREAM, p_proto);
  if ( sock==INVALID_SOCKET )
  {
    printf("socket() failed\n");
    return INVALID_SOCKET;
  }

  int flgs=fcntl(sock,F_GETFL);
  if(flgs<0) {
	close(sock);
	printf("socket: fcntl GETFL failed\n");
    return INVALID_SOCKET;
  }
  if ( fcntl(sock,F_SETFL,flgs|O_NONBLOCK)<0 ) {
	close(sock);
	printf("socket: fcntl SETFL failed\n");
    return INVALID_SOCKET;
  }

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

  if ( bind(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr))==SOCKET_ERROR )
  {
    close(sock);
    printf("bind() failed (Port:%d)\n",port);
    return INVALID_SOCKET;
  }
  if (listen(sock, SOMAXCONN) == SOCKET_ERROR)
  {
    close(sock);
    printf("listen() failed\n");
    return INVALID_SOCKET;
  }
  return sock;
}


int recv_nonb1(int sock,uint8 *buf,int len,int timeout)
{
	int retval;
    int index = 0;

	uint32 ticks = GetTickCount()+timeout; // timeout ~ 2sec
	uint32 now;
	do {
		now = GetTickCount();
		if ( ticks<now ) {
			//printf("recv_nonb(): receive timeout (got %d from %d)\n",index,len);
			return -2; // timeout
		}
/*
		errno = 0;
		retval = fdstatus_readt(sock,ticks-now);
		switch (retval) {
			case -1: // error
				if ( (errno==EINTR)||(errno==EAGAIN) ) continue;
				return -2;
			case 0: // timeout
				continue;
				return -2;
			default: // nb descriptors
*/
				do {
					errno = 0;
			  		retval = recv(sock, buf+index, len-index, MSG_NOSIGNAL|MSG_DONTWAIT);
				} while(retval<0 && errno==EINTR);
				switch (retval) {
					case -1:
						if ( (errno==0)||(errno==110)||(errno==EAGAIN)||(errno==EWOULDBLOCK)||(errno==EINTR) ) continue;
						//printf("recv_nonb(): recv() error(%d)\n", errno);
						return -1;
					case 0:
						if (!recv(sock, buf+index, len-index, MSG_NOSIGNAL|MSG_DONTWAIT)) { // retry
							//if (index) printf("Gotten data %d\n", index);
							//printf("recv_nonb err = 0 errno(%d)\n", errno);
							return -1;
						}
						else {
							//printf("recv_nonb(): err = 0 errno(%d) -> Saved\n", errno);
							return -2;
						}
						if (errno==EINTR) continue; //return index;
						else if (index==len) return index;
						else {
							//printf("recv_nonb(): err = 0 errno(%d)\n", errno);
							return -1;
						}
					default: index+=retval;
				}
//		}
	} while (index<len);
	return index; 
}

int recv_nonb2(int sock,uint8 *buf,int len,int timeout)
{
	int retval;
    int index = 0;

	uint32 ticks = GetTickCount()+timeout; // timeout ~ 2sec
	uint32 now;
	do {
		now = GetTickCount();
		if ( ticks<now ) {
			//printf("socket: receive timeout\n");
			return -2; // timeout
		}
		errno = 0;
		retval = fdstatus_readt(sock,ticks-now);
		switch (retval) {
			case -1: // error
				if (errno==EINTR) continue;
				if ( (errno==EAGAIN)||(errno==EWOULDBLOCK) ) continue;
				if ( (errno==0)||(errno==110) ) return -2;
				return -1;
			case 0: // timeout
				return -2;
			default: // nb descriptors
		  		retval = recv(sock, buf+index, len-index, MSG_NOSIGNAL);
				switch (retval) {
					case -1:
						if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) return -1;
					case 0:
						errno = ECONNRESET;
						return -1;
					default: index+=retval;
				}
		}
	} while (index<len);
	return index; 
}


// >0 : received ok
// =0 : disconnected
// =-1 : error
// =-2 : timeout
int recv_nonb(int sock,uint8 *buf,int len,int timeout)
{
	int ret;
    int index = 0;
	uint32 last = GetTickCount()+timeout;
	while (1) {
		uint32 now = GetTickCount();
		if (now>last) return -2; // timeout
		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 return -1; // error
	}
}


int send_nonb2(int sock,uint8 *buf,int len,int to)
{
	int retval;
	int index = 0;

	uint32 ticks = GetTickCount()+to;
	uint32 now;
	do {

		now = GetTickCount();
		if ( ticks<now ) {
			printf("send error timeout\n");
			return -2; // timeout
		}

		fd_set writefds;
		struct timeval timeout;
		timeout.tv_usec = (to%1000)*1000;
		timeout.tv_sec = to/1000;
	    FD_ZERO(&writefds);
	    FD_SET(sock, &writefds);
        retval = select( sock+1, NULL, &writefds, NULL, &timeout );

		switch (retval) {
			case -1: // error
				if ( (errno == EINTR)||(errno==EWOULDBLOCK)||(errno==EAGAIN)||(errno==0) ) continue;
				printf("send error %d(%d)\n",retval,errno);
				return retval; // disconnection
			case 0: // timeout
				printf("send error timeout\n");
				return retval;
			default: // nb. desriptors
				do {
			  		retval = send(sock, buf+index, len-index, MSG_NOSIGNAL|MSG_DONTWAIT);
				} while( (retval<0)&&((errno==EINTR)||(errno==EWOULDBLOCK)||(errno==EAGAIN)||(errno==0)) );
				if(retval>0) index+=retval;
		}
	} while (retval>0 && index<len);
	if (index!=len) printf("send_nonb err %d!=%d\n",index,len);
	if (retval>0) return index; else return -1;
}


int send_nonb(int sock,uint8 *buf,int len,int to)
{
	int remain, got;
	uint8 *ptr;
	int  error;
	struct timeval timeout;

    error           = 0;
	timeout.tv_usec = (to%1000)*1000;
	timeout.tv_sec = to/1000;
    remain = len;
    ptr    = buf;


	uint32 ticks = GetTickCount()+to;
	uint32 now;
    while (remain) {
		now = GetTickCount();
		if ( ticks<now ) {
			//printf("send_nonb(): timeout\n");
			return FALSE; // timeout
		}
/*	    FD_ZERO(&writefds);
	    FD_SET(sock, &writefds);
        error = select( sock+1, NULL, &writefds, NULL, &timeout );
//        if (error == 0) {
//            errno = ETIMEDOUT;
//            return FALSE;

//        } else 

		if (error < 0) {
			if ( (!errno)||(errno==EINTR)||(errno==EWOULDBLOCK)||(errno==EAGAIN) ) continue;
			return -1;
        }
		else {
*/
            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       &&
                errno != 0
            ) {
				//printf(" send_nonb: error(%d) (sent %d from %d)\n", errno, len-remain,len );
                return FALSE;
            }
//        }
    }
    return TRUE;
}