Add a method to pass file descriptors and one to create a socket from an fd.
diff --git a/osi/include/socket.h b/osi/include/socket.h
index 754e468..aadfd5b 100644
--- a/osi/include/socket.h
+++ b/osi/include/socket.h
@@ -32,6 +32,12 @@
// |socket_free|. Returns NULL on failure.
socket_t *socket_new(void);
+// Returns a new socket object backed by |fd|. The socket object is in whichever
+// state |fd| is in when it was passed to this function. The returned object must
+// be freed by calling |socket_free|. Returns NULL on failure. If this function
+// is successful, ownership of |fd| is transferred and the caller must not close it.
+socket_t *socket_new_from_fd(int fd);
+
// Frees a socket object created by |socket_new| or |socket_accept|. |socket| may
// be NULL. If the socket was connected, it will be disconnected.
void socket_free(socket_t *socket);
@@ -66,6 +72,12 @@
// may be NULL.
ssize_t socket_write(const socket_t *socket, const void *buf, size_t count);
+// This function performs the same write operation as |socket_write| and also
+// sends the file descriptor |fd| over the socket to a remote process. Ownership
+// of |fd| transfers to this function and the descriptor must not be used any longer.
+// If |fd| is INVALID_FD, this function behaves the same as |socket_write|.
+ssize_t socket_write_and_transfer_fd(const socket_t *socket, const void *buf, size_t count, int fd);
+
// Registers |socket| with the |reactor|. When the socket becomes readable, |read_cb|
// will be called. When the socket becomes writeable, |write_cb| will be called. The
// |context| parameter is passed, untouched, to each of the callback routines. Neither
diff --git a/osi/src/socket.c b/osi/src/socket.c
index 827941c..9a7e1ab 100644
--- a/osi/src/socket.c
+++ b/osi/src/socket.c
@@ -70,6 +70,19 @@
return NULL;
}
+socket_t *socket_new_from_fd(int fd) {
+ assert(fd != INVALID_FD);
+
+ socket_t *ret = (socket_t *)calloc(1, sizeof(socket_t));
+ if (!ret) {
+ ALOGE("%s unable to allocate memory for socket.", __func__);
+ return NULL;
+ }
+
+ ret->fd = fd;
+ return ret;
+}
+
void socket_free(socket_t *socket) {
if (!socket)
return;
@@ -133,6 +146,38 @@
return send(socket->fd, buf, count, MSG_DONTWAIT);
}
+ssize_t socket_write_and_transfer_fd(const socket_t *socket, const void *buf, size_t count, int fd) {
+ assert(socket != NULL);
+ assert(buf != NULL);
+
+ if (fd == INVALID_FD)
+ return socket_write(socket, buf, count);
+
+ struct msghdr msg;
+ struct iovec iov;
+ char control_buf[CMSG_SPACE(sizeof(int))];
+
+ iov.iov_base = (void *)buf;
+ iov.iov_len = count;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control_buf;
+ msg.msg_controllen = sizeof(control_buf);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ struct cmsghdr *header = CMSG_FIRSTHDR(&msg);
+ header->cmsg_level = SOL_SOCKET;
+ header->cmsg_type = SCM_RIGHTS;
+ header->cmsg_len = CMSG_LEN(sizeof(int));
+ *(int *)CMSG_DATA(header) = fd;
+
+ ssize_t ret = sendmsg(socket->fd, &msg, MSG_DONTWAIT);
+ close(fd);
+ return ret;
+}
+
void socket_register(socket_t *socket, reactor_t *reactor, void *context, socket_cb read_cb, socket_cb write_cb) {
assert(socket != NULL);
assert(read_cb || write_cb);