Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcea80e7

Browse files
committed
Avoid extra system calls to block SIGPIPE if the platform provides either
sockopt(SO_NOSIGPIPE) or the MSG_NOSIGNAL flag to send().We assume these features are available if (1) the symbol is defined atcompile time and (2) the kernel doesn't reject the call at runtime.It might turn out that there are some platforms where (1) and (2) aretrue and yet the signal isn't really blocked, in which case applicationswould die on server crash. If that sort of thing gets reported, thenwe'll have to add additional defenses of some kind.Jeremy Kerr
1 parent655473a commitcea80e7

File tree

3 files changed

+151
-40
lines changed

3 files changed

+151
-40
lines changed

‎src/interfaces/libpq/fe-connect.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.375 2009/06/11 14:49:13 momjian Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.376 2009/07/24 17:58:31 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1018,6 +1018,7 @@ PQconnectPoll(PGconn *conn)
10181018
{
10191019
PGresult*res;
10201020
charsebuf[256];
1021+
intoptval;
10211022

10221023
if (conn==NULL)
10231024
returnPGRES_POLLING_FAILED;
@@ -1153,6 +1154,46 @@ PQconnectPoll(PGconn *conn)
11531154
}
11541155
#endif/* F_SETFD */
11551156

1157+
/*----------
1158+
* We have three methods of blocking SIGPIPE during
1159+
* send() calls to this socket:
1160+
*
1161+
* - setsockopt(sock, SO_NOSIGPIPE)
1162+
* - send(sock, ..., MSG_NOSIGNAL)
1163+
* - setting the signal mask to SIG_IGN during send()
1164+
*
1165+
* The third method requires three syscalls per send,
1166+
* so we prefer either of the first two, but they are
1167+
* less portable. The state is tracked in the following
1168+
* members of PGconn:
1169+
*
1170+
* conn->sigpipe_so- we have set up SO_NOSIGPIPE
1171+
* conn->sigpipe_flag- we're specifying MSG_NOSIGNAL
1172+
*
1173+
* If we can use SO_NOSIGPIPE, then set sigpipe_so here
1174+
* and we're done. Otherwise, set sigpipe_flag so that
1175+
* we will try MSG_NOSIGNAL on sends. If we get an error
1176+
* with MSG_NOSIGNAL, we'll clear that flag and revert to
1177+
* signal masking.
1178+
*----------
1179+
*/
1180+
conn->sigpipe_so= false;
1181+
#ifdefMSG_NOSIGNAL
1182+
conn->sigpipe_flag= true;
1183+
#else
1184+
conn->sigpipe_flag= false;
1185+
#endif/* MSG_NOSIGNAL */
1186+
1187+
#ifdefSO_NOSIGPIPE
1188+
optval=1;
1189+
if (setsockopt(conn->sock,SOL_SOCKET,SO_NOSIGPIPE,
1190+
(char*)&optval,sizeof(optval))==0)
1191+
{
1192+
conn->sigpipe_so= true;
1193+
conn->sigpipe_flag= false;
1194+
}
1195+
#endif/* SO_NOSIGPIPE */
1196+
11561197
/*
11571198
* Start/make connection. This should not block, since we
11581199
* are in nonblock mode. If it does, well, too bad.
@@ -1214,7 +1255,6 @@ PQconnectPoll(PGconn *conn)
12141255

12151256
caseCONNECTION_STARTED:
12161257
{
1217-
intoptval;
12181258
ACCEPT_TYPE_ARG3optlen=sizeof(optval);
12191259

12201260
/*

‎src/interfaces/libpq/fe-secure.c

Lines changed: 106 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
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
#ifndefWIN32
125+
126+
#defineSIGPIPE_MASKED(conn)((conn)->sigpipe_so || (conn)->sigpipe_flag)
127+
125128
#ifdefENABLE_THREAD_SAFETY
126129

127-
#defineDISABLE_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+
structsigpipe_info
131+
{
132+
sigset_toldsigmask;
133+
boolsigpipe_pending;
134+
boolgot_epipe;
135+
};
134136

135-
#defineREMEMBER_EPIPE(cond) \
137+
#defineDECLARE_SIGPIPE_INFO(spinfo) struct sigpipe_info spinfo
138+
139+
#defineDISABLE_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+
#defineREMEMBER_EPIPE(spinfo,cond) \
136151
do { \
137152
if (cond) \
138-
got_epipe = true; \
153+
(spinfo).got_epipe = true; \
139154
} while (0)
140155

141-
#defineRESTORE_SIGPIPE() \
142-
pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe)
143-
#else/* !ENABLE_THREAD_SAFETY */
156+
#defineRESTORE_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-
#defineDISABLE_SIGPIPE(failaction) \
146-
pqsigfuncoldsighandler = pqsignal(SIGPIPE, SIG_IGN)
163+
#else/* !ENABLE_THREAD_SAFETY */
147164

148-
#defineREMEMBER_EPIPE(cond)
165+
#defineDECLARE_SIGPIPE_INFO(spinfo) pqsigfunc spinfo = NULL
149166

