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