aboutgitcodebugslistschat
path: root/repair.c
diff options
context:
space:
mode:
Diffstat (limited to 'repair.c')
-rw-r--r--repair.c60
1 files changed, 55 insertions, 5 deletions
diff --git a/repair.c b/repair.c
index 3ee089f..f6b1bf3 100644
--- a/repair.c
+++ b/repair.c
@@ -27,6 +27,10 @@
#define SCM_MAX_FD 253 /* From Linux kernel (include/net/scm.h), not in UAPI */
+/* Wait for a while for TCP_REPAIR helper to connect if it's not there yet */
+#define REPAIR_ACCEPT_TIMEOUT_MS 10
+#define REPAIR_ACCEPT_TIMEOUT_US (REPAIR_ACCEPT_TIMEOUT_MS * 1000)
+
/* Pending file descriptors for next repair_flush() call, or command change */
static int repair_fds[SCM_MAX_FD];
@@ -64,18 +68,21 @@ void repair_sock_init(const struct ctx *c)
* repair_listen_handler() - Handle events on TCP_REPAIR helper listening socket
* @c: Execution context
* @events: epoll events
+ *
+ * Return: 0 on valid event with new connected socket, error code on failure
*/
-void repair_listen_handler(struct ctx *c, uint32_t events)
+int repair_listen_handler(struct ctx *c, uint32_t events)
{
union epoll_ref ref = { .type = EPOLL_TYPE_REPAIR };
struct epoll_event ev = { 0 };
struct ucred ucred;
socklen_t len;
+ int rc;
if (events != EPOLLIN) {
debug("Spurious event 0x%04x on TCP_REPAIR helper socket",
events);
- return;
+ return EINVAL;
}
len = sizeof(ucred);
@@ -86,18 +93,19 @@ void repair_listen_handler(struct ctx *c, uint32_t events)
SOCK_NONBLOCK);
if (discard == -1)
- return;
+ return errno;
if (!getsockopt(discard, SOL_SOCKET, SO_PEERCRED, &ucred, &len))
info("Discarding TCP_REPAIR helper, PID %i", ucred.pid);
close(discard);
- return;
+ return EEXIST;
}
if ((c->fd_repair = accept4(c->fd_repair_listen, NULL, NULL, 0)) < 0) {
+ rc = errno;
debug_perror("accept4() on TCP_REPAIR helper listening socket");
- return;
+ return rc;
}
if (!getsockopt(c->fd_repair, SOL_SOCKET, SO_PEERCRED, &ucred, &len))
@@ -107,10 +115,14 @@ void repair_listen_handler(struct ctx *c, uint32_t events)
ev.events = EPOLLHUP | EPOLLET;
ev.data.u64 = ref.u64;
if (epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->fd_repair, &ev)) {
+ rc = errno;
debug_perror("epoll_ctl() on TCP_REPAIR helper socket");
close(c->fd_repair);
c->fd_repair = -1;
+ return rc;
}
+
+ return 0;
}
/**
@@ -139,6 +151,44 @@ void repair_handler(struct ctx *c, uint32_t events)
}
/**
+ * repair_wait() - Wait (with timeout) for TCP_REPAIR helper to connect
+ * @c: Execution context
+ *
+ * Return: 0 on success or if already connected, error code on failure
+ */
+int repair_wait(struct ctx *c)
+{
+ struct timeval tv = { .tv_sec = 0,
+ .tv_usec = (long)(REPAIR_ACCEPT_TIMEOUT_US) };
+ int rc;
+
+ static_assert(REPAIR_ACCEPT_TIMEOUT_US < 1000 * 1000,
+ ".tv_usec is greater than 1000 * 1000");
+
+ if (c->fd_repair >= 0)
+ return 0;
+
+ if (c->fd_repair_listen == -1)
+ return ENOENT;
+
+ if (setsockopt(c->fd_repair_listen, SOL_SOCKET, SO_RCVTIMEO,
+ &tv, sizeof(tv))) {
+ rc = errno;
+ err_perror("Set timeout on TCP_REPAIR listening socket");
+ return rc;
+ }
+
+ rc = repair_listen_handler(c, EPOLLIN);
+
+ tv.tv_usec = 0;
+ if (setsockopt(c->fd_repair_listen, SOL_SOCKET, SO_RCVTIMEO,
+ &tv, sizeof(tv)))
+ err_perror("Clear timeout on TCP_REPAIR listening socket");
+
+ return rc;
+}
+
+/**
* repair_flush() - Flush current set of sockets to helper, with current command
* @c: Execution context
*