1111 *
1212 *
1313 * IDENTIFICATION
14- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.127 2009/06/23 18:13:23 mha Exp $
14+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.128 2009/07/24 17:58:31 tgl Exp $
1515 *
1616 * NOTES
1717 *
@@ -118,44 +118,76 @@ static long win32_ssl_create_mutex = 0;
118118
119119/*
120120 * Macros to handle disabling and then restoring the state of SIGPIPE handling.
121- *Note that DISABLE_SIGPIPE() must appear at the start of a block .
121+ *On Windows, these are all no-ops since there's no SIGPIPEs .
122122 */
123123
124124#ifndef WIN32
125+
126+ #define SIGPIPE_MASKED (conn )((conn)->sigpipe_so || (conn)->sigpipe_flag)
127+
125128#ifdef ENABLE_THREAD_SAFETY
126129
127- #define DISABLE_SIGPIPE (failaction ) \
128- sigset_tosigmask; \
129- boolsigpipe_pending; \
130- boolgot_epipe = false; \
131- \
132- if (pq_block_sigpipe(&osigmask, &sigpipe_pending) < 0) \
133- failaction
130+ struct sigpipe_info
131+ {
132+ sigset_t oldsigmask ;
133+ bool sigpipe_pending ;
134+ bool got_epipe ;
135+ };
134136
135- #define REMEMBER_EPIPE (cond ) \
137+ #define DECLARE_SIGPIPE_INFO (spinfo ) struct sigpipe_info spinfo
138+
139+ #define DISABLE_SIGPIPE (conn ,spinfo ,failaction ) \
140+ do { \
141+ (spinfo).got_epipe = false; \
142+ if (!SIGPIPE_MASKED(conn)) \
143+ { \
144+ if (pq_block_sigpipe(&(spinfo).oldsigmask, \
145+ &(spinfo).sigpipe_pending) < 0) \
146+ failaction; \
147+ } \
148+ } while (0)
149+
150+ #define REMEMBER_EPIPE (spinfo ,cond ) \
136151do { \
137152if (cond) \
138- got_epipe = true; \
153+ (spinfo). got_epipe = true; \
139154} while (0)
140155
141- #define RESTORE_SIGPIPE () \
142- pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe)
143- #else /* !ENABLE_THREAD_SAFETY */
156+ #define RESTORE_SIGPIPE (conn ,spinfo ) \
157+ do { \
158+ if (!SIGPIPE_MASKED(conn)) \
159+ pq_reset_sigpipe(&(spinfo).oldsigmask, (spinfo).sigpipe_pending, \
160+ (spinfo).got_epipe); \
161+ } while (0)
144162
145- #define DISABLE_SIGPIPE (failaction ) \
146- pqsigfuncoldsighandler = pqsignal(SIGPIPE, SIG_IGN)
163+ #else /* !ENABLE_THREAD_SAFETY */
147164
148- #define REMEMBER_EPIPE ( cond )
165+ #define DECLARE_SIGPIPE_INFO ( spinfo ) pqsigfunc spinfo = NULL
149166
150- #define RESTORE_SIGPIPE () \
151- pqsignal(SIGPIPE, oldsighandler)
152- #endif /* ENABLE_THREAD_SAFETY */
153- #else /* WIN32 */
167+ #define DISABLE_SIGPIPE (conn ,spinfo ,failaction ) \
168+ do { \
169+ if (!SIGPIPE_MASKED(conn)) \
170+ spinfo = pqsignal(SIGPIPE, SIG_IGN); \
171+ } while (0)
172+
173+ #define REMEMBER_EPIPE (spinfo ,cond )
174+
175+ #define RESTORE_SIGPIPE (conn ,spinfo ) \
176+ do { \
177+ if (!SIGPIPE_MASKED(conn)) \
178+ pqsignal(SIGPIPE, spinfo); \
179+ } while (0)
180+
181+ #endif /* ENABLE_THREAD_SAFETY */
154182
155- #define DISABLE_SIGPIPE (failaction )
156- #define REMEMBER_EPIPE (cond )
157- #define RESTORE_SIGPIPE ()
158- #endif /* WIN32 */
183+ #else /* WIN32 */
184+
185+ #define DECLARE_SIGPIPE_INFO (spinfo )
186+ #define DISABLE_SIGPIPE (conn ,spinfo ,failaction )
187+ #define REMEMBER_EPIPE (spinfo ,cond )
188+ #define RESTORE_SIGPIPE (conn ,spinfo )
189+
190+ #endif /* WIN32 */
159191
160192/* ------------------------------------------------------------ */
161193/* Procedures common to all secure sessions*/
@@ -231,6 +263,9 @@ pqsecure_open_client(PGconn *conn)
231263/* First time through? */
232264if (conn -> ssl == NULL )
233265{
266+ /* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */
267+ conn -> sigpipe_flag = false;
268+
234269if (!(conn -> ssl = SSL_new (SSL_context ))||
235270!SSL_set_app_data (conn -> ssl ,conn )||
236271!SSL_set_fd (conn -> ssl ,conn -> sock ))
@@ -283,9 +318,10 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
283318if (conn -> ssl )
284319{
285320int err ;
321+ DECLARE_SIGPIPE_INFO (spinfo );
286322
287323/* SSL_read can write to the socket, so we need to disable SIGPIPE */
288- DISABLE_SIGPIPE (return - 1 );
324+ DISABLE_SIGPIPE (conn , spinfo , return - 1 );
289325
290326rloop :
291327n = SSL_read (conn -> ssl ,ptr ,len );
@@ -312,7 +348,7 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
312348
313349if (n == -1 )
314350{
315- REMEMBER_EPIPE (SOCK_ERRNO == EPIPE );
351+ REMEMBER_EPIPE (spinfo , SOCK_ERRNO == EPIPE );
316352printfPQExpBuffer (& conn -> errorMessage ,
317353libpq_gettext ("SSL SYSCALL error: %s\n" ),
318354SOCK_STRERROR (SOCK_ERRNO ,sebuf ,sizeof (sebuf )));
@@ -348,7 +384,7 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
348384break ;
349385}
350386
351- RESTORE_SIGPIPE ();
387+ RESTORE_SIGPIPE (conn , spinfo );
352388}
353389else
354390#endif
@@ -364,14 +400,15 @@ ssize_t
364400pqsecure_write (PGconn * conn ,const void * ptr ,size_t len )
365401{
366402ssize_t n ;
367-
368- DISABLE_SIGPIPE (return - 1 );
403+ DECLARE_SIGPIPE_INFO (spinfo );
369404
370405#ifdef USE_SSL
371406if (conn -> ssl )
372407{
373408int err ;
374409
410+ DISABLE_SIGPIPE (conn ,spinfo ,return - 1 );
411+
375412n = SSL_write (conn -> ssl ,ptr ,len );
376413err = SSL_get_error (conn -> ssl ,n );
377414switch (err )
@@ -396,7 +433,7 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
396433
397434if (n == -1 )
398435{
399- REMEMBER_EPIPE (SOCK_ERRNO == EPIPE );
436+ REMEMBER_EPIPE (spinfo , SOCK_ERRNO == EPIPE );
400437printfPQExpBuffer (& conn -> errorMessage ,
401438libpq_gettext ("SSL SYSCALL error: %s\n" ),
402439SOCK_STRERROR (SOCK_ERRNO ,sebuf ,sizeof (sebuf )));
@@ -434,11 +471,41 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
434471else
435472#endif
436473{
437- n = send (conn -> sock ,ptr ,len ,0 );
438- REMEMBER_EPIPE (n < 0 && SOCK_ERRNO == EPIPE );
474+ int flags = 0 ;
475+
476+ #ifdef MSG_NOSIGNAL
477+ if (conn -> sigpipe_flag )
478+ flags |=MSG_NOSIGNAL ;
479+
480+ retry_masked :
481+
482+ #endif /* MSG_NOSIGNAL */
483+
484+ DISABLE_SIGPIPE (conn ,spinfo ,return - 1 );
485+
486+ n = send (conn -> sock ,ptr ,len ,flags );
487+
488+ if (n < 0 )
489+ {
490+ /*
491+ * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't
492+ * available on this machine. So, clear sigpipe_flag so we don't
493+ * try the flag again, and retry the send().
494+ */
495+ #ifdef MSG_NOSIGNAL
496+ if (flags != 0 && SOCK_ERRNO == EINVAL )
497+ {
498+ conn -> sigpipe_flag = false;
499+ flags = 0 ;
500+ gotoretry_masked ;
501+ }
502+ #endif /* MSG_NOSIGNAL */
503+
504+ REMEMBER_EPIPE (spinfo ,SOCK_ERRNO == EPIPE );
505+ }
439506}
440507
441- RESTORE_SIGPIPE ();
508+ RESTORE_SIGPIPE (conn , spinfo );
442509
443510return n ;
444511}
@@ -1220,14 +1287,16 @@ close_SSL(PGconn *conn)
12201287{
12211288if (conn -> ssl )
12221289{
1223- DISABLE_SIGPIPE ((void )0 );
1290+ DECLARE_SIGPIPE_INFO (spinfo );
1291+
1292+ DISABLE_SIGPIPE (conn ,spinfo , (void )0 );
12241293SSL_shutdown (conn -> ssl );
12251294SSL_free (conn -> ssl );
12261295conn -> ssl = NULL ;
12271296pqsecure_destroy ();
12281297/* We have to assume we got EPIPE */
1229- REMEMBER_EPIPE (true);
1230- RESTORE_SIGPIPE ();
1298+ REMEMBER_EPIPE (spinfo , true);
1299+ RESTORE_SIGPIPE (conn , spinfo );
12311300}
12321301
12331302if (conn -> peer )