Commit 5d7a555d authored by Tom Lane's avatar Tom Lane

Code review for recent libpq changes. Be more careful about error

handling in SIGPIPE processing; avoid unnecessary pollution of application
link-symbol namespace; spell 'pointer to function' in the conventional
way.
parent 9b711e76
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.291 2004/12/02 15:32:54 momjian Exp $ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.292 2004/12/02 23:20:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -202,6 +202,11 @@ static int parseServiceInfo(PQconninfoOption *options, ...@@ -202,6 +202,11 @@ static int parseServiceInfo(PQconninfoOption *options,
static char *pwdfMatchesString(char *buf, char *token); static char *pwdfMatchesString(char *buf, char *token);
static char *PasswordFromFile(char *hostname, char *port, char *dbname, static char *PasswordFromFile(char *hostname, char *port, char *dbname,
char *username); char *username);
static void default_threadlock(int acquire);
/* global variable because fe-auth.c needs to access it */
pgthreadlock_t pg_g_threadlock = default_threadlock;
/* /*
...@@ -3276,16 +3281,6 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username) ...@@ -3276,16 +3281,6 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
* if they are not required. * if they are not required.
*/ */
void
PQinitSSL(int do_init)
{
#ifdef USE_SSL
pq_initssllib = do_init;
#endif
}
static pgthreadlock_t default_threadlock;
static void static void
default_threadlock(int acquire) default_threadlock(int acquire)
{ {
...@@ -3313,17 +3308,15 @@ default_threadlock(int acquire) ...@@ -3313,17 +3308,15 @@ default_threadlock(int acquire)
#endif #endif
} }
pgthreadlock_t *g_threadlock = default_threadlock; pgthreadlock_t
PQregisterThreadLock(pgthreadlock_t newhandler)
pgthreadlock_t *
PQregisterThreadLock(pgthreadlock_t *newhandler)
{ {
pgthreadlock_t *prev; pgthreadlock_t prev = pg_g_threadlock;
prev = g_threadlock;
if (newhandler) if (newhandler)
g_threadlock = newhandler; pg_g_threadlock = newhandler;
else else
g_threadlock = default_threadlock; pg_g_threadlock = default_threadlock;
return prev; return prev;
} }
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* didn't really belong there. * didn't really belong there.
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.56 2004/12/02 15:32:54 momjian Exp $ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.57 2004/12/02 23:20:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -193,7 +193,7 @@ PQprint(FILE *fout, ...@@ -193,7 +193,7 @@ PQprint(FILE *fout,
{ {
usePipe = 1; usePipe = 1;
#ifdef ENABLE_THREAD_SAFETY #ifdef ENABLE_THREAD_SAFETY
pq_block_sigpipe(&osigset, &sigpipe_pending); if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0)
sigpipe_masked = true; sigpipe_masked = true;
#else #else
#ifndef WIN32 #ifndef WIN32
...@@ -316,8 +316,9 @@ PQprint(FILE *fout, ...@@ -316,8 +316,9 @@ PQprint(FILE *fout,
pclose(fout); pclose(fout);
#endif #endif
#ifdef ENABLE_THREAD_SAFETY #ifdef ENABLE_THREAD_SAFETY
/* we can't easily verify if EPIPE occurred, so say it did */
if (sigpipe_masked) if (sigpipe_masked)
pq_reset_sigpipe(&osigset, sigpipe_pending); pq_reset_sigpipe(&osigset, sigpipe_pending, true);
#else #else
#ifndef WIN32 #ifndef WIN32
pqsignal(SIGPIPE, oldsigpipehandler); pqsignal(SIGPIPE, oldsigpipehandler);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.58 2004/12/02 15:32:54 momjian Exp $ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.59 2004/12/02 23:20:21 tgl Exp $
* *
* NOTES * NOTES
* [ Most of these notes are wrong/obsolete, but perhaps not all ] * [ Most of these notes are wrong/obsolete, but perhaps not all ]
...@@ -147,7 +147,7 @@ static void SSLerrfree(char *buf); ...@@ -147,7 +147,7 @@ static void SSLerrfree(char *buf);
#endif #endif
#ifdef USE_SSL #ifdef USE_SSL
bool pq_initssllib = true; static bool pq_initssllib = true;
static SSL_CTX *SSL_context = NULL; static SSL_CTX *SSL_context = NULL;
#endif #endif
...@@ -212,6 +212,19 @@ KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\ ...@@ -212,6 +212,19 @@ KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\
/* Procedures common to all secure sessions */ /* Procedures common to all secure sessions */
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/*
* Exported (but as yet undocumented) function to allow application to
* tell us it's already initialized OpenSSL.
*/
void
PQinitSSL(int do_init)
{
#ifdef USE_SSL
pq_initssllib = do_init;
#endif
}
/* /*
* Initialize global context * Initialize global context
*/ */
...@@ -377,8 +390,10 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) ...@@ -377,8 +390,10 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
#ifdef ENABLE_THREAD_SAFETY #ifdef ENABLE_THREAD_SAFETY
sigset_t osigmask; sigset_t osigmask;
bool sigpipe_pending; bool sigpipe_pending;
bool got_epipe = false;
pq_block_sigpipe(&osigmask, &sigpipe_pending); if (pq_block_sigpipe(&osigmask, &sigpipe_pending) < 0)
return -1;
#else #else
#ifndef WIN32 #ifndef WIN32
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN); pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
...@@ -413,9 +428,13 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) ...@@ -413,9 +428,13 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
char sebuf[256]; char sebuf[256];
if (n == -1) if (n == -1)
{
if (SOCK_ERRNO == EPIPE)
got_epipe = true;
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"), libpq_gettext("SSL SYSCALL error: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
}
else else
{ {
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
...@@ -448,15 +467,16 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) ...@@ -448,15 +467,16 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
} }
else else
#endif #endif
{
n = send(conn->sock, ptr, len, 0); n = send(conn->sock, ptr, len, 0);
/* #ifdef ENABLE_THREAD_SAFETY
* Possible optimization: if sigpending() turns out to be an if (n < 0 && SOCK_ERRNO == EPIPE)
* expensive operation, we can set sigpipe_pending = 'true' got_epipe = true;
* here if errno != EPIPE, avoiding a sigpending call. #endif
*/ }
#ifdef ENABLE_THREAD_SAFETY #ifdef ENABLE_THREAD_SAFETY
pq_reset_sigpipe(&osigmask, sigpipe_pending); pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe);
#else #else
#ifndef WIN32 #ifndef WIN32
pqsignal(SIGPIPE, oldsighandler); pqsignal(SIGPIPE, oldsighandler);
...@@ -1228,13 +1248,14 @@ pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending) ...@@ -1228,13 +1248,14 @@ pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending)
{ {
sigset_t sigpipe_sigset; sigset_t sigpipe_sigset;
sigset_t sigset; sigset_t sigset;
int ret;
sigemptyset(&sigpipe_sigset); sigemptyset(&sigpipe_sigset);
sigaddset(&sigpipe_sigset, SIGPIPE); sigaddset(&sigpipe_sigset, SIGPIPE);
/* Block SIGPIPE and save previous mask for later reset */ /* Block SIGPIPE and save previous mask for later reset */
ret = pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset); SOCK_ERRNO_SET(pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset));
if (SOCK_ERRNO)
return -1;
/* We can have a pending SIGPIPE only if it was blocked before */ /* We can have a pending SIGPIPE only if it was blocked before */
if (sigismember(osigset, SIGPIPE)) if (sigismember(osigset, SIGPIPE))
...@@ -1251,31 +1272,39 @@ pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending) ...@@ -1251,31 +1272,39 @@ pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending)
else else
*sigpipe_pending = false; *sigpipe_pending = false;
return ret; return 0;
} }
/* /*
* Discard any pending SIGPIPE and reset the signal mask. * Discard any pending SIGPIPE and reset the signal mask.
* We might be discarding a blocked SIGPIPE that we didn't generate, *
* but we document that you can't keep blocked SIGPIPE calls across * Note: we are effectively assuming here that the C library doesn't queue
* libpq function calls. * up multiple SIGPIPE events. If it did, then we'd accidentally leave
* ours in the queue when an event was already pending and we got another.
* As long as it doesn't queue multiple events, we're OK because the caller
* can't tell the difference.
*
* The caller should say got_epipe = FALSE if it is certain that it
* didn't get an EPIPE error; in that case we'll skip the clear operation
* and things are definitely OK, queuing or no. If it got one or might have
* gotten one, pass got_epipe = TRUE.
*
* We do not want this to change errno, since if it did that could lose
* the error code from a preceding send(). We essentially assume that if
* we were able to do pq_block_sigpipe(), this can't fail.
*/ */
int void
pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending) pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe)
{ {
int save_errno = SOCK_ERRNO;
int signo; int signo;
sigset_t sigset; sigset_t sigset;
/* Clear SIGPIPE only if none was pending */ /* Clear SIGPIPE only if none was pending */
if (!sigpipe_pending) if (got_epipe && !sigpipe_pending)
{ {
if (sigpending(&sigset) != 0) if (sigpending(&sigset) == 0 &&
return -1; sigismember(&sigset, SIGPIPE))
/*
* Discard pending and blocked SIGPIPE
*/
if (sigismember(&sigset, SIGPIPE))
{ {
sigset_t sigpipe_sigset; sigset_t sigpipe_sigset;
...@@ -1283,12 +1312,12 @@ pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending) ...@@ -1283,12 +1312,12 @@ pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending)
sigaddset(&sigpipe_sigset, SIGPIPE); sigaddset(&sigpipe_sigset, SIGPIPE);
sigwait(&sigpipe_sigset, &signo); sigwait(&sigpipe_sigset, &signo);
if (signo != SIGPIPE)
return -1;
} }
} }
/* Restore saved block mask */ /* Restore saved block mask */
return pthread_sigmask(SIG_SETMASK, osigset, NULL); pthread_sigmask(SIG_SETMASK, osigset, NULL);
SOCK_ERRNO_SET(save_errno);
} }
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.114 2004/12/02 15:32:54 momjian Exp $ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.115 2004/12/02 23:20:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -279,6 +279,9 @@ extern SSL *PQgetssl(PGconn *conn); ...@@ -279,6 +279,9 @@ extern SSL *PQgetssl(PGconn *conn);
extern void *PQgetssl(PGconn *conn); extern void *PQgetssl(PGconn *conn);
#endif #endif
/* Tell libpq whether it needs to initialize OpenSSL */
extern void PQinitSSL(int do_init);
/* Set verbosity for PQerrorMessage and PQresultErrorMessage */ /* Set verbosity for PQerrorMessage and PQresultErrorMessage */
extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity); extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
...@@ -301,11 +304,9 @@ extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, ...@@ -301,11 +304,9 @@ extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
* Only required for multithreaded apps that use kerberos * Only required for multithreaded apps that use kerberos
* both within their app and for postgresql connections. * both within their app and for postgresql connections.
*/ */
typedef void (pgthreadlock_t) (int acquire); typedef void (*pgthreadlock_t) (int acquire);
extern pgthreadlock_t *PQregisterThreadLock(pgthreadlock_t *newhandler); extern pgthreadlock_t PQregisterThreadLock(pgthreadlock_t newhandler);
extern void PQinitSSL(int do_init);
/* === in fe-exec.c === */ /* === in fe-exec.c === */
...@@ -495,8 +496,6 @@ extern int PQdsplen(const unsigned char *s, int encoding); ...@@ -495,8 +496,6 @@ extern int PQdsplen(const unsigned char *s, int encoding);
/* Get encoding id from environment variable PGCLIENTENCODING */ /* Get encoding id from environment variable PGCLIENTENCODING */
extern int PQenv2encoding(void); extern int PQenv2encoding(void);
/* === in fe-secure.c === */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.97 2004/12/02 15:32:54 momjian Exp $ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.98 2004/12/02 23:20:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -379,13 +379,13 @@ extern int pqPacketSend(PGconn *conn, char pack_type, ...@@ -379,13 +379,13 @@ extern int pqPacketSend(PGconn *conn, char pack_type,
const void *buf, size_t buf_len); const void *buf, size_t buf_len);
#ifdef ENABLE_THREAD_SAFETY #ifdef ENABLE_THREAD_SAFETY
extern pgthreadlock_t *g_threadlock; extern pgthreadlock_t pg_g_threadlock;
#define pglock_thread() g_threadlock(true); #define pglock_thread() pg_g_threadlock(true)
#define pgunlock_thread() g_threadlock(false); #define pgunlock_thread() pg_g_threadlock(false)
#else #else
#define pglock_thread() ((void)0) #define pglock_thread() ((void) 0)
#define pgunlock_thread() ((void)0) #define pgunlock_thread() ((void) 0)
#endif #endif
...@@ -476,13 +476,10 @@ extern void pqsecure_close(PGconn *); ...@@ -476,13 +476,10 @@ extern void pqsecure_close(PGconn *);
extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len); extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len);
extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len); extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
#ifdef USE_SSL
extern bool pq_initssllib;
#endif
#ifdef ENABLE_THREAD_SAFETY #ifdef ENABLE_THREAD_SAFETY
int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending); extern int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending);
int pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending); extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending,
bool got_epipe);
#endif #endif
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment