@@ -389,6 +389,7 @@ static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
389
389
static void freePGconn (PGconn * conn );
390
390
static void closePGconn (PGconn * conn );
391
391
static void release_conn_addrinfo (PGconn * conn );
392
+ static int store_conn_addrinfo (PGconn * conn , struct addrinfo * addrlist );
392
393
static void sendTerminateConn (PGconn * conn );
393
394
static PQconninfoOption * conninfo_init (PQExpBuffer errorMessage );
394
395
static PQconninfoOption * parse_connection_string (const char * connstr ,
@@ -2295,7 +2296,7 @@ connectDBComplete(PGconn *conn)
2295
2296
time_t finish_time = ((time_t ) - 1 );
2296
2297
int timeout = 0 ;
2297
2298
int last_whichhost = -2 ; /* certainly different from whichhost */
2298
- struct addrinfo * last_addr_cur = NULL ;
2299
+ int last_whichaddr = -2 ; /* certainly different from whichaddr */
2299
2300
2300
2301
if (conn == NULL || conn -> status == CONNECTION_BAD )
2301
2302
return 0 ;
@@ -2339,11 +2340,11 @@ connectDBComplete(PGconn *conn)
2339
2340
if (flag != PGRES_POLLING_OK &&
2340
2341
timeout > 0 &&
2341
2342
(conn -> whichhost != last_whichhost ||
2342
- conn -> addr_cur != last_addr_cur ))
2343
+ conn -> whichaddr != last_whichaddr ))
2343
2344
{
2344
2345
finish_time = time (NULL ) + timeout ;
2345
2346
last_whichhost = conn -> whichhost ;
2346
- last_addr_cur = conn -> addr_cur ;
2347
+ last_whichaddr = conn -> whichaddr ;
2347
2348
}
2348
2349
2349
2350
/*
@@ -2490,9 +2491,9 @@ PQconnectPoll(PGconn *conn)
2490
2491
/* Time to advance to next address, or next host if no more addresses? */
2491
2492
if (conn -> try_next_addr )
2492
2493
{
2493
- if (conn -> addr_cur && conn -> addr_cur -> ai_next )
2494
+ if (conn -> whichaddr < conn -> naddr )
2494
2495
{
2495
- conn -> addr_cur = conn -> addr_cur -> ai_next ;
2496
+ conn -> whichaddr ++ ;
2496
2497
reset_connection_state_machine = true;
2497
2498
}
2498
2499
else
@@ -2505,6 +2506,7 @@ PQconnectPoll(PGconn *conn)
2505
2506
{
2506
2507
pg_conn_host * ch ;
2507
2508
struct addrinfo hint ;
2509
+ struct addrinfo * addrlist ;
2508
2510
int thisport ;
2509
2511
int ret ;
2510
2512
char portstr [MAXPGPATH ];
@@ -2545,7 +2547,7 @@ PQconnectPoll(PGconn *conn)
2545
2547
/* Initialize hint structure */
2546
2548
MemSet (& hint , 0 , sizeof (hint ));
2547
2549
hint .ai_socktype = SOCK_STREAM ;
2548
- conn -> addrlist_family = hint .ai_family = AF_UNSPEC ;
2550
+ hint .ai_family = AF_UNSPEC ;
2549
2551
2550
2552
/* Figure out the port number we're going to use. */
2551
2553
if (ch -> port == NULL || ch -> port [0 ] == '\0' )
@@ -2568,8 +2570,8 @@ PQconnectPoll(PGconn *conn)
2568
2570
{
2569
2571
case CHT_HOST_NAME :
2570
2572
ret = pg_getaddrinfo_all (ch -> host , portstr , & hint ,
2571
- & conn -> addrlist );
2572
- if (ret || !conn -> addrlist )
2573
+ & addrlist );
2574
+ if (ret || !addrlist )
2573
2575
{
2574
2576
libpq_append_conn_error (conn , "could not translate host name \"%s\" to address: %s" ,
2575
2577
ch -> host , gai_strerror (ret ));
@@ -2580,8 +2582,8 @@ PQconnectPoll(PGconn *conn)
2580
2582
case CHT_HOST_ADDRESS :
2581
2583
hint .ai_flags = AI_NUMERICHOST ;
2582
2584
ret = pg_getaddrinfo_all (ch -> hostaddr , portstr , & hint ,
2583
- & conn -> addrlist );
2584
- if (ret || !conn -> addrlist )
2585
+ & addrlist );
2586
+ if (ret || !addrlist )
2585
2587
{
2586
2588
libpq_append_conn_error (conn , "could not parse network address \"%s\": %s" ,
2587
2589
ch -> hostaddr , gai_strerror (ret ));
@@ -2590,7 +2592,7 @@ PQconnectPoll(PGconn *conn)
2590
2592
break ;
2591
2593
2592
2594
case CHT_UNIX_SOCKET :
2593
- conn -> addrlist_family = hint .ai_family = AF_UNIX ;
2595
+ hint .ai_family = AF_UNIX ;
2594
2596
UNIXSOCK_PATH (portstr , thisport , ch -> host );
2595
2597
if (strlen (portstr ) >= UNIXSOCK_PATH_BUFLEN )
2596
2598
{
@@ -2605,8 +2607,8 @@ PQconnectPoll(PGconn *conn)
2605
2607
* name as a Unix-domain socket path.
2606
2608
*/
2607
2609
ret = pg_getaddrinfo_all (NULL , portstr , & hint ,
2608
- & conn -> addrlist );
2609
- if (ret || !conn -> addrlist )
2610
+ & addrlist );
2611
+ if (ret || !addrlist )
2610
2612
{
2611
2613
libpq_append_conn_error (conn , "could not translate Unix-domain socket path \"%s\" to address: %s" ,
2612
2614
portstr , gai_strerror (ret ));
@@ -2615,8 +2617,15 @@ PQconnectPoll(PGconn *conn)
2615
2617
break ;
2616
2618
}
2617
2619
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
+
2620
2629
reset_connection_state_machine = true;
2621
2630
conn -> try_next_host = false;
2622
2631
}
@@ -2673,31 +2682,30 @@ PQconnectPoll(PGconn *conn)
2673
2682
{
2674
2683
/*
2675
2684
* 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
2677
2686
* next one to try.
2678
2687
*
2679
2688
* The extra level of braces here is historical. It's not
2680
2689
* worth reindenting this whole switch case to remove 'em.
2681
2690
*/
2682
2691
{
2683
- struct addrinfo * addr_cur = conn -> addr_cur ;
2684
2692
char host_addr [NI_MAXHOST ];
2685
2693
int sock_type ;
2694
+ AddrInfo * addr_cur ;
2686
2695
2687
2696
/*
2688
2697
* Advance to next possible host, if we've tried all of
2689
2698
* the addresses for the current host.
2690
2699
*/
2691
- if (addr_cur == NULL )
2700
+ if (conn -> whichaddr == conn -> naddr )
2692
2701
{
2693
2702
conn -> try_next_host = true;
2694
2703
goto keep_going ;
2695
2704
}
2705
+ addr_cur = & conn -> addr [conn -> whichaddr ];
2696
2706
2697
2707
/* 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 ));
2701
2709
2702
2710
/*
2703
2711
* Set connip, too. Note we purposely ignore strdup
@@ -2732,7 +2740,7 @@ PQconnectPoll(PGconn *conn)
2732
2740
*/
2733
2741
sock_type |= SOCK_NONBLOCK ;
2734
2742
#endif
2735
- conn -> sock = socket (addr_cur -> ai_family , sock_type , 0 );
2743
+ conn -> sock = socket (addr_cur -> family , sock_type , 0 );
2736
2744
if (conn -> sock == PGINVALID_SOCKET )
2737
2745
{
2738
2746
int errorno = SOCK_ERRNO ;
@@ -2743,7 +2751,7 @@ PQconnectPoll(PGconn *conn)
2743
2751
* cases where the address list includes both IPv4 and
2744
2752
* IPv6 but kernel only accepts one family.
2745
2753
*/
2746
- if (addr_cur -> ai_next != NULL ||
2754
+ if (conn -> whichaddr < conn -> naddr ||
2747
2755
conn -> whichhost + 1 < conn -> nconnhost )
2748
2756
{
2749
2757
conn -> try_next_addr = true;
@@ -2769,7 +2777,7 @@ PQconnectPoll(PGconn *conn)
2769
2777
* TCP sockets, nonblock mode, close-on-exec. Try the
2770
2778
* next address if any of this fails.
2771
2779
*/
2772
- if (addr_cur -> ai_family != AF_UNIX )
2780
+ if (addr_cur -> family != AF_UNIX )
2773
2781
{
2774
2782
if (!connectNoDelay (conn ))
2775
2783
{
@@ -2800,7 +2808,7 @@ PQconnectPoll(PGconn *conn)
2800
2808
#endif /* F_SETFD */
2801
2809
#endif
2802
2810
2803
- if (addr_cur -> ai_family != AF_UNIX )
2811
+ if (addr_cur -> family != AF_UNIX )
2804
2812
{
2805
2813
#ifndef WIN32
2806
2814
int on = 1 ;
@@ -2892,8 +2900,8 @@ PQconnectPoll(PGconn *conn)
2892
2900
* Start/make connection. This should not block, since we
2893
2901
* are in nonblock mode. If it does, well, too bad.
2894
2902
*/
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 )
2897
2905
{
2898
2906
if (SOCK_ERRNO == EINPROGRESS ||
2899
2907
#ifdef WIN32
@@ -4318,18 +4326,60 @@ freePGconn(PGconn *conn)
4318
4326
free (conn );
4319
4327
}
4320
4328
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
+
4321
4372
/*
4322
4373
* release_conn_addrinfo
4323
4374
* - Free any addrinfo list in the PGconn.
4324
4375
*/
4325
4376
static void
4326
4377
release_conn_addrinfo (PGconn * conn )
4327
4378
{
4328
- if (conn -> addrlist )
4379
+ if (conn -> addr )
4329
4380
{
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 ;
4333
4383
}
4334
4384
}
4335
4385
0 commit comments