|
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 |