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);