diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c index 1c5d7422f..a719063a8 100644 --- a/src/proto_sockpair.c +++ b/src/proto_sockpair.c @@ -137,6 +137,30 @@ int sockpair_bind_receiver(struct receiver *rx, char **errmsg) if (rx->flags & RX_F_BOUND) return ERR_NONE; + if (rx->flags & RX_F_MUST_DUP) { + /* this is a secondary receiver that is an exact copy of a + * reference which must already be bound (or has failed). + * We'll try to dup() the other one's FD and take it. We + * try hard not to reconfigure the socket since it's shared. + */ + BUG_ON(!rx->shard_info); + if (!(rx->shard_info->ref->flags & RX_F_BOUND)) { + /* it's assumed that the first one has already reported + * the error, let's not spam with another one, and do + * not set ERR_ALERT. + */ + err |= ERR_RETRYABLE; + goto bind_ret_err; + } + /* taking the other one's FD will result in it being marked + * extern and being dup()ed. Let's mark the receiver as + * inherited so that it properly bypasses all second-stage + * setup and avoids being passed to new processes. + */ + rx->flags |= RX_F_INHERITED; + rx->fd = rx->shard_info->ref->fd; + } + if (rx->fd == -1) { err |= ERR_FATAL | ERR_ALERT; memprintf(errmsg, "sockpair may be only used with inherited FDs"); @@ -164,6 +188,7 @@ int sockpair_bind_receiver(struct receiver *rx, char **errmsg) if (errmsg && *errmsg) memprintf(errmsg, "%s for [fd %d]", *errmsg, rx->fd); + bind_ret_err: return err; bind_close_return: diff --git a/src/sock_inet.c b/src/sock_inet.c index f85582cfd..b7861f788 100644 --- a/src/sock_inet.c +++ b/src/sock_inet.c @@ -288,6 +288,30 @@ int sock_inet_bind_receiver(struct receiver *rx, char **errmsg) if (rx->flags & RX_F_BOUND) return ERR_NONE; + if (rx->flags & RX_F_MUST_DUP) { + /* this is a secondary receiver that is an exact copy of a + * reference which must already be bound (or has failed). + * We'll try to dup() the other one's FD and take it. We + * try hard not to reconfigure the socket since it's shared. + */ + BUG_ON(!rx->shard_info); + if (!(rx->shard_info->ref->flags & RX_F_BOUND)) { + /* it's assumed that the first one has already reported + * the error, let's not spam with another one, and do + * not set ERR_ALERT. + */ + err |= ERR_RETRYABLE; + goto bind_ret_err; + } + /* taking the other one's FD will result in it being marked + * extern and being dup()ed. Let's mark the receiver as + * inherited so that it properly bypasses all second-stage + * setup and avoids being passed to new processes. + */ + rx->flags |= RX_F_INHERITED; + rx->fd = rx->shard_info->ref->fd; + } + /* if no FD was assigned yet, we'll have to either find a compatible * one or create a new one. */ @@ -421,6 +445,7 @@ int sock_inet_bind_receiver(struct receiver *rx, char **errmsg) addr_to_str(&addr_inet, pn, sizeof(pn)); memprintf(errmsg, "%s for [%s:%d]", *errmsg, pn, get_host_port(&addr_inet)); } + bind_ret_err: return err; bind_close_return: diff --git a/src/sock_unix.c b/src/sock_unix.c index ac3cb642d..1f7da504d 100644 --- a/src/sock_unix.c +++ b/src/sock_unix.c @@ -154,6 +154,30 @@ int sock_unix_bind_receiver(struct receiver *rx, char **errmsg) if (rx->flags & RX_F_BOUND) return ERR_NONE; + if (rx->flags & RX_F_MUST_DUP) { + /* this is a secondary receiver that is an exact copy of a + * reference which must already be bound (or has failed). + * We'll try to dup() the other one's FD and take it. We + * try hard not to reconfigure the socket since it's shared. + */ + BUG_ON(!rx->shard_info); + if (!(rx->shard_info->ref->flags & RX_F_BOUND)) { + /* it's assumed that the first one has already reported + * the error, let's not spam with another one, and do + * not set ERR_ALERT. + */ + err |= ERR_RETRYABLE; + goto bind_ret_err; + } + /* taking the other one's FD will result in it being marked + * extern and being dup()ed. Let's mark the receiver as + * inherited so that it properly bypasses all second-stage + * setup and avoids being passed to new processes. + */ + rx->flags |= RX_F_INHERITED; + rx->fd = rx->shard_info->ref->fd; + } + /* if no FD was assigned yet, we'll have to either find a compatible * one or create a new one. */ @@ -347,6 +371,7 @@ int sock_unix_bind_receiver(struct receiver *rx, char **errmsg) else memprintf(errmsg, "%s [fd %d]", *errmsg, fd); } + bind_ret_err: return err; bind_close_return: