Patchwork [03,of,13] rust-chg: add function to send fds via domain socket

login
register
mail settings
Submitter Yuya Nishihara
Date Oct. 2, 2018, 2:25 p.m.
Message ID <6e54b2234a94cca1fd3d.1538490342@mimosa>
Download mbox | patch
Permalink /patch/35309/
State Accepted
Headers show

Comments

Yuya Nishihara - Oct. 2, 2018, 2:25 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1537773275 -32400
#      Mon Sep 24 16:14:35 2018 +0900
# Node ID 6e54b2234a94cca1fd3d8adc050345ab94a1904c
# Parent  9a9d3c24436a82cb94ccc5a81eee592191991140
rust-chg: add function to send fds via domain socket

As a beginning, I wrote some C.

It's extracted from attachio() of contrib/chg/hgclient.c. Maybe it could
be rewritten in Rust by using the libc (and/or nix) crates, but doing that
wouldn't be trivial as the code depends on CMSG_*() macros. IMO, using C
is better here.

Patch

diff --git a/rust/chg/build.rs b/rust/chg/build.rs
new file mode 100644
--- /dev/null
+++ b/rust/chg/build.rs
@@ -0,0 +1,8 @@ 
+extern crate cc;
+
+fn main() {
+    cc::Build::new()
+        .warnings(true)
+        .file("src/sendfds.c")
+        .compile("procutil");
+}
diff --git a/rust/chg/src/sendfds.c b/rust/chg/src/sendfds.c
new file mode 100644
--- /dev/null
+++ b/rust/chg/src/sendfds.c
@@ -0,0 +1,51 @@ 
+/*
+ * Utility to send fds via Unix domain socket
+ *
+ * Copyright 2011, 2018 Yuya Nishihara <yuya@tcha.org>
+ *
+ * This software may be used and distributed according to the terms of the
+ * GNU General Public License version 2 or any later version.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#define MAX_FD_LEN 10
+
+/*
+ * Sends the given fds with 1-byte dummy payload.
+ *
+ * Returns the number of bytes sent on success, -1 on error and errno is set
+ * appropriately.
+ */
+ssize_t sendfds(int sockfd, const int *fds, size_t fdlen)
+{
+	char dummy[1] = {0};
+	struct iovec iov = {dummy, sizeof(dummy)};
+	char fdbuf[CMSG_SPACE(sizeof(fds[0]) * MAX_FD_LEN)];
+	struct msghdr msgh;
+	struct cmsghdr *cmsg;
+
+	/* just use a fixed-size buffer since we'll never send tons of fds */
+	if (fdlen > MAX_FD_LEN) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	memset(&msgh, 0, sizeof(msgh));
+	msgh.msg_iov = &iov;
+	msgh.msg_iovlen = 1;
+	msgh.msg_control = fdbuf;
+	msgh.msg_controllen = CMSG_SPACE(sizeof(fds[0]) * fdlen);
+
+	cmsg = CMSG_FIRSTHDR(&msgh);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(fds[0]) * fdlen);
+	memcpy(CMSG_DATA(cmsg), fds, sizeof(fds[0]) * fdlen);
+	msgh.msg_controllen = cmsg->cmsg_len;
+	return sendmsg(sockfd, &msgh, 0);
+}