pgpool2.git / summary / log / commit / refs

commit    05a91f40198d2fb0598ff42bfebf0a6bac54cd12
Author:   Tatsuo Ishii <ishii@postgresql.org>
Date:     Fri Aug 29 23:05:28 2014 +0000

    Support IPv6 connections to PostgreSQL.
    
    Now pgpool-II accepts IPv6 address in backend_hostname* such as '::1'.
    Note that pgpool-II still does not bind to IPv6 address however.
    
    Patch contributed by Michael Stapelberg.


src/protocol/pool_connection_pool.c | 143 +++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 61 deletions(-) diff --git a/src/protocol/pool_connection_pool.c b/src/protocol/pool_connection_pool.c index 9f12346fe..8b0efd581 100644 --- a/src/protocol/pool_connection_pool.c +++ b/src/protocol/pool_connection_pool.c @@ -528,57 +528,14 @@ int connect_unix_domain_socket_by_port(int port, char *socket_dir, bool retry) return fd; } -/* - * Connect to PostgreSQL server by using INET domain socket. - * If retry is true, retry to call connect() upon receiving EINTR error. - */ -int connect_inet_domain_socket_by_port(char *host, int port, bool retry) +bool connect_with_timeout(int fd, struct addrinfo *walk, char *host, int port, bool retry) { - int fd; - int len; - int on = 1; - struct sockaddr_in addr; - struct hostent *hp; - struct timeval timeout; struct timeval *tm; + struct timeval timeout; fd_set rset, wset; + int sts; int error; socklen_t socklen; - int sts; - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) - { - pool_error("connect_inet_domain_socket_by_port: socket() failed: %s", strerror(errno)); - return -1; - } - - /* set nodelay */ - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - (char *) &on, - sizeof(on)) < 0) - { - pool_error("connect_inet_domain_socket_by_port: setsockopt() failed: %s", strerror(errno)); - close(fd); - return -1; - } - - memset((char *) &addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - - addr.sin_port = htons(port); - len = sizeof(struct sockaddr_in); - - hp = gethostbyname(host); - if ((hp == NULL) || (hp->h_addrtype != AF_INET)) - { - pool_error("connect_inet_domain_socket: gethostbyname() failed: %s host: %s", hstrerror(h_errno), host); - close(fd); - return -1; - } - memmove((char *) &(addr.sin_addr), - (char *) hp->h_addr, - hp->h_length); pool_set_nonblock(fd); @@ -590,7 +547,7 @@ int connect_inet_domain_socket_by_port(char *host, int port, bool retry) (errmsg("failed to connect to PostgreSQL server on \"%s:%d\" using INET socket",host,port), errdetail("exit request has been sent"))); close(fd); - return -1; + return false; } if (health_check_timer_expired && getpid() == mypid) /* has health check timer expired */ @@ -599,10 +556,10 @@ int connect_inet_domain_socket_by_port(char *host, int port, bool retry) (errmsg("failed to connect to PostgreSQL server on \"%s:%d\" using INET socket",host,port), errdetail("health check timer expired"))); close(fd); - return -1; + return false; } - if (connect(fd, (struct sockaddr *)&addr, len) < 0) + if (connect(fd, walk->ai_addr, walk->ai_addrlen) < 0) { if (errno == EISCONN) { @@ -621,8 +578,7 @@ int connect_inet_domain_socket_by_port(char *host, int port, bool retry) { pool_error("connect_inet_domain_socket(%s:%d): connect() failed: %s", host, port, strerror(errno)); - close(fd); - return -1; + return false; } if (pool_config->connect_timeout == 0) @@ -660,8 +616,7 @@ int connect_inet_domain_socket_by_port(char *host, int port, bool retry) else { pool_error("connect_inet_domain_socket(%s:%d): select() timed out", host, port); - close(fd); - return -1; + return false; } } else if (sts > 0) @@ -683,8 +638,7 @@ int connect_inet_domain_socket_by_port(char *host, int port, bool retry) /* Solaris returns error in this case */ pool_error("connect_inet_domain_socket(%s:%d): getsockopt() failed: %s", host, port, strerror(errno)); - close(fd); - return -1; + return false; } /* Non Solaris case */ @@ -692,16 +646,14 @@ int connect_inet_domain_socket_by_port(char *host, int port, bool retry) { pool_error("connect_inet_domain_socket(%s:%d): getsockopt() detected error: %s", host, port, strerror(error)); - close(fd); - return -1; + return false; } } else { pool_error("connect_inet_domain_socket(%s:%d): both read data and write data was not set", host, port); - close(fd); - return -1; + return false; } } else /* select returns error */ @@ -717,16 +669,85 @@ int connect_inet_domain_socket_by_port(char *host, int port, bool retry) (errmsg("failed to connect to PostgreSQL server on \"%s:%d\" using INET socket",host,port), errdetail("select() system call interrupted"))); close(fd); - return -1; + return false; } } break; } pool_unset_nonblock(fd); - return fd; + return true; } +/* + * Connect to PostgreSQL server by using INET domain socket. + * If retry is true, retry to call connect() upon receiving EINTR error. + */ +int connect_inet_domain_socket_by_port(char *host, int port, bool retry) +{ + int fd = -1; + int on = 1; + char *portstr; + int ret; + struct addrinfo *res; + struct addrinfo *walk; + struct addrinfo hints; + + /* getaddrinfo() requires a string because it also accepts service names, such as "http". */ + if (asprintf(&portstr, "%d", port) == -1) + { + pool_error("connect_inet_domain_socket_by_port: asprintf() failed: %s", strerror(errno)); + return -1; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if ((ret = getaddrinfo(host, portstr, &hints, &res)) != 0) + { + pool_error("connect_inet_domain_socket_by_port: getaddrinfo() failed: %s", gai_strerror(ret)); + free(portstr); + return -1; + } + + free(portstr); + + for (walk = res; walk != NULL; walk = walk->ai_next) + { + fd = socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol); + if (fd < 0) + { + pool_error("connect_inet_domain_socket_by_port: socket() failed: %s", strerror(errno)); + continue; + } + + /* set nodelay */ + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, + (char *) &on, + sizeof(on)) < 0) + { + pool_error("connect_inet_domain_socket_by_port: setsockopt() failed: %s", strerror(errno)); + close(fd); + freeaddrinfo(res); + return -1; + } + + if (!connect_with_timeout(fd, walk, host, port, retry)) + { + close(fd); + fd = -1; + continue; + } + + freeaddrinfo(res); + return fd; + } + + freeaddrinfo(res); + return -1; +} + /* * create connection pool */ [parent: 57aff9f312c3]