Skip to content

Commit f0ed431

Browse files
committed
Add libpq connection timeout parameter.
Denis A Ustimenko
1 parent b7214a8 commit f0ed431

File tree

4 files changed

+97
-9
lines changed

4 files changed

+97
-9
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.92 2002/08/15 03:00:59 momjian Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.93 2002/08/17 12:33:17 momjian Exp $
33
-->
44

55
<chapter id="libpq">
@@ -171,6 +171,15 @@ PGconn *PQconnectdb(const char *conninfo)
171171
</listitem>
172172
</varlistentry>
173173

174+
<varlistentry>
175+
<term><literal>connect_timeout</literal></term>
176+
<listitem>
177+
<para>
178+
Time space in seconds given to connect routine. Zero or not set means infinite.
179+
</para>
180+
</listitem>
181+
</varlistentry>
182+
174183
<varlistentry>
175184
<term><literal>options</literal></term>
176185
<listitem>

src/interfaces/libpq/fe-connect.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.191 2002/08/15 02:56:19 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.192 2002/08/17 12:33:17 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -110,6 +110,9 @@ static const PQconninfoOption PQconninfoOptions[] = {
110110
{"password", "PGPASSWORD", DefaultPassword, NULL,
111111
"Database-Password", "*", 20},
112112

113+
{"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL,
114+
"Connect-timeout", "", 10}, /* strlen( INT32_MAX) == 10 */
115+
113116
{"dbname", "PGDATABASE", NULL, NULL,
114117
"Database-Name", "", 20},
115118

@@ -302,6 +305,8 @@ PQconnectStart(const char *conninfo)
302305
conn->pguser = tmp ? strdup(tmp) : NULL;
303306
tmp = conninfo_getval(connOptions, "password");
304307
conn->pgpass = tmp ? strdup(tmp) : NULL;
308+
tmp = conninfo_getval(connOptions, "connect_timeout");
309+
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
305310
#ifdef USE_SSL
306311
tmp = conninfo_getval(connOptions, "requiressl");
307312
if (tmp && tmp[0] == '1')
@@ -1052,12 +1057,39 @@ connectDBComplete(PGconn *conn)
10521057
{
10531058
PostgresPollingStatusType flag = PGRES_POLLING_WRITING;
10541059

1060+
struct timeval remains, *rp = NULL, finish_time, start_time;
1061+
10551062
if (conn == NULL || conn->status == CONNECTION_BAD)
10561063
return 0;
10571064

1058-
for (;;)
1065+
/*
1066+
* Prepare to time calculations, if connect_timeout isn't zero.
1067+
*/
1068+
if (conn->connect_timeout != NULL)
10591069
{
1070+
remains.tv_sec = atoi(conn->connect_timeout);
1071+
if (!remains.tv_sec)
1072+
{
1073+
conn->status = CONNECTION_BAD;
1074+
return 0;
1075+
}
1076+
remains.tv_usec = 0;
1077+
rp = &remains;
1078+
}
1079+
1080+
1081+
while (NULL == rp || remains.tv_sec > 0 || remains.tv_sec == 0 && remains.tv_usec > 0)
1082+
{
10601083
/*
1084+
* If connecting timeout is set, get current time.
1085+
*/
1086+
if ( NULL != rp && -1 == gettimeofday(&start_time, NULL))
1087+
{
1088+
conn->status = CONNECTION_BAD;
1089+
return 0;
1090+
}
1091+
1092+
/*
10611093
* Wait, if necessary. Note that the initial state (just after
10621094
* PQconnectStart) is to wait for the socket to select for
10631095
* writing.
@@ -1071,15 +1103,15 @@ connectDBComplete(PGconn *conn)
10711103
return 1; /* success! */
10721104

10731105
case PGRES_POLLING_READING:
1074-
if (pqWait(1, 0, conn))
1106+
if (pqWaitTimed(1, 0, conn, rp))
10751107
{
10761108
conn->status = CONNECTION_BAD;
10771109
return 0;
10781110
}
10791111
break;
10801112

10811113
case PGRES_POLLING_WRITING:
1082-
if (pqWait(0, 1, conn))
1114+
if (pqWaitTimed(0, 1, conn, rp))
10831115
{
10841116
conn->status = CONNECTION_BAD;
10851117
return 0;
@@ -1096,7 +1128,31 @@ connectDBComplete(PGconn *conn)
10961128
* Now try to advance the state machine.
10971129
*/
10981130
flag = PQconnectPoll(conn);
1131+
1132+
/*
1133+
* If connecting timeout is set, calculate remain time.
1134+
*/
1135+
if (NULL != rp) {
1136+
if (-1 == gettimeofday(&finish_time, NULL))
1137+
{
1138+
conn->status = CONNECTION_BAD;
1139+
return 0;
1140+
}
1141+
if (0 > (finish_time.tv_usec -= start_time.tv_usec))
1142+
{
1143+
remains.tv_sec++;
1144+
finish_time.tv_usec += 1000000;
1145+
}
1146+
if (0 > (remains.tv_usec -= finish_time.tv_usec))
1147+
{
1148+
remains.tv_sec--;
1149+
remains.tv_usec += 1000000;
1150+
}
1151+
remains.tv_sec -= finish_time.tv_sec - start_time.tv_sec;
1152+
}
10991153
}
1154+
conn->status = CONNECTION_BAD;
1155+
return 0;
11001156
}
11011157

11021158
/* ----------------
@@ -1928,6 +1984,8 @@ freePGconn(PGconn *conn)
19281984
free(conn->pguser);
19291985
if (conn->pgpass)
19301986
free(conn->pgpass);
1987+
if (conn->connect_timeout)
1988+
free(conn->connect_timeout);
19311989
/* Note that conn->Pfdebug is not ours to close or free */
19321990
if (conn->notifyList)
19331991
DLFreeList(conn->notifyList);

src/interfaces/libpq/fe-misc.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*
2626
*
2727
* IDENTIFICATION
28-
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.76 2002/06/20 20:29:54 momjian Exp $
28+
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.77 2002/08/17 12:33:18 momjian Exp $
2929
*
3030
*-------------------------------------------------------------------------
3131
*/
@@ -775,11 +775,20 @@ pqFlush(PGconn *conn)
775775
*/
776776
int
777777
pqWait(int forRead, int forWrite, PGconn *conn)
778+
{
779+
return pqWaitTimed( forRead, forWrite, conn, (const struct timeval *) NULL);
780+
}
781+
782+
int
783+
pqWaitTimed(int forRead, int forWrite, PGconn *conn, const struct timeval *timeout)
778784
{
779785
fd_set input_mask;
780786
fd_set output_mask;
781787
fd_set except_mask;
782788

789+
struct timeval tmp_timeout;
790+
struct timeval *ptmp_timeout = NULL;
791+
783792
if (conn->sock < 0)
784793
{
785794
printfPQExpBuffer(&conn->errorMessage,
@@ -807,9 +816,18 @@ pqWait(int forRead, int forWrite, PGconn *conn)
807816
if (forWrite)
808817
FD_SET(conn->sock, &output_mask);
809818
FD_SET(conn->sock, &except_mask);
810-
if (select(conn->sock + 1, &input_mask, &output_mask, &except_mask,
811-
(struct timeval *) NULL) < 0)
819+
820+
if (NULL != timeout)
812821
{
822+
/*
823+
* select may modify timeout argument on some platforms use copy
824+
*/
825+
tmp_timeout = *timeout;
826+
ptmp_timeout = &tmp_timeout;
827+
}
828+
if (select(conn->sock + 1, &input_mask, &output_mask,
829+
&except_mask, ptmp_timeout) < 0)
830+
{
813831
if (SOCK_ERRNO == EINTR)
814832
goto retry5;
815833
printfPQExpBuffer(&conn->errorMessage,

src/interfaces/libpq/libpq-int.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
15-
* $Id: libpq-int.h,v 1.52 2002/07/20 05:43:31 momjian Exp $
15+
* $Id: libpq-int.h,v 1.53 2002/08/17 12:33:18 momjian Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -286,6 +286,8 @@ struct pg_conn
286286
PQExpBufferData workBuffer; /* expansible string */
287287

288288
int client_encoding; /* encoding id */
289+
290+
char *connect_timeout;
289291
};
290292

291293
/* String descriptions of the ExecStatusTypes.
@@ -332,6 +334,7 @@ extern int pqReadData(PGconn *conn);
332334
extern int pqFlush(PGconn *conn);
333335
extern int pqSendSome(PGconn *conn);
334336
extern int pqWait(int forRead, int forWrite, PGconn *conn);
337+
extern int pqWaitTimed(int forRead, int forWrite, PGconn *conn, const struct timeval* timeout);
335338
extern int pqReadReady(PGconn *conn);
336339
extern int pqWriteReady(PGconn *conn);
337340

0 commit comments

Comments
 (0)