diff --git a/configure.ac b/configure.ac index fcdb312a..305a1ad0 100644 --- a/configure.ac +++ b/configure.ac @@ -35,7 +35,7 @@ AC_CHECK_HEADERS(stdio.h stdlib.h fcntl.h sys/time.h unistd.h) AC_CHECK_HEADERS(ctype.h errno.h byteswap.h string.h time.h) AC_CHECK_HEADERS(endian.h sys/endian.h arpa/inet.h syslog.h) AC_CHECK_HEADERS(alloca.h pthread.h stdio.h math.h) -AC_CHECK_HEADERS(sys/types.h sys/socket.h) +AC_CHECK_HEADERS(sys/types.h sys/socket.h netdb.h) AC_CHECK_HEADERS(stdint.h netinet/in.h netinet/tcp.h) PTHREAD_LIBS="-lpthread" diff --git a/src/libckpool.c b/src/libckpool.c index 27ba988d..9d21c482 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -313,6 +314,80 @@ void block_socket(int fd) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } +int connect_socket(char *url, char *port) +{ + struct addrinfo servinfobase, *servinfo, hints, *p; + int sockd = -1; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + servinfo = &servinfobase; + + if (getaddrinfo(url, port, &hints, &servinfo) != 0) { + LOGWARNING("Failed to resolve (?wrong URL) %s:%s", url, port); + goto out; + } + + for (p = servinfo; p != NULL; p = p->ai_next) { + sockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (sockd == -1) { + LOGDEBUG("Failed socket"); + continue; + } + + /* Iterate non blocking over entries returned by getaddrinfo + * to cope with round robin DNS entries, finding the first one + * we can connect to quickly. */ + noblock_socket(sockd); + if (connect(sockd, p->ai_addr, p->ai_addrlen) == -1) { + struct timeval tv_timeout = {1, 0}; + int selret; + fd_set rw; + + if (!sock_connecting()) { + close(sockd); + LOGDEBUG("Failed sock connect"); + continue; + } +retry: + FD_ZERO(&rw); + FD_SET(sockd, &rw); + selret = select(sockd + 1, NULL, &rw, NULL, &tv_timeout); + if (selret > 0 && FD_ISSET(sockd, &rw)) { + socklen_t len; + int err, n; + + len = sizeof(err); + n = getsockopt(sockd, SOL_SOCKET, SO_ERROR, (void *)&err, &len); + if (!n && !err) { + LOGDEBUG("Succeeded delayed connect"); + block_socket(sockd); + break; + } + } + if (selret < 0 && interrupted()) + goto retry; + close(sockd); + sockd = -1; + LOGDEBUG("Select timeout/failed connect"); + continue; + } + LOGDEBUG("Succeeded immediate connect"); + if (sockd >= 0) + block_socket(sockd); + + break; + } + if (p == NULL) { + LOGNOTICE("Failed to connect to %s:%s", url, port); + sockd = -1; + } + freeaddrinfo(servinfo); +out: + return sockd; +} + /* Align a size_t to 4 byte boundaries for fussy arches */ void align_len(size_t *len) { diff --git a/src/libckpool.h b/src/libckpool.h index 72f4f753..dbdb3bfc 100644 --- a/src/libckpool.h +++ b/src/libckpool.h @@ -137,7 +137,7 @@ bool extract_sockaddr(char *url, char **sockaddr_url, char **sockaddr_port); void keep_sockalive(int fd); void noblock_socket(int fd); void block_socket(int fd); -bool sock_connecting(void); +int connect_socket(char *url, char *port); void align_len(size_t *len); void __bin2hex(uchar *s, const uchar *p, size_t len);