Solaris based operating systems don't define MSG_NOSIGNAL and SO_NOSIGPIPE.

They return SIGPIPE when send is used with a closed socket. A SIGPIPE handler
must be used or SIGPIPE should be set ignored with SIG_IGN. In this case send
returns -1 instead of a SIGPIPE. The setting to ignore SIGPIPE is global and
should be used only where it is absolutely necessary.

Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
This commit is contained in:
Angus Salkeld 2012-10-22 11:15:05 +11:00
parent bcba4a2983
commit 79059bcae3

View File

@ -74,14 +74,36 @@ struct ipc_auth_ugp {
static int32_t qb_ipcs_us_connection_acceptor(int fd, int revent, void *data);
static int32_t qb_ipc_us_fc_get(struct qb_ipc_one_way *one_way);
#ifdef SO_NOSIGPIPE
static void
socket_nosigpipe(int32_t s)
{
#ifdef SO_NOSIGPIPE
int32_t on = 1;
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
#endif /* SO_NOSIGPIPE */
}
enum qb_sigpipe_ctl {
QB_SIGPIPE_IGNORE,
QB_SIGPIPE_DEFAULT,
};
static void sigpipe_ctl(enum qb_sigpipe_ctl ctl)
{
#if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE)
struct sigaction act;
struct sigaction oact;
act.sa_handler = SIG_IGN;
if (ctl == QB_SIGPIPE_IGNORE) {
sigaction(SIGPIPE, &act, &oact);
} else {
sigaction(SIGPIPE, &oact, NULL);
}
#endif /* !MSG_NOSIGNAL && !defined(SO_NOSIGPIPE) */
}
#endif
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
@ -94,6 +116,8 @@ qb_ipc_us_send(struct qb_ipc_one_way *one_way, const void *msg, size_t len)
int32_t processed = 0;
char *rbuf = (char *)msg;
sigpipe_ctl(QB_SIGPIPE_IGNORE);
retry_send:
result = send(one_way->u.us.sock,
&rbuf[processed],
@ -104,6 +128,7 @@ retry_send:
if (errno == EAGAIN && processed > 0) {
goto retry_send;
} else {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
return -errno;
}
}
@ -112,6 +137,9 @@ retry_send:
if (processed != len) {
goto retry_send;
}
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
if (one_way->type == QB_IPC_SOCKET) {
struct ipc_us_control *ctl = NULL;
ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
@ -132,6 +160,8 @@ qb_ipc_us_sendv(struct qb_ipc_one_way *one_way, const struct iovec *iov,
int32_t iov_p = 0;
char *rbuf = (char *)iov[iov_p].iov_base;
sigpipe_ctl(QB_SIGPIPE_IGNORE);
retry_send:
result = send(one_way->u.us.sock,
&rbuf[processed],
@ -143,6 +173,7 @@ retry_send:
(processed > 0 || iov_p > 0)) {
goto retry_send;
} else {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
return -errno;
}
}
@ -159,6 +190,9 @@ retry_send:
} else {
goto retry_send;
}
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
if (one_way->type == QB_IPC_SOCKET) {
struct ipc_us_control *ctl;
ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
@ -175,6 +209,8 @@ qb_ipc_us_recv_msghdr(int32_t s, struct msghdr *hdr, char *msg, size_t len)
int32_t result;
int32_t processed = 0;
sigpipe_ctl(QB_SIGPIPE_IGNORE);
retry_recv:
hdr->msg_iov->iov_base = &msg[processed];
hdr->msg_iov->iov_len = len - processed;
@ -184,9 +220,11 @@ retry_recv:
goto retry_recv;
}
if (result == -1) {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
return -errno;
}
if (result == 0) {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
qb_util_log(LOG_DEBUG,
"recv(fd %d) got 0 bytes assuming ENOTCONN", s);
return -ENOTCONN;
@ -196,6 +234,7 @@ retry_recv:
if (processed != len) {
goto retry_recv;
}
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
assert(processed == len);
return processed;
@ -257,6 +296,8 @@ qb_ipc_us_recv(struct qb_ipc_one_way * one_way,
int32_t to_recv = len;
char *data = msg;
sigpipe_ctl(QB_SIGPIPE_IGNORE);
retry_recv:
result = recv(one_way->u.us.sock, &data[processed], to_recv,
MSG_NOSIGNAL | MSG_WAITALL);
@ -266,16 +307,19 @@ retry_recv:
(processed > 0 || timeout == -1)) {
goto retry_recv;
} else if (errno == ECONNRESET || errno == EPIPE) {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
qb_util_perror(LOG_DEBUG,
"recv(fd %d) converting to ENOTCONN",
one_way->u.us.sock);
return -ENOTCONN;
} else {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
return -errno;
}
}
if (result == 0) {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
qb_util_log(LOG_DEBUG,
"recv(fd %d) got 0 bytes assuming ENOTCONN",
one_way->u.us.sock);
@ -286,6 +330,7 @@ retry_recv:
if (processed != len) {
goto retry_recv;
}
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
if (one_way->type == QB_IPC_SOCKET) {
struct ipc_us_control *ctl = NULL;
ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
@ -310,6 +355,8 @@ qb_ipc_us_recv_at_most(struct qb_ipc_one_way * one_way,
struct ipc_us_control *ctl = NULL;
struct qb_ipc_request_header *hdr = NULL;
sigpipe_ctl(QB_SIGPIPE_IGNORE);
retry_recv:
result = recv(one_way->u.us.sock, &data[processed], to_recv,
MSG_NOSIGNAL | MSG_WAITALL);
@ -318,9 +365,11 @@ retry_recv:
(processed > 0 || timeout == -1)) {
goto retry_recv;
} else {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
return -errno;
}
} else if (result == 0) {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
qb_util_log(LOG_DEBUG,
"recv(fd %d) got 0 bytes assuming ENOTCONN",
one_way->u.us.sock);
@ -339,6 +388,7 @@ retry_recv:
if (to_recv > 0) {
goto retry_recv;
}
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
if (ctl) {
(void)qb_atomic_int_dec_and_test(&ctl->sent);
@ -358,9 +408,9 @@ qb_ipcc_us_sock_connect(const char *socket_name, int32_t * sock_pt)
if (request_fd == -1) {
return -errno;
}
#ifdef SO_NOSIGPIPE
socket_nosigpipe(request_fd);
#endif /* SO_NOSIGPIPE */
res = qb_sys_fd_nonblock_cloexec_set(request_fd);
if (res < 0) {
goto error_connect;