|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.393 2010/05/26 21:39:27 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.394 2010/06/23 21:54:13 rhaas Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -183,6 +183,18 @@ static const PQconninfoOption PQconninfoOptions[] = {
|
183 | 183 | {"fallback_application_name", NULL, NULL, NULL,
|
184 | 184 | "Fallback-Application-Name", "", 64},
|
185 | 185 |
|
| 186 | + {"keepalives", NULL, NULL, NULL, |
| 187 | + "TCP-Keepalives", "", 1}, /* should be just '0' or '1' */ |
| 188 | + |
| 189 | + {"keepalives_idle", NULL, NULL, NULL, |
| 190 | + "TCP-Keepalives-Idle", "", 10}, /* strlen(INT32_MAX) == 10 */ |
| 191 | + |
| 192 | + {"keepalives_interval", NULL, NULL, NULL, |
| 193 | + "TCP-Keepalives-Interval", "", 10}, /* strlen(INT32_MAX) == 10 */ |
| 194 | + |
| 195 | + {"keepalives_count", NULL, NULL, NULL, |
| 196 | + "TCP-Keepalives-Count", "", 10}, /* strlen(INT32_MAX) == 10 */ |
| 197 | + |
186 | 198 | #ifdef USE_SSL
|
187 | 199 |
|
188 | 200 | /*
|
@@ -552,6 +564,14 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
|
552 | 564 | conn->pgpass = tmp ? strdup(tmp) : NULL;
|
553 | 565 | tmp = conninfo_getval(connOptions, "connect_timeout");
|
554 | 566 | conn->connect_timeout = tmp ? strdup(tmp) : NULL;
|
| 567 | + tmp = conninfo_getval(connOptions, "keepalives"); |
| 568 | + conn->keepalives = tmp ? strdup(tmp) : NULL; |
| 569 | + tmp = conninfo_getval(connOptions, "keepalives_idle"); |
| 570 | + conn->keepalives_idle = tmp ? strdup(tmp) : NULL; |
| 571 | + tmp = conninfo_getval(connOptions, "keepalives_interval"); |
| 572 | + conn->keepalives_interval = tmp ? strdup(tmp) : NULL; |
| 573 | + tmp = conninfo_getval(connOptions, "keepalives_count"); |
| 574 | + conn->keepalives_count = tmp ? strdup(tmp) : NULL; |
555 | 575 | tmp = conninfo_getval(connOptions, "sslmode");
|
556 | 576 | conn->sslmode = tmp ? strdup(tmp) : NULL;
|
557 | 577 | tmp = conninfo_getval(connOptions, "sslkey");
|
@@ -943,6 +963,119 @@ connectFailureMessage(PGconn *conn, int errorno)
|
943 | 963 | }
|
944 | 964 | }
|
945 | 965 |
|
| 966 | +/* |
| 967 | + * Should we use keepalives? Returns 1 if yes, 0 if no, and -1 if |
| 968 | + * conn->keepalives is set to a value which is not parseable as an |
| 969 | + * integer. |
| 970 | + */ |
| 971 | +static int |
| 972 | +useKeepalives(PGconn *conn) |
| 973 | +{ |
| 974 | + char *ep; |
| 975 | + int val; |
| 976 | + |
| 977 | + if (conn->keepalives == NULL) |
| 978 | + return 1; |
| 979 | + val = strtol(conn->keepalives, &ep, 10); |
| 980 | + if (*ep) |
| 981 | + return -1; |
| 982 | + return val != 0 ? 1 : 0; |
| 983 | +} |
| 984 | + |
| 985 | +/* |
| 986 | + * Set the keepalive idle timer. |
| 987 | + */ |
| 988 | +static int |
| 989 | +setKeepalivesIdle(PGconn *conn) |
| 990 | +{ |
| 991 | + int idle; |
| 992 | + |
| 993 | + if (conn->keepalives_idle == NULL) |
| 994 | + return 1; |
| 995 | + |
| 996 | + idle = atoi(conn->keepalives_idle); |
| 997 | + if (idle < 0) |
| 998 | + idle = 0; |
| 999 | + |
| 1000 | +#ifdef TCP_KEEPIDLE |
| 1001 | + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPIDLE, |
| 1002 | + (char *) &idle, sizeof(idle)) < 0) |
| 1003 | + { |
| 1004 | + char sebuf[256]; |
| 1005 | + |
| 1006 | + appendPQExpBuffer(&conn->errorMessage, |
| 1007 | + libpq_gettext("setsockopt(TCP_KEEPIDLE) failed: %s\n"), |
| 1008 | + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); |
| 1009 | + return 0; |
| 1010 | + } |
| 1011 | +#endif |
| 1012 | + |
| 1013 | + return 1; |
| 1014 | +} |
| 1015 | + |
| 1016 | +/* |
| 1017 | + * Set the keepalive interval. |
| 1018 | + */ |
| 1019 | +static int |
| 1020 | +setKeepalivesInterval(PGconn *conn) |
| 1021 | +{ |
| 1022 | + int interval; |
| 1023 | + |
| 1024 | + if (conn->keepalives_interval == NULL) |
| 1025 | + return 1; |
| 1026 | + |
| 1027 | + interval = atoi(conn->keepalives_interval); |
| 1028 | + if (interval < 0) |
| 1029 | + interval = 0; |
| 1030 | + |
| 1031 | +#ifdef TCP_KEEPINTVL |
| 1032 | + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL, |
| 1033 | + (char *) &interval, sizeof(interval)) < 0) |
| 1034 | + { |
| 1035 | + char sebuf[256]; |
| 1036 | + |
| 1037 | + appendPQExpBuffer(&conn->errorMessage, |
| 1038 | + libpq_gettext("setsockopt(TCP_KEEPINTVL) failed: %s\n"), |
| 1039 | + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); |
| 1040 | + return 0; |
| 1041 | + } |
| 1042 | +#endif |
| 1043 | + |
| 1044 | + return 1; |
| 1045 | +} |
| 1046 | + |
| 1047 | +/* |
| 1048 | + * Set the count of lost keepalive packets that will trigger a connection |
| 1049 | + * break. |
| 1050 | + */ |
| 1051 | +static int |
| 1052 | +setKeepalivesCount(PGconn *conn) |
| 1053 | +{ |
| 1054 | + int count; |
| 1055 | + |
| 1056 | + if (conn->keepalives_count == NULL) |
| 1057 | + return 1; |
| 1058 | + |
| 1059 | + count = atoi(conn->keepalives_count); |
| 1060 | + if (count < 0) |
| 1061 | + count = 0; |
| 1062 | + |
| 1063 | +#ifdef TCP_KEEPCNT |
| 1064 | + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT, |
| 1065 | + (char *) &count, sizeof(count)) < 0) |
| 1066 | + { |
| 1067 | + char sebuf[256]; |
| 1068 | + |
| 1069 | + appendPQExpBuffer(&conn->errorMessage, |
| 1070 | + libpq_gettext("setsockopt(TCP_KEEPCNT) failed: %s\n"), |
| 1071 | + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); |
| 1072 | + return 0; |
| 1073 | + } |
| 1074 | +#endif |
| 1075 | + |
| 1076 | + return 1; |
| 1077 | +} |
| 1078 | + |
946 | 1079 |
|
947 | 1080 | /* ----------
|
948 | 1081 | * connectDBStart -
|
@@ -1329,6 +1462,45 @@ PQconnectPoll(PGconn *conn)
|
1329 | 1462 | }
|
1330 | 1463 | #endif /* F_SETFD */
|
1331 | 1464 |
|
| 1465 | + if (!IS_AF_UNIX(addr_cur->ai_family)) |
| 1466 | + { |
| 1467 | + int on = 1; |
| 1468 | + int usekeepalives = useKeepalives(conn); |
| 1469 | + int err = 0; |
| 1470 | + |
| 1471 | + if (usekeepalives < 0) |
| 1472 | + { |
| 1473 | + appendPQExpBuffer(&conn->errorMessage, |
| 1474 | + libpq_gettext("keepalives parameter must be an integer\n")); |
| 1475 | + err = 1; |
| 1476 | + } |
| 1477 | + else if (usekeepalives == 0) |
| 1478 | + { |
| 1479 | + /* Do nothing */ |
| 1480 | + } |
| 1481 | + else if (setsockopt(conn->sock, |
| 1482 | + SOL_SOCKET, SO_KEEPALIVE, |
| 1483 | + (char *) &on, sizeof(on)) < 0) |
| 1484 | + { |
| 1485 | + appendPQExpBuffer(&conn->errorMessage, |
| 1486 | + libpq_gettext("setsockopt(SO_KEEPALIVE) failed: %s\n"), |
| 1487 | + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); |
| 1488 | + err = 1; |
| 1489 | + } |
| 1490 | + else if (!setKeepalivesIdle(conn) |
| 1491 | + || !setKeepalivesInterval(conn) |
| 1492 | + || !setKeepalivesCount(conn)) |
| 1493 | + err = 1; |
| 1494 | + |
| 1495 | + if (err) |
| 1496 | + { |
| 1497 | + closesocket(conn->sock); |
| 1498 | + conn->sock = -1; |
| 1499 | + conn->addr_cur = addr_cur->ai_next; |
| 1500 | + continue; |
| 1501 | + } |
| 1502 | + } |
| 1503 | + |
1332 | 1504 | /*----------
|
1333 | 1505 | * We have three methods of blocking SIGPIPE during
|
1334 | 1506 | * send() calls to this socket:
|
@@ -2290,6 +2462,14 @@ freePGconn(PGconn *conn)
|
2290 | 2462 | free(conn->pguser);
|
2291 | 2463 | if (conn->pgpass)
|
2292 | 2464 | free(conn->pgpass);
|
| 2465 | + if (conn->keepalives) |
| 2466 | + free(conn->keepalives); |
| 2467 | + if (conn->keepalives_idle) |
| 2468 | + free(conn->keepalives_idle); |
| 2469 | + if (conn->keepalives_interval) |
| 2470 | + free(conn->keepalives_interval); |
| 2471 | + if (conn->keepalives_count) |
| 2472 | + free(conn->keepalives_count); |
2293 | 2473 | if (conn->sslmode)
|
2294 | 2474 | free(conn->sslmode);
|
2295 | 2475 | if (conn->sslcert)
|
|
0 commit comments