#include #include #include #include #include #include #include #include #include #include "socket_wrapper.h" int getBufferSizeFrom(int sock){ int buffer_sz; socklen_t len = sizeof(buffer_sz); //getsockopt is thread-safe if(getsockopt(sock,SOL_SOCKET,SO_SNDBUF,&buffer_sz,&len) < 0){ perror("failed to get sock buffer size: getsockopt"); buffer_sz = DEFAULT_BUF_SIZE;/*set to default*/ } if(buffer_sz < MINIMUM_BUF_SIZE) buffer_sz = MINIMUM_BUF_SIZE; return buffer_sz; } ssize_t timeout_recv(int fd,void * buf,size_t n,int timeout) { ssize_t ret = 0; int poll_ret; int try = 0; struct pollfd fd_single; timeout = timeout * 1000; if (n == 0) return 0; for(;;){ fd_single.fd = fd; fd_single.events = POLL_IN; poll_ret = (poll(&fd_single,1,timeout)); if (poll_ret < 0){ fprintf(stderr,"timeout %d\n",timeout); return -1;} else if(poll_ret == 0) return -2; if (fd_single.revents & POLLHUP) //We'll treat hangups state like timeouts state. return -2; if ((fd_single.revents & POLLERR) || (fd_single.revents & POLLNVAL)) return -1; if (fd_single.revents & POLL_IN){ ret = recv(fd,buf,n,0); if(ret != 0) return ret; //try 3 times if (try < 3){ try++; timeout /= 2; continue; } return -2; } } assert(0 && "unreachable"); } ssize_t recv_until_byte(int fd,void * buf, size_t n,int timeout){ ssize_t cur = 0; uint8_t * b = buf; while (cur < n) { ssize_t r = timeout_recv(fd,&b[cur],n-cur,timeout); if (r < 0){ return r; } cur += r; } assert(cur == n); return cur; } int getsockaddrbyname(int domain,int type, int protocol, const char * hostname_str, struct sockaddr * retaddr){ struct addrinfo hints; struct addrinfo * result, *entry; int ret, i; memset(&hints,0,sizeof(hints)); hints.ai_family = domain; hints.ai_socktype = type; hints.ai_flags = 0; hints.ai_protocol = protocol; //try 5 times for (i = 0; i < 5; i++) { ret = getaddrinfo(hostname_str,NULL,&hints,&result); if(ret == EAI_AGAIN) continue; else if (ret != 0) return ret; break; } if (ret != 0) return ret; //maybe name server doesn't work properly. for (entry = result; entry != NULL; entry = entry->ai_next){ memcpy(retaddr,entry->ai_addr,sizeof(*retaddr)); } freeaddrinfo(result); return ret; }