|
11 | 11 | *
|
12 | 12 | *
|
13 | 13 | * IDENTIFICATION
|
14 |
| - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.57 2004/11/20 00:35:13 tgl Exp $ |
| 14 | + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.58 2004/12/02 15:32:54 momjian Exp $ |
15 | 15 | *
|
16 | 16 | * NOTES
|
17 | 17 | * [ Most of these notes are wrong/obsolete, but perhaps not all ]
|
@@ -152,12 +152,6 @@ boolpq_initssllib = true;
|
152 | 152 | staticSSL_CTX*SSL_context=NULL;
|
153 | 153 | #endif
|
154 | 154 |
|
155 |
| -#ifdefENABLE_THREAD_SAFETY |
156 |
| -staticvoidsigpipe_handler_ignore_send(intsigno); |
157 |
| -pthread_key_tpq_thread_in_send=0;/* initializer needed on Darwin */ |
158 |
| -staticpqsigfuncpq_pipe_handler; |
159 |
| -#endif |
160 |
| - |
161 | 155 | /* ------------------------------------------------------------ */
|
162 | 156 | /* Hardcoded values*/
|
163 | 157 | /* ------------------------------------------------------------ */
|
@@ -379,9 +373,12 @@ ssize_t
|
379 | 373 | pqsecure_write(PGconn*conn,constvoid*ptr,size_tlen)
|
380 | 374 | {
|
381 | 375 | ssize_tn;
|
382 |
| - |
| 376 | +
|
383 | 377 | #ifdefENABLE_THREAD_SAFETY
|
384 |
| -pthread_setspecific(pq_thread_in_send,"t"); |
| 378 | +sigset_tosigmask; |
| 379 | +boolsigpipe_pending; |
| 380 | + |
| 381 | +pq_block_sigpipe(&osigmask,&sigpipe_pending); |
385 | 382 | #else
|
386 | 383 | #ifndefWIN32
|
387 | 384 | pqsigfuncoldsighandler=pqsignal(SIGPIPE,SIG_IGN);
|
@@ -452,9 +449,14 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
452 | 449 | else
|
453 | 450 | #endif
|
454 | 451 | n=send(conn->sock,ptr,len,0);
|
| 452 | +/* |
| 453 | + *Possible optimization: if sigpending() turns out to be an |
| 454 | + *expensive operation, we can set sigpipe_pending = 'true' |
| 455 | + *here if errno != EPIPE, avoiding a sigpending call. |
| 456 | + */ |
455 | 457 |
|
456 | 458 | #ifdefENABLE_THREAD_SAFETY
|
457 |
| -pthread_setspecific(pq_thread_in_send,"f"); |
| 459 | +pq_reset_sigpipe(&osigmask,sigpipe_pending); |
458 | 460 | #else
|
459 | 461 | #ifndefWIN32
|
460 | 462 | pqsignal(SIGPIPE,oldsighandler);
|
@@ -1216,65 +1218,77 @@ PQgetssl(PGconn *conn)
|
1216 | 1218 | }
|
1217 | 1219 | #endif/* USE_SSL */
|
1218 | 1220 |
|
1219 |
| - |
1220 | 1221 | #ifdefENABLE_THREAD_SAFETY
|
1221 |
| -#ifndefWIN32 |
1222 | 1222 | /*
|
1223 |
| - *Check SIGPIPE handler and perhaps install our own. |
| 1223 | + *Block SIGPIPE for this thread. This prevents send()/write() from exiting |
| 1224 | + *the application. |
1224 | 1225 | */
|
1225 |
| -void |
1226 |
| -pq_check_sigpipe_handler(void) |
1227 |
| -{ |
1228 |
| -pthread_key_create(&pq_thread_in_send,NULL); |
1229 |
| - |
1230 |
| -/* |
1231 |
| - * Find current pipe handler and chain on to it. |
1232 |
| - */ |
1233 |
| -pq_pipe_handler=pqsignalinquire(SIGPIPE); |
1234 |
| -pqsignal(SIGPIPE,sigpipe_handler_ignore_send); |
1235 |
| -} |
1236 |
| - |
1237 |
| -/* |
1238 |
| - *Threaded SIGPIPE signal handler |
1239 |
| - */ |
1240 |
| -void |
1241 |
| -sigpipe_handler_ignore_send(intsigno) |
| 1226 | +int |
| 1227 | +pq_block_sigpipe(sigset_t*osigset,bool*sigpipe_pending) |
1242 | 1228 | {
|
1243 |
| -/* |
1244 |
| - * If we have gotten a SIGPIPE outside send(), chain or exit if we are |
1245 |
| - * at the end of the chain. Synchronous signals are delivered to the |
1246 |
| - * thread that caused the signal. |
1247 |
| - */ |
1248 |
| -if (!PQinSend()) |
| 1229 | +sigset_tsigpipe_sigset; |
| 1230 | +sigset_tsigset; |
| 1231 | +intret; |
| 1232 | + |
| 1233 | +sigemptyset(&sigpipe_sigset); |
| 1234 | +sigaddset(&sigpipe_sigset,SIGPIPE); |
| 1235 | + |
| 1236 | +/* Block SIGPIPE and save previous mask for later reset */ |
| 1237 | +ret=pthread_sigmask(SIG_BLOCK,&sigpipe_sigset,osigset); |
| 1238 | + |
| 1239 | +/* We can have a pending SIGPIPE only if it was blocked before */ |
| 1240 | +if (sigismember(osigset,SIGPIPE)) |
1249 | 1241 | {
|
1250 |
| -if (pq_pipe_handler==SIG_DFL)/* not set by application */ |
1251 |
| -exit(128+SIGPIPE);/* typical return value for SIG_DFL */ |
| 1242 | +/* Is there a pending SIGPIPE? */ |
| 1243 | +if (sigpending(&sigset)!=0) |
| 1244 | +return-1; |
| 1245 | + |
| 1246 | +if (sigismember(&sigset,SIGPIPE)) |
| 1247 | +*sigpipe_pending= true; |
1252 | 1248 | else
|
1253 |
| -(*pq_pipe_handler) (signo);/* call original handler */ |
| 1249 | +*sigpipe_pending= false; |
1254 | 1250 | }
|
| 1251 | +else |
| 1252 | +*sigpipe_pending= false; |
| 1253 | + |
| 1254 | +returnret; |
1255 | 1255 | }
|
1256 |
| -#endif |
1257 |
| -#endif |
1258 |
| - |
| 1256 | + |
1259 | 1257 | /*
|
1260 |
| - *Indicates whether the current thread is in send() |
1261 |
| - *For use by SIGPIPE signal handlers; they should |
1262 |
| - *ignore SIGPIPE when libpq is in send(). This means |
1263 |
| - *that the backend has died unexpectedly. |
| 1258 | + *Discard any pending SIGPIPE and reset the signal mask. |
| 1259 | + *We might be discarding a blocked SIGPIPE that we didn't generate, |
| 1260 | + *but we document that you can't keep blocked SIGPIPE calls across |
| 1261 | + *libpq function calls. |
1264 | 1262 | */
|
1265 |
| -pqbool |
1266 |
| -PQinSend(void) |
| 1263 | +int |
| 1264 | +pq_reset_sigpipe(sigset_t*osigset,boolsigpipe_pending) |
1267 | 1265 | {
|
1268 |
| -#ifdefENABLE_THREAD_SAFETY |
1269 |
| -return (pthread_getspecific(pq_thread_in_send)/* has it been set? */&& |
1270 |
| -*(char*)pthread_getspecific(pq_thread_in_send)=='t') ? true : false; |
1271 |
| -#else |
| 1266 | +intsigno; |
| 1267 | +sigset_tsigset; |
1272 | 1268 |
|
1273 |
| -/* |
1274 |
| - * No threading: our code ignores SIGPIPE around send(). Therefore, we |
1275 |
| - * can't be in send() if we are checking from a SIGPIPE signal |
1276 |
| - * handler. |
1277 |
| - */ |
1278 |
| -return false; |
1279 |
| -#endif |
| 1269 | +/* Clear SIGPIPE only if none was pending */ |
| 1270 | +if (!sigpipe_pending) |
| 1271 | +{ |
| 1272 | +if (sigpending(&sigset)!=0) |
| 1273 | +return-1; |
| 1274 | + |
| 1275 | +/* |
| 1276 | + *Discard pending and blocked SIGPIPE |
| 1277 | + */ |
| 1278 | +if (sigismember(&sigset,SIGPIPE)) |
| 1279 | +{ |
| 1280 | +sigset_tsigpipe_sigset; |
| 1281 | + |
| 1282 | +sigemptyset(&sigpipe_sigset); |
| 1283 | +sigaddset(&sigpipe_sigset,SIGPIPE); |
| 1284 | + |
| 1285 | +sigwait(&sigpipe_sigset,&signo); |
| 1286 | +if (signo!=SIGPIPE) |
| 1287 | +return-1; |
| 1288 | +} |
| 1289 | +} |
| 1290 | + |
| 1291 | +/* Restore saved block mask */ |
| 1292 | +returnpthread_sigmask(SIG_SETMASK,osigset,NULL); |
1280 | 1293 | }
|
| 1294 | +#endif |