jl777
7 years ago
5 changed files with 299 additions and 9 deletions
@ -0,0 +1,284 @@ |
|||
/******************************************************************************
|
|||
* Copyright © 2014-2017 The SuperNET Developers. * |
|||
* * |
|||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
|||
* the top-level directory of this distribution for the individual copyright * |
|||
* holder information and the developer policies on copyright and licensing. * |
|||
* * |
|||
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
|||
* SuperNET software, including this file may be copied, modified, propagated * |
|||
* or distributed except according to the terms contained in the LICENSE file * |
|||
* * |
|||
* Removal or modification of this copyright notice is prohibited. * |
|||
* * |
|||
******************************************************************************/ |
|||
|
|||
/**
|
|||
* - we need to include WinSock2.h header to correctly use windows structure |
|||
* as the application is still using 32bit structure from mingw so, we need to |
|||
* add the include based on checking |
|||
* @author - fadedreamz@gmail.com |
|||
* @remarks - #if (defined(_M_X64) || defined(__amd64__)) && defined(WIN32) |
|||
* is equivalent to #if defined(_M_X64) as _M_X64 is defined for MSVC only |
|||
*/ |
|||
#if defined(_M_X64) |
|||
#define WIN32_LEAN_AND_MEAN |
|||
#include <WinSock2.h> |
|||
#endif |
|||
|
|||
int32_t LP_socket(int32_t bindflag,char *hostname,uint16_t port) |
|||
{ |
|||
int32_t opt,sock,result; char ipaddr[64],checkipaddr[64]; struct timeval timeout; |
|||
struct sockaddr_in saddr; socklen_t addrlen,slen; |
|||
addrlen = sizeof(saddr); |
|||
struct hostent *hostent; |
|||
|
|||
/**
|
|||
* gethostbyname() is deprecated and cause crash on x64 windows |
|||
* the solution is to implement similar functionality by using getaddrinfo() |
|||
* it is standard posix function and is correctly supported in win32/win64/linux |
|||
* @author - fadedreamz@gmail.com |
|||
*/ |
|||
#if defined(_M_X64) |
|||
struct addrinfo *addrresult = NULL; |
|||
struct addrinfo *returnptr = NULL; |
|||
struct addrinfo hints; |
|||
struct sockaddr_in * sockaddr_ipv4; |
|||
int retVal; |
|||
int found = 0; |
|||
memset(&hints, 0, sizeof(hints)); |
|||
hints.ai_family = AF_INET; |
|||
hints.ai_socktype = SOCK_STREAM; |
|||
hints.ai_protocol = IPPROTO_TCP; |
|||
#endif |
|||
|
|||
if ( parse_ipaddr(ipaddr,hostname) != 0 ) |
|||
port = parse_ipaddr(ipaddr,hostname); |
|||
|
|||
#if defined(_M_X64) |
|||
retVal = getaddrinfo(ipaddr, NULL, &hints, &addrresult); |
|||
for (returnptr = addrresult; returnptr != NULL && found == 0; returnptr = returnptr->ai_next) { |
|||
switch (returnptr->ai_family) { |
|||
case AF_INET: |
|||
sockaddr_ipv4 = (struct sockaddr_in *) returnptr->ai_addr; |
|||
// we want to break from the loop after founding the first ipv4 address
|
|||
found = 1; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// if we iterate through the loop and didn't find anything,
|
|||
// that means we failed in the dns lookup
|
|||
if (found == 0) { |
|||
printf("getaddrinfo(%s) returned error\n", hostname); |
|||
freeaddrinfo(addrresult); |
|||
return(-1); |
|||
} |
|||
#else |
|||
hostent = gethostbyname(ipaddr); |
|||
if ( hostent == NULL ) |
|||
{ |
|||
printf("gethostbyname(%s) returned error: %d port.%d ipaddr.(%s)\n",hostname,errno,port,ipaddr); |
|||
return(-1); |
|||
} |
|||
#endif |
|||
saddr.sin_family = AF_INET; |
|||
saddr.sin_port = htons(port); |
|||
//#ifdef WIN32
|
|||
// saddr.sin_addr.s_addr = (uint32_t)calc_ipbits("127.0.0.1");
|
|||
//#else
|
|||
|
|||
#if defined(_M_X64) |
|||
saddr.sin_addr.s_addr = sockaddr_ipv4->sin_addr.s_addr; |
|||
// graceful cleanup
|
|||
sockaddr_ipv4 = NULL; |
|||
freeaddrinfo(addrresult); |
|||
#else |
|||
memcpy(&saddr.sin_addr.s_addr,hostent->h_addr_list[0],hostent->h_length); |
|||
#endif |
|||
expand_ipbits(checkipaddr,saddr.sin_addr.s_addr); |
|||
if ( strcmp(ipaddr,checkipaddr) != 0 ) |
|||
printf("bindflag.%d iguana_socket mismatch (%s) -> (%s)?\n",bindflag,checkipaddr,ipaddr); |
|||
//#endif
|
|||
if ( (sock= socket(AF_INET,SOCK_STREAM,0)) < 0 ) |
|||
{ |
|||
if ( errno != ETIMEDOUT ) |
|||
printf("socket() failed: %s errno.%d", strerror(errno),errno); |
|||
return(-1); |
|||
} |
|||
opt = 1; |
|||
slen = sizeof(opt); |
|||
//printf("set keepalive.%d\n",setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(void *)&opt,slen));
|
|||
#ifndef WIN32 |
|||
if ( 1 )//&& bindflag != 0 )
|
|||
{ |
|||
opt = 0; |
|||
getsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(void *)&opt,&slen); |
|||
opt = 1; |
|||
//printf("keepalive.%d\n",opt);
|
|||
} |
|||
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void *)&opt,sizeof(opt)); |
|||
#ifdef __APPLE__ |
|||
setsockopt(sock,SOL_SOCKET,SO_NOSIGPIPE,&opt,sizeof(opt)); |
|||
#endif |
|||
#endif |
|||
if ( bindflag == 0 ) |
|||
{ |
|||
timeout.tv_sec = 10; |
|||
timeout.tv_usec = 0; |
|||
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(void *)&timeout,sizeof(timeout)); |
|||
result = connect(sock,(struct sockaddr *)&saddr,addrlen); |
|||
if ( result != 0 ) |
|||
{ |
|||
if ( errno != ECONNRESET && errno != ENOTCONN && errno != ECONNREFUSED && errno != ETIMEDOUT && errno != EHOSTUNREACH ) |
|||
{ |
|||
//printf("%s(%s) port.%d failed: %s sock.%d. errno.%d\n",bindflag!=0?"bind":"connect",hostname,port,strerror(errno),sock,errno);
|
|||
} |
|||
if ( sock >= 0 ) |
|||
closesocket(sock); |
|||
return(-1); |
|||
} |
|||
timeout.tv_sec = 10000000; |
|||
timeout.tv_usec = 0; |
|||
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(void *)&timeout,sizeof(timeout)); |
|||
} |
|||
else |
|||
{ |
|||
while ( (result= bind(sock,(struct sockaddr*)&saddr,addrlen)) != 0 ) |
|||
{ |
|||
if ( errno == EADDRINUSE ) |
|||
{ |
|||
sleep(1); |
|||
printf("ERROR BINDING PORT.%d. this is normal tcp timeout, unless another process is using port\n",port); |
|||
fflush(stdout); |
|||
sleep(3); |
|||
printf("%s(%s) port.%d try again: %s sock.%d. errno.%d\n",bindflag!=0?"bind":"connect",hostname,port,strerror(errno),sock,errno); |
|||
if ( bindflag == 1 ) |
|||
{ |
|||
closesocket(sock); |
|||
return(-1); |
|||
} |
|||
sleep(13); |
|||
//continue;
|
|||
} |
|||
if ( errno != ECONNRESET && errno != ENOTCONN && errno != ECONNREFUSED && errno != ETIMEDOUT && errno != EHOSTUNREACH ) |
|||
{ |
|||
printf("%s(%s) port.%d failed: %s sock.%d. errno.%d\n",bindflag!=0?"bind":"connect",hostname,port,strerror(errno),sock,errno); |
|||
closesocket(sock); |
|||
return(-1); |
|||
} |
|||
} |
|||
if ( listen(sock,64) != 0 ) |
|||
{ |
|||
printf("listen(%s) port.%d failed: %s sock.%d. errno.%d\n",hostname,port,strerror(errno),sock,errno); |
|||
if ( sock >= 0 ) |
|||
closesocket(sock); |
|||
return(-1); |
|||
} |
|||
} |
|||
#ifdef __APPLE__ |
|||
//timeout.tv_sec = 0;
|
|||
//timeout.tv_usec = 30000;
|
|||
//setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(void *)&timeout,sizeof(timeout));
|
|||
timeout.tv_sec = 0; |
|||
timeout.tv_usec = 10000; |
|||
setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(void *)&timeout,sizeof(timeout)); |
|||
#endif |
|||
return(sock); |
|||
} |
|||
|
|||
int32_t LP_socketsend(int32_t sock,uint8_t *serialized,int32_t len) |
|||
{ |
|||
int32_t numsent,remains,flags = 0; |
|||
#ifndef _WIN32 |
|||
flags = MSG_NOSIGNAL; |
|||
#endif |
|||
remains = len; |
|||
while ( remains > 0 ) |
|||
{ |
|||
if ( (numsent= (int32_t)send(sock,serialized,remains,flags)) < 0 ) |
|||
{ |
|||
if ( errno == EAGAIN || errno == EWOULDBLOCK ) |
|||
{ |
|||
sleep(1); |
|||
continue; |
|||
} |
|||
printf("(%s): numsent.%d vs remains.%d len.%d errno.%d (%s) usock.%d\n",serialized,numsent,remains,len,errno,strerror(errno),sock); |
|||
return(-errno); |
|||
} |
|||
else if ( remains > 0 ) |
|||
{ |
|||
remains -= numsent; |
|||
serialized += numsent; |
|||
if ( remains > 0 ) |
|||
printf("%d LP_socket sent.%d remains.%d of len.%d\n",sock,numsent,remains,len); |
|||
} |
|||
} |
|||
return(len); |
|||
} |
|||
|
|||
int32_t LP_socketrecv(int32_t sock,uint8_t *recvbuf,int32_t maxlen) |
|||
{ |
|||
int32_t recvlen = -1; |
|||
while ( 1 ) |
|||
{ |
|||
if ( (recvlen= (int32_t)recv(sock,recvbuf,maxlen,0)) < 0 ) |
|||
{ |
|||
if ( errno == EAGAIN ) |
|||
{ |
|||
//printf("%s recv errno.%d %s len.%d remains.%d\n",ipaddr,errno,strerror(errno),len,remains);
|
|||
//printf("EAGAIN for len %d, remains.%d\n",len,remains);
|
|||
sleep(1); |
|||
} else return(-errno); |
|||
} else break; |
|||
} |
|||
return(recvlen); |
|||
} |
|||
|
|||
int32_t LP_recvfunc(char *ipaddr,char *str,int32_t len) |
|||
{ |
|||
printf("RECV.(%s) from %s\n",str,ipaddr); |
|||
return(0); |
|||
} |
|||
|
|||
void LP_dedicatedloop(int32_t (*recvfunc)(char *ipaddr,char *str,int32_t len),char **sendstrp,char *ipaddr,uint16_t port) |
|||
{ |
|||
struct pollfd fds; uint8_t *buf; char *str; int32_t len,sock,bufsize,flag,timeout = 10; |
|||
bufsize = IGUANA_MAXPACKETSIZE * 2; |
|||
buf = malloc(bufsize); |
|||
sock = LP_socket(0,ipaddr,port); |
|||
while ( sock >= 0 ) |
|||
{ |
|||
flag = 0; |
|||
memset(&fds,0,sizeof(fds)); |
|||
fds.fd = sock; |
|||
fds.events |= (POLLOUT | POLLIN); |
|||
if ( poll(&fds,1,timeout) > 0 && (fds.revents & POLLOUT) != 0 && (str= *sendstrp) != 0 ) |
|||
{ |
|||
*sendstrp = 0; |
|||
if ( LP_socketsend(sock,(uint8_t *)str,(int32_t)strlen(str+1)) <= 0 ) |
|||
{ |
|||
printf("%s:%u is dead\n",ipaddr,port); |
|||
closesocket(sock); |
|||
sock = -1; |
|||
break; |
|||
} |
|||
flag++; |
|||
} |
|||
if ( flag == 0 ) |
|||
{ |
|||
if ( (fds.revents & POLLIN) != 0 ) |
|||
{ |
|||
if ( (len= LP_socketrecv(sock,buf,bufsize)) > 0 ) |
|||
{ |
|||
(*recvfunc)(ipaddr,(char *)buf,len); |
|||
flag++; |
|||
} |
|||
} |
|||
if ( flag == 0 ) |
|||
usleep(100000); |
|||
} |
|||
} |
|||
free(buf); |
|||
} |
|||
|
Loading…
Reference in new issue