[PATCH] fix connect for multi IP dns
Alexander Malysh <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi, attached patch should fix connect failure if DNS returns multiple IPs for a hostname. This patch fixes this issue for blocking connect but only partially fixes it for nonblocking connect due to design limitation. Please try it and vote. Thanks, Alex
socket.diff
(application/octet-stream, 15.5 KB)
diff --git a/gwlib/socket.c b/gwlib/socket.c index 78f2683..6e9033b 100644 --- a/gwlib/socket.c +++ b/gwlib/socket.c @@ -1,58 +1,58 @@ -/* ==================================================================== - * The Kannel Software License, Version 1.0 - * - * Copyright (c) 2001-2009 Kannel Group - * Copyright (c) 1998-2001 WapIT Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Kannel Group (http://www.kannel.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Kannel" and "Kannel Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please - * contact [email protected]. - * - * 5. Products derived from this software may not be called "Kannel", - * nor may "Kannel" appear in their name, without prior written - * permission of the Kannel Group. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Kannel Group. For more information on - * the Kannel Group, please see <http://www.kannel.org/>. - * - * Portions of this software are based upon software originally written at - * WapIT Ltd., Helsinki, Finland for the Kannel project. - */ +/* ==================================================================== + * The Kannel Software License, Version 1.0 + * + * Copyright (c) 2001-2004 Kannel Group + * Copyright (c) 1998-2001 WapIT Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Kannel Group (http://www.kannel.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Kannel" and "Kannel Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact [email protected]. + * + * 5. Products derived from this software may not be called "Kannel", + * nor may "Kannel" appear in their name, without prior written + * permission of the Kannel Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Kannel Group. For more information on + * the Kannel Group, please see <http://www.kannel.org/>. + * + * Portions of this software are based upon software originally written at + * WapIT Ltd., Helsinki, Finland for the Kannel project. + */ #include <ctype.h> #include <errno.h> @@ -159,7 +159,7 @@ int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, co struct sockaddr_in o_addr; struct hostent hostinfo; struct hostent o_hostinfo; - int s; + int s, rc = -1, i; char *buff, *buff1; buff = buff1 = NULL; @@ -175,30 +175,24 @@ int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, co goto error; } - addr = empty_sockaddr_in; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr = *(struct in_addr *) hostinfo.h_addr; - if (our_port > 0 || (interface_name != NULL && strcmp(interface_name, "*") != 0)) { int reuse; o_addr = empty_sockaddr_in; o_addr.sin_family = AF_INET; o_addr.sin_port = htons(our_port); - if (interface_name == NULL || strcmp(interface_name, "*") == 0) - o_addr.sin_addr.s_addr = htonl(INADDR_ANY); - else { - if (gw_gethostbyname(&o_hostinfo, interface_name, &buff1) == -1) { - error(errno, "gethostbyname failed"); - goto error; - } - o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; - } + if (interface_name == NULL || strcmp(interface_name, "*") == 0) + o_addr.sin_addr.s_addr = htonl(INADDR_ANY); + else { + if (gw_gethostbyname(&o_hostinfo, interface_name, &buff1) == -1) { + error(errno, "gethostbyname failed"); + goto error; + } + o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; + } reuse = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, - sizeof(reuse)) == -1) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) { error(errno, "setsockopt failed before bind"); goto error; } @@ -208,18 +202,35 @@ int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, co } } - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) { - error(errno, "connect failed"); + i = 0; + do { + char ip[16]; + const char *ip2; + + addr = empty_sockaddr_in; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr = *(struct in_addr *) hostinfo.h_addr_list[i]; + + ip2 = inet_ntop(AF_INET, &addr.sin_addr, ip, 16); + + debug("gwlib.socket", 0, "Connecting to <%s>", ip2); + + rc = connect(s, (struct sockaddr *) &addr, sizeof(addr)); + if (rc == -1) { + error(errno, "connect to <%s> failed", ip2); + } + } while (rc == -1 && hostinfo.h_addr_list[++i] != NULL); + + if (rc == -1) goto error; - } gw_free(buff); gw_free(buff1); return s; error: - error(0, "error connecting to server `%s' at port `%d'", - hostname, port); + error(0, "error connecting to server `%s' at port `%d'", hostname, port); if (s >= 0) close(s); gw_free(buff); @@ -229,95 +240,105 @@ error: int tcpip_connect_nb_to_server(char *hostname, int port, const char *interface_name, int *done) { - return tcpip_connect_nb_to_server_with_port(hostname, port, 0, interface_name, done); + return tcpip_connect_nb_to_server_with_port(hostname, port, 0, interface_name, done); } -int tcpip_connect_nb_to_server_with_port(char *hostname, int port, int our_port, const char *interface_name, int *done) +int tcpip_connect_nb_to_server_with_port(char *hostname, int port, int our_port, const char *interface_name, int *done) { - struct sockaddr_in addr; - struct sockaddr_in o_addr; - struct hostent hostinfo; - struct hostent o_hostinfo; - int s; - int flags,rc; - char *buff, *buff1; - - *done = 1; - buff = buff1 = NULL; - - s = socket(PF_INET, SOCK_STREAM, 0); - if (s == -1) { - error(errno, "Couldn't create new socket."); - goto error; - } - - if (gw_gethostbyname(&hostinfo, hostname, &buff) == -1) { - error(errno, "gethostbyname failed"); - goto error; - } - - addr = empty_sockaddr_in; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr = *(struct in_addr *) hostinfo.h_addr; - - if (our_port > 0 || (interface_name != NULL && strcmp(interface_name, "*") != 0)) { - int reuse; + struct sockaddr_in addr; + struct sockaddr_in o_addr; + struct hostent hostinfo; + struct hostent o_hostinfo; + int s, flags, rc = -1, i; + char *buff, *buff1; - o_addr = empty_sockaddr_in; - o_addr.sin_family = AF_INET; - o_addr.sin_port = htons(our_port); - if (interface_name == NULL || strcmp(interface_name, "*") == 0) - o_addr.sin_addr.s_addr = htonl(INADDR_ANY); - else { - if (gw_gethostbyname(&o_hostinfo, interface_name, &buff1) == -1) { - error(errno, "gethostbyname failed"); - goto error; - } - o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; + *done = 1; + buff = buff1 = NULL; + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s == -1) { + error(errno, "Couldn't create new socket."); + goto error; } - reuse = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, - sizeof(reuse)) == -1) { - error(errno, "setsockopt failed before bind"); - goto error; + if (gw_gethostbyname(&hostinfo, hostname, &buff) == -1) { + error(errno, "gethostbyname failed"); + goto error; } - if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) { - error(errno, "bind to local port %d failed", our_port); - goto error; + + if (our_port > 0 || (interface_name != NULL && strcmp(interface_name, "*") != 0)) { + int reuse; + + o_addr = empty_sockaddr_in; + o_addr.sin_family = AF_INET; + o_addr.sin_port = htons(our_port); + if (interface_name == NULL || strcmp(interface_name, "*") == 0) + o_addr.sin_addr.s_addr = htonl(INADDR_ANY); + else { + if (gw_gethostbyname(&o_hostinfo, interface_name, &buff1) == -1) { + error(errno, "gethostbyname failed"); + goto error; + } + o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; + } + + reuse = 1; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) { + error(errno, "setsockopt failed before bind"); + goto error; + } + if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) { + error(errno, "bind to local port %d failed", our_port); + goto error; + } } - } - flags = fcntl(s, F_GETFL, 0); - fcntl(s, F_SETFL, flags | O_NONBLOCK); + flags = fcntl(s, F_GETFL, 0); + fcntl(s, F_SETFL, flags | O_NONBLOCK); + + i = 0; + do { + char ip[16]; + const char *ip2; - if ((rc = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) { - if (errno != EINPROGRESS) { - error(errno, "nonblocking connect failed"); - goto error; + addr = empty_sockaddr_in; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr = *(struct in_addr *) hostinfo.h_addr_list[i]; + + ip2 = inet_ntop(AF_INET, &addr.sin_addr, ip, 16); + + debug("gwlib.socket", 0, "Connecting nonblocking to <%s>", ip2); + + if ((rc = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) { + if (errno != EINPROGRESS) { + error(errno, "nonblocking connect to <%s> failed", ip2); + } + } + } while (rc == -1 && errno != EINPROGRESS && hostinfo.h_addr_list[++i] != NULL); + + if (rc == -1 && errno != EINPROGRESS) + goto error; + + /* May be connected immediatly + * (if we connecting to localhost for example) + */ + if (rc == 0) { + *done = 0; } - } - - /* May be connected immediatly - * (if we connecting to localhost for example) */ - if (rc == 0) { - *done = 0; - } - - gw_free(buff); - gw_free(buff1); - - return s; - - error: - error(0, "error connecting to server `%s' at port `%d'", - hostname, port); - if (s >= 0) - close(s); - gw_free(buff); - gw_free(buff1); - return -1; + + gw_free(buff); + gw_free(buff1); + + return s; + +error: + error(0, "error connecting to server `%s' at port `%d'", hostname, port); + if (s >= 0) + close(s); + gw_free(buff); + gw_free(buff1); + return -1; } @@ -549,15 +570,14 @@ int udp_sendto(int s, Octstr *datagram, Octstr *addr) int udp_recvfrom(int s, Octstr **datagram, Octstr **addr) { struct sockaddr_in sa; - int salen; + socklen_t salen; char *buf; int bytes; buf = gw_malloc(UDP_PACKET_MAX_SIZE); salen = sizeof(sa); - bytes = recvfrom(s, buf, UDP_PACKET_MAX_SIZE, 0, - (struct sockaddr *) &sa, &salen); + bytes = recvfrom(s, buf, UDP_PACKET_MAX_SIZE, 0, (struct sockaddr *) &sa, &salen); if (bytes == -1) { if (errno != EAGAIN) error(errno, "Couldn't receive UDP packet"); @@ -567,7 +587,7 @@ int udp_recvfrom(int s, Octstr **datagram, Octstr **addr) *datagram = octstr_create_from_data(buf, bytes); *addr = octstr_create_from_data((char *) &sa, salen); - + gw_free(buf); return 0; @@ -650,9 +670,9 @@ static Octstr *gw_netaddr_to_octstr6(unsigned char *src) "%x:%x:%x:%x:" "%x:%x:%x:%x:" "%x:%x:%x:%x", - src[0], src[1], src[2], src[3], - src[4], src[5], src[6], src[7], - src[8], src[9], src[10], src[11], + src[0], src[1], src[2], src[3], + src[4], src[5], src[6], src[7], + src[8], src[9], src[10], src[11], src[12], src[13], src[14], src[15]); } #endif @@ -670,14 +690,14 @@ Octstr *gw_netaddr_to_octstr(int af, void *src) default: return NULL; - } + } } int gw_accept(int fd, Octstr **client_addr) { struct sockaddr_in addr; - int addrlen; + socklen_t addrlen; int new_fd; if (gwthread_pollfd(fd, POLLIN, -1.0) != POLLIN) {