MEDIUM: sockpair: implement sockpair_bind_receiver()
Note that for now we don't have a sockpair.c file to host that unusual
family, so the new function was placed directly into proto_sockpair.c.
It's no big deal given that this family is currently not shared with
multiple protocols.
The function does almost nothing but setting up the receiver. This is
normal as the socket the FDs are passed onto are supposed to have been
already created somewhere else, and the only usable identifier for such
a socket pair is the receiving FD itself.
The function was assigned to sockpair's ->bind() and is not used yet.
diff --git a/include/haproxy/proto_sockpair.h b/include/haproxy/proto_sockpair.h
index ff1482e..b04ebea 100644
--- a/include/haproxy/proto_sockpair.h
+++ b/include/haproxy/proto_sockpair.h
@@ -23,6 +23,7 @@
int recv_fd_uxst(int sock);
int send_fd_uxst(int fd, int send_fd);
+int sockpair_bind_receiver(struct receiver *rx, void (*handler)(int fd), char **errmsg);
#endif /* _HAPROXY_PROTO_SOCKPAIR_H */
diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c
index c5361c6..de28faf 100644
--- a/src/proto_sockpair.c
+++ b/src/proto_sockpair.c
@@ -35,6 +35,7 @@
#include <haproxy/list.h>
#include <haproxy/listener.h>
#include <haproxy/protocol.h>
+#include <haproxy/proto_sockpair.h>
#include <haproxy/time.h>
#include <haproxy/tools.h>
#include <haproxy/version.h>
@@ -55,6 +56,7 @@
.l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),/* path len */
.accept = &listener_accept,
.connect = &sockpair_connect_server,
+ .bind = sockpair_bind_receiver,
.listen = sockpair_bind_listener,
.enable_all = enable_all_listeners,
.disable_all = disable_all_listeners,
@@ -85,6 +87,61 @@
proto_sockpair.nb_listeners++;
}
+/* Binds receiver <rx>, and assigns <handler> and rx->owner as the callback and
+ * context, respectively, with <tm> as the thread mask. Returns and error code
+ * made of ERR_* bits on failure or ERR_NONE on success. On failure, an error
+ * message may be passed into <errmsg>. Note that the binding address is only
+ * an FD to receive the incoming FDs on. Thus by definition there is no real
+ * "bind" operation, this only completes the receiver. Such FDs are not
+ * inherited upon reload.
+ */
+int sockpair_bind_receiver(struct receiver *rx, void (*handler)(int fd), char **errmsg)
+{
+ int err;
+
+ /* ensure we never return garbage */
+ if (errmsg)
+ *errmsg = 0;
+
+ err = ERR_NONE;
+
+ if (rx->flags & RX_F_BOUND)
+ return ERR_NONE;
+
+ if (rx->fd == -1) {
+ err |= ERR_FATAL | ERR_ALERT;
+ memprintf(errmsg, "sockpair may be only used with inherited FDs");
+ goto bind_return;
+ }
+
+ if (rx->fd >= global.maxsock) {
+ err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
+ memprintf(errmsg, "not enough free sockets (raise '-n' parameter)");
+ goto bind_close_return;
+ }
+
+ if (fcntl(rx->fd, F_SETFL, O_NONBLOCK) == -1) {
+ err |= ERR_FATAL | ERR_ALERT;
+ memprintf(errmsg, "cannot make socket non-blocking");
+ goto bind_close_return;
+ }
+
+ rx->flags |= RX_F_BOUND;
+
+ fd_insert(rx->fd, rx->owner, handler, thread_mask(rx->settings->bind_thread) & all_threads_mask);
+ return err;
+
+ bind_return:
+ if (errmsg && *errmsg)
+ memprintf(errmsg, "%s [fd %d]", *errmsg, rx->fd);
+
+ return err;
+
+ bind_close_return:
+ close(rx->fd);
+ goto bind_return;
+}
+
/* This function changes the state from ASSIGNED to LISTEN. The socket is NOT
* enabled for polling. The return value is composed from ERR_NONE,
* ERR_RETRYABLE and ERR_FATAL. It may return a warning or an error message in