@@ -389,6 +389,7 @@ static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
389389static void freePGconn (PGconn * conn );
390390static void closePGconn (PGconn * conn );
391391static void release_conn_addrinfo (PGconn * conn );
392+ static int store_conn_addrinfo (PGconn * conn , struct addrinfo * addrlist );
392393static void sendTerminateConn (PGconn * conn );
393394static PQconninfoOption * conninfo_init (PQExpBuffer errorMessage );
394395static PQconninfoOption * parse_connection_string (const char * connstr ,
@@ -2295,7 +2296,7 @@ connectDBComplete(PGconn *conn)
22952296 time_t finish_time = ((time_t ) - 1 );
22962297 int timeout = 0 ;
22972298 int last_whichhost = -2 ; /* certainly different from whichhost */
2298- struct addrinfo * last_addr_cur = NULL ;
2299+ int last_whichaddr = -2 ; /* certainly different from whichaddr */
22992300
23002301 if (conn == NULL || conn -> status == CONNECTION_BAD )
23012302 return 0 ;
@@ -2339,11 +2340,11 @@ connectDBComplete(PGconn *conn)
23392340 if (flag != PGRES_POLLING_OK &&
23402341 timeout > 0 &&
23412342 (conn -> whichhost != last_whichhost ||
2342- conn -> addr_cur != last_addr_cur ))
2343+ conn -> whichaddr != last_whichaddr ))
23432344 {
23442345 finish_time = time (NULL ) + timeout ;
23452346 last_whichhost = conn -> whichhost ;
2346- last_addr_cur = conn -> addr_cur ;
2347+ last_whichaddr = conn -> whichaddr ;
23472348 }
23482349
23492350 /*
@@ -2490,9 +2491,9 @@ PQconnectPoll(PGconn *conn)
24902491 /* Time to advance to next address, or next host if no more addresses? */
24912492 if (conn -> try_next_addr )
24922493 {
2493- if (conn -> addr_cur && conn -> addr_cur -> ai_next )
2494+ if (conn -> whichaddr < conn -> naddr )
24942495 {
2495- conn -> addr_cur = conn -> addr_cur -> ai_next ;
2496+ conn -> whichaddr ++ ;
24962497 reset_connection_state_machine = true;
24972498 }
24982499 else
@@ -2505,6 +2506,7 @@ PQconnectPoll(PGconn *conn)
25052506 {
25062507 pg_conn_host * ch ;
25072508 struct addrinfo hint ;
2509+ struct addrinfo * addrlist ;
25082510 int thisport ;
25092511 int ret ;
25102512 char portstr [MAXPGPATH ];
@@ -2545,7 +2547,7 @@ PQconnectPoll(PGconn *conn)
25452547 /* Initialize hint structure */
25462548 MemSet (& hint , 0 , sizeof (hint ));
25472549 hint .ai_socktype = SOCK_STREAM ;
2548- conn -> addrlist_family = hint .ai_family = AF_UNSPEC ;
2550+ hint .ai_family = AF_UNSPEC ;
25492551
25502552 /* Figure out the port number we're going to use. */
25512553 if (ch -> port == NULL || ch -> port [0 ] == '\0' )
@@ -2568,8 +2570,8 @@ PQconnectPoll(PGconn *conn)
25682570 {
25692571 case CHT_HOST_NAME :
25702572 ret = pg_getaddrinfo_all (ch -> host , portstr , & hint ,
2571- & conn -> addrlist );
2572- if (ret || !conn -> addrlist )
2573+ & addrlist );
2574+ if (ret || !addrlist )
25732575 {
25742576 libpq_append_conn_error (conn , "could not translate host name \"%s\" to address: %s" ,
25752577 ch -> host , gai_strerror (ret ));
@@ -2580,8 +2582,8 @@ PQconnectPoll(PGconn *conn)
25802582 case CHT_HOST_ADDRESS :
25812583 hint .ai_flags = AI_NUMERICHOST ;
25822584 ret = pg_getaddrinfo_all (ch -> hostaddr , portstr , & hint ,
2583- & conn -> addrlist );
2584- if (ret || !conn -> addrlist )
2585+ & addrlist );
2586+ if (ret || !addrlist )
25852587 {
25862588 libpq_append_conn_error (conn , "could not parse network address \"%s\": %s" ,
25872589 ch -> hostaddr , gai_strerror (ret ));
@@ -2590,7 +2592,7 @@ PQconnectPoll(PGconn *conn)
25902592 break ;
25912593
25922594 case CHT_UNIX_SOCKET :
2593- conn -> addrlist_family = hint .ai_family = AF_UNIX ;
2595+ hint .ai_family = AF_UNIX ;
25942596 UNIXSOCK_PATH (portstr , thisport , ch -> host );
25952597 if (strlen (portstr ) >= UNIXSOCK_PATH_BUFLEN )
25962598 {
@@ -2605,8 +2607,8 @@ PQconnectPoll(PGconn *conn)
26052607 * name as a Unix-domain socket path.
26062608 */
26072609 ret = pg_getaddrinfo_all (NULL , portstr , & hint ,
2608- & conn -> addrlist );
2609- if (ret || !conn -> addrlist )
2610+ & addrlist );
2611+ if (ret || !addrlist )
26102612 {
26112613 libpq_append_conn_error (conn , "could not translate Unix-domain socket path \"%s\" to address: %s" ,
26122614 portstr , gai_strerror (ret ));
@@ -2615,8 +2617,15 @@ PQconnectPoll(PGconn *conn)
26152617 break ;
26162618 }
26172619
2618- /* OK, scan this addrlist for a working server address */
2619- conn -> addr_cur = conn -> addrlist ;
2620+ /*
2621+ * Store a copy of the addrlist in private memory so we can perform
2622+ * randomization for load balancing.
2623+ */
2624+ ret = store_conn_addrinfo (conn , addrlist );
2625+ pg_freeaddrinfo_all (hint .ai_family , addrlist );
2626+ if (ret )
2627+ goto error_return ; /* message already logged */
2628+
26202629 reset_connection_state_machine = true;
26212630 conn -> try_next_host = false;
26222631 }
@@ -2673,31 +2682,30 @@ PQconnectPoll(PGconn *conn)
26732682 {
26742683 /*
26752684 * Try to initiate a connection to one of the addresses
2676- * returned by pg_getaddrinfo_all(). conn->addr_cur is the
2685+ * returned by pg_getaddrinfo_all(). conn->whichaddr is the
26772686 * next one to try.
26782687 *
26792688 * The extra level of braces here is historical. It's not
26802689 * worth reindenting this whole switch case to remove 'em.
26812690 */
26822691 {
2683- struct addrinfo * addr_cur = conn -> addr_cur ;
26842692 char host_addr [NI_MAXHOST ];
26852693 int sock_type ;
2694+ AddrInfo * addr_cur ;
26862695
26872696 /*
26882697 * Advance to next possible host, if we've tried all of
26892698 * the addresses for the current host.
26902699 */
2691- if (addr_cur == NULL )
2700+ if (conn -> whichaddr == conn -> naddr )
26922701 {
26932702 conn -> try_next_host = true;
26942703 goto keep_going ;
26952704 }
2705+ addr_cur = & conn -> addr [conn -> whichaddr ];
26962706
26972707 /* Remember current address for possible use later */
2698- memcpy (& conn -> raddr .addr , addr_cur -> ai_addr ,
2699- addr_cur -> ai_addrlen );
2700- conn -> raddr .salen = addr_cur -> ai_addrlen ;
2708+ memcpy (& conn -> raddr , & addr_cur -> addr , sizeof (SockAddr ));
27012709
27022710 /*
27032711 * Set connip, too. Note we purposely ignore strdup
@@ -2732,7 +2740,7 @@ PQconnectPoll(PGconn *conn)
27322740 */
27332741 sock_type |= SOCK_NONBLOCK ;
27342742#endif
2735- conn -> sock = socket (addr_cur -> ai_family , sock_type , 0 );
2743+ conn -> sock = socket (addr_cur -> family , sock_type , 0 );
27362744 if (conn -> sock == PGINVALID_SOCKET )
27372745 {
27382746 int errorno = SOCK_ERRNO ;
@@ -2743,7 +2751,7 @@ PQconnectPoll(PGconn *conn)
27432751 * cases where the address list includes both IPv4 and
27442752 * IPv6 but kernel only accepts one family.
27452753 */
2746- if (addr_cur -> ai_next != NULL ||
2754+ if (conn -> whichaddr < conn -> naddr ||
27472755 conn -> whichhost + 1 < conn -> nconnhost )
27482756 {
27492757 conn -> try_next_addr = true;
@@ -2769,7 +2777,7 @@ PQconnectPoll(PGconn *conn)
27692777 * TCP sockets, nonblock mode, close-on-exec. Try the
27702778 * next address if any of this fails.
27712779 */
2772- if (addr_cur -> ai_family != AF_UNIX )
2780+ if (addr_cur -> family != AF_UNIX )
27732781 {
27742782 if (!connectNoDelay (conn ))
27752783 {
@@ -2800,7 +2808,7 @@ PQconnectPoll(PGconn *conn)
28002808#endif /* F_SETFD */
28012809#endif
28022810
2803- if (addr_cur -> ai_family != AF_UNIX )
2811+ if (addr_cur -> family != AF_UNIX )
28042812 {
28052813#ifndef WIN32
28062814 int on = 1 ;
@@ -2892,8 +2900,8 @@ PQconnectPoll(PGconn *conn)
28922900 * Start/make connection. This should not block, since we
28932901 * are in nonblock mode. If it does, well, too bad.
28942902 */
2895- if (connect (conn -> sock , addr_cur -> ai_addr ,
2896- addr_cur -> ai_addrlen ) < 0 )
2903+ if (connect (conn -> sock , ( struct sockaddr * ) & addr_cur -> addr . addr ,
2904+ addr_cur -> addr . salen ) < 0 )
28972905 {
28982906 if (SOCK_ERRNO == EINPROGRESS ||
28992907#ifdef WIN32
@@ -4318,18 +4326,60 @@ freePGconn(PGconn *conn)
43184326 free (conn );
43194327}
43204328
4329+ /*
4330+ * store_conn_addrinfo
4331+ * - copy addrinfo to PGconn object
4332+ *
4333+ * Copies the addrinfos from addrlist to the PGconn object such that the
4334+ * addrinfos can be manipulated by libpq. Returns a positive integer on
4335+ * failure, otherwise zero.
4336+ */
4337+ static int
4338+ store_conn_addrinfo (PGconn * conn , struct addrinfo * addrlist )
4339+ {
4340+ struct addrinfo * ai = addrlist ;
4341+
4342+ conn -> whichaddr = 0 ;
4343+
4344+ conn -> naddr = 0 ;
4345+ while (ai )
4346+ {
4347+ ai = ai -> ai_next ;
4348+ conn -> naddr ++ ;
4349+ }
4350+
4351+ conn -> addr = calloc (conn -> naddr , sizeof (AddrInfo ));
4352+ if (conn -> addr == NULL )
4353+ {
4354+ libpq_append_conn_error (conn , "out of memory" );
4355+ return 1 ;
4356+ }
4357+
4358+ ai = addrlist ;
4359+ for (int i = 0 ; i < conn -> naddr ; i ++ )
4360+ {
4361+ conn -> addr [i ].family = ai -> ai_family ;
4362+
4363+ memcpy (& conn -> addr [i ].addr .addr , ai -> ai_addr ,
4364+ ai -> ai_addrlen );
4365+ conn -> addr [i ].addr .salen = ai -> ai_addrlen ;
4366+ ai = ai -> ai_next ;
4367+ }
4368+
4369+ return 0 ;
4370+ }
4371+
43214372/*
43224373 * release_conn_addrinfo
43234374 * - Free any addrinfo list in the PGconn.
43244375 */
43254376static void
43264377release_conn_addrinfo (PGconn * conn )
43274378{
4328- if (conn -> addrlist )
4379+ if (conn -> addr )
43294380 {
4330- pg_freeaddrinfo_all (conn -> addrlist_family , conn -> addrlist );
4331- conn -> addrlist = NULL ;
4332- conn -> addr_cur = NULL ; /* for safety */
4381+ free (conn -> addr );
4382+ conn -> addr = NULL ;
43334383 }
43344384}
43354385
0 commit comments