150-
#defineRESTORE_SIGPIPE() \
151-
pqsignal(SIGPIPE, oldsighandler)
152-
#endif/* ENABLE_THREAD_SAFETY */
153-
#else/* WIN32 */
167+
#defineDISABLE_SIGPIPE(conn,spinfo,failaction) \
168+
do { \
169+
if (!SIGPIPE_MASKED(conn)) \
170+
spinfo = pqsignal(SIGPIPE, SIG_IGN); \
171+
} while (0)
172+
173+
#defineREMEMBER_EPIPE(spinfo,cond)
174+
175+
#defineRESTORE_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-
#defineDISABLE_SIGPIPE(failaction)
156-
#defineREMEMBER_EPIPE(cond)
157-
#defineRESTORE_SIGPIPE()
158-
#endif/* WIN32 */
183+
#else/* WIN32 */
184+
185+
#defineDECLARE_SIGPIPE_INFO(spinfo)
186+
#defineDISABLE_SIGPIPE(conn,spinfo,failaction)
187+
#defineREMEMBER_EPIPE(spinfo,cond)
188+
#defineRESTORE_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? */
232264
if (conn->ssl==NULL)
233265
{
266+
/* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */
267+
conn->sigpipe_flag= false;
268+
234269
if (!(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)
283318
if (conn->ssl)
284319
{
285320
interr;
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

290326
rloop:
291327
n=SSL_read(conn->ssl,ptr,len);
@@ -312,7 +348,7 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
312348

313349
if (n==-1)
314350
{
315-
REMEMBER_EPIPE(SOCK_ERRNO==EPIPE);
351+
REMEMBER_EPIPE(spinfo,SOCK_ERRNO==EPIPE);
316352
printfPQExpBuffer(&conn->errorMessage,
317353
libpq_gettext("SSL SYSCALL error: %s\n"),
318354
SOCK_STRERROR(SOCK_ERRNO,sebuf,sizeof(sebuf)));
@@ -348,7 +384,7 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
348384
break;
349385
}
350386

351-
RESTORE_SIGPIPE();
387+
RESTORE_SIGPIPE(conn,spinfo);
352388
}
353389
else
354390
#endif
@@ -364,14 +400,15 @@ ssize_t
364400
pqsecure_write(PGconn*conn,constvoid*ptr,size_tlen)
365401
{
366402
ssize_tn;
367-
368-
DISABLE_SIGPIPE(return-1);
403+
DECLARE_SIGPIPE_INFO(spinfo);
369404

370405
#ifdefUSE_SSL
371406
if (conn->ssl)
372407
{
373408
interr;
374409

410+
DISABLE_SIGPIPE(conn,spinfo,return-1);
411+
375412
n=SSL_write(conn->ssl,ptr,len);
376413
err=SSL_get_error(conn->ssl,n);
377414
switch (err)
@@ -396,7 +433,7 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
396433

397434
if (n==-1)
398435
{
399-
REMEMBER_EPIPE(SOCK_ERRNO==EPIPE);
436+
REMEMBER_EPIPE(spinfo,SOCK_ERRNO==EPIPE);
400437
printfPQExpBuffer(&conn->errorMessage,
401438
libpq_gettext("SSL SYSCALL error: %s\n"),
402439
SOCK_STRERROR(SOCK_ERRNO,sebuf,sizeof(sebuf)));
@@ -434,11 +471,41 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
434471
else
435472
#endif
436473
{
437-
n=send(conn->sock,ptr,len,0);
438-
REMEMBER_EPIPE(n<0&&SOCK_ERRNO==EPIPE);
474+
intflags=0;
475+
476+
#ifdefMSG_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+
#ifdefMSG_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

443510
returnn;
444511
}
@@ -1220,14 +1287,16 @@ close_SSL(PGconn *conn)
12201287
{
12211288
if (conn->ssl)
12221289
{
1223-
DISABLE_SIGPIPE((void)0);
1290+
DECLARE_SIGPIPE_INFO(spinfo);
1291+
1292+
DISABLE_SIGPIPE(conn,spinfo, (void)0);
12241293
SSL_shutdown(conn->ssl);
12251294
SSL_free(conn->ssl);
12261295
conn->ssl=NULL;
12271296
pqsecure_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

12331302
if (conn->peer)

‎src/interfaces/libpq/libpq-int.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
15-
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.143 2009/06/23 18:13:23 mha Exp $
15+
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.144 2009/07/24 17:58:31 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -341,6 +341,8 @@ struct pg_conn
341341
ProtocolVersionpversion;/* FE/BE protocol version in use */
342342
intsversion;/* server version, e.g. 70401 for 7.4.1 */
343343
boolpassword_needed;/* true if server demanded a password */
344+
boolsigpipe_so;/* have we masked SIGPIPE via SO_NOSIGPIPE? */
345+
boolsigpipe_flag;/* can we mask SIGPIPE via MSG_NOSIGNAL? */
344346

345347
/* Transient state needed while establishing connection */
346348
structaddrinfo*addrlist;/* list of possible backend addresses */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp