Skip to content

Commit

Permalink
Solaris based operating systems don't define MSG_NOSIGNAL and SO_NOSI…
Browse files Browse the repository at this point in the history
…GPIPE.

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>
  • Loading branch information
asalkeld committed Oct 22, 2012
1 parent bcba4a2 commit 79059bc
Showing 1 changed file with 54 additions and 4 deletions.
58 changes: 54 additions & 4 deletions lib/ipc_us.c
Expand Up @@ -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
Expand All @@ -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],
Expand All @@ -104,6 +128,7 @@ qb_ipc_us_send(struct qb_ipc_one_way *one_way, const void *msg, size_t len)
if (errno == EAGAIN && processed > 0) {
goto retry_send;
} else {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
return -errno;
}
}
Expand All @@ -112,6 +137,9 @@ qb_ipc_us_send(struct qb_ipc_one_way *one_way, const void *msg, size_t len)
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;
Expand All @@ -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],
Expand All @@ -143,6 +173,7 @@ qb_ipc_us_sendv(struct qb_ipc_one_way *one_way, const struct iovec *iov,
(processed > 0 || iov_p > 0)) {
goto retry_send;
} else {
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
return -errno;
}
}
Expand All @@ -159,6 +190,9 @@ qb_ipc_us_sendv(struct qb_ipc_one_way *one_way, const struct iovec *iov,
} 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;
Expand All @@ -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;
Expand All @@ -184,9 +220,11 @@ qb_ipc_us_recv_msghdr(int32_t s, struct msghdr *hdr, char *msg, size_t len)
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;
Expand All @@ -196,6 +234,7 @@ qb_ipc_us_recv_msghdr(int32_t s, struct msghdr *hdr, char *msg, size_t len)
if (processed != len) {
goto retry_recv;
}
sigpipe_ctl(QB_SIGPIPE_DEFAULT);
assert(processed == len);

return processed;
Expand Down Expand Up @@ -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);
Expand All @@ -266,16 +307,19 @@ qb_ipc_us_recv(struct qb_ipc_one_way * one_way,
(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);
Expand All @@ -286,6 +330,7 @@ qb_ipc_us_recv(struct qb_ipc_one_way * one_way,
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;
Expand All @@ -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);
Expand All @@ -318,9 +365,11 @@ qb_ipc_us_recv_at_most(struct qb_ipc_one_way * one_way,
(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);
Expand All @@ -339,6 +388,7 @@ qb_ipc_us_recv_at_most(struct qb_ipc_one_way * one_way,
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);
Expand All @@ -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;
Expand Down

1 comment on commit 79059bc

@grueni
Copy link
Contributor

@grueni grueni commented on 79059bc Oct 22, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I merged the commit with my upstream or in other words I replaced my version of ipc_us.c with this version.
It worked without any problems.

Please sign in to comment.