[fdio] Acquire socket type from kernel

After this change, we acquire the type of the socket (e.g., pipe,
stream, or datagram) using zx_object_get_info rather than using the
process args id. This CL paves the way for reducing the process args
ids.

Test: No behavior change
Change-Id: Ia92305fcf08a22d5403a315be11df3e21041aff3
diff --git a/system/ulib/fdio/bsdsocket.c b/system/ulib/fdio/bsdsocket.c
index d971c7a..6e85b50 100644
--- a/system/ulib/fdio/bsdsocket.c
+++ b/system/ulib/fdio/bsdsocket.c
@@ -106,15 +106,14 @@
         return STATUS(rr);
     }
 
-    io = fdio_socket_create(s, 0);
-    if (io == NULL) {
-        return ERRNO(EIO);
+    if (type & SOCK_DGRAM) {
+        io = fdio_socket_create_datagram(s, 0);
+    } else {
+        io = fdio_socket_create_stream(s, 0);
     }
 
-    if (type & SOCK_STREAM) {
-        fdio_socket_set_stream_ops(io);
-    } else if (type & SOCK_DGRAM) {
-        fdio_socket_set_dgram_ops(io);
+    if (io == NULL) {
+        return ERRNO(EIO);
     }
 
     if (type & SOCK_NONBLOCK) {
@@ -236,11 +235,10 @@
     }
 
     fdio_t* io2;
-    if ((io2 = fdio_socket_create(s2, IOFLAG_SOCKET_CONNECTED)) == NULL) {
+    if ((io2 = fdio_socket_create_stream(s2, IOFLAG_SOCKET_CONNECTED)) == NULL) {
         return ERROR(ZX_ERR_NO_RESOURCES);
     }
 
-    fdio_socket_set_stream_ops(io2);
     io2->ioflag |= IOFLAG_SOCKET_CONNECTED;
 
     if (flags & SOCK_NONBLOCK) {
diff --git a/system/ulib/fdio/private.h b/system/ulib/fdio/private.h
index 85354a9..96ed9eec 100644
--- a/system/ulib/fdio/private.h
+++ b/system/ulib/fdio/private.h
@@ -135,8 +135,15 @@
 // Takens ownership of h.
 fdio_t* fdio_vmofile_create(zx_handle_t h, zx_handle_t vmo, zx_off_t off, zx_off_t len);
 
+// Examines |socket| and determines whether to create a pipe, stream socket, or
+// datagram socket.
+//
+// Always consumes |socket|.
+zx_status_t fdio_acquire_socket(zx_handle_t socket, int flags, fdio_t** out_io);
+
 // Wraps a socket with an fdio_t using socket io.
-fdio_t* fdio_socket_create(zx_handle_t s, int flags);
+fdio_t* fdio_socket_create_stream(zx_handle_t s, int flags);
+fdio_t* fdio_socket_create_datagram(zx_handle_t s, int flags);
 
 // creates a message port and pair of simple io fdio_t's
 int fdio_pipe_pair(fdio_t** a, fdio_t** b);
@@ -153,9 +160,6 @@
 fdio_t* fdio_waitable_create(zx_handle_t h, zx_signals_t signals_in,
                              zx_signals_t signals_out, bool shared_handle);
 
-void fdio_socket_set_stream_ops(fdio_t* io);
-void fdio_socket_set_dgram_ops(fdio_t* io);
-
 // unsupported / do-nothing hooks shared by implementations
 zx_status_t fdio_default_get_token(fdio_t* io, zx_handle_t* out);
 zx_status_t fdio_default_set_attr(fdio_t* io, const vnattr_t* attr);
diff --git a/system/ulib/fdio/remoteio.c b/system/ulib/fdio/remoteio.c
index 7d16a63..a1f4d39 100644
--- a/system/ulib/fdio/remoteio.c
+++ b/system/ulib/fdio/remoteio.c
@@ -457,6 +457,34 @@
                          ZX_FS_RIGHT_WRITABLE, 0755, "");
 }
 
+zx_status_t fdio_acquire_socket(zx_handle_t socket, int flags, fdio_t** out_io) {
+    zx_info_socket_t info;
+    memset(&info, 0, sizeof(info));
+    zx_status_t status = zx_object_get_info(socket, ZX_INFO_SOCKET, &info, sizeof(info), NULL, NULL);
+    if (status != ZX_OK) {
+        zx_handle_close(socket);
+        return status;
+    }
+    fdio_t* io = NULL;
+    if ((info.options & ZX_SOCKET_HAS_CONTROL) != 0) {
+        // If the socket has a control plane, then the socket is either
+        // a stream or a datagram socket.
+        if ((info.options & ZX_SOCKET_DATAGRAM) != 0) {
+            io = fdio_socket_create_datagram(socket, flags);
+        } else {
+            io = fdio_socket_create_stream(socket, flags);
+        }
+    } else {
+        // Without a control plane, the socket is a pipe.
+        io = fdio_pipe_create(socket);
+    }
+    if (!io) {
+        return ZX_ERR_NO_RESOURCES;
+    }
+    *out_io = io;
+    return ZX_OK;
+}
+
 // Create a fdio (if possible) from handles and info.
 //
 // The Control channel is provided in |handle|, and auxillary
@@ -512,14 +540,6 @@
         }
         *out = io;
         return ZX_OK;
-    case FDIO_PROTOCOL_PIPE:
-        if (handle != ZX_HANDLE_INVALID) {
-            r = ZX_ERR_INVALID_ARGS;
-            break;
-        } else if ((*out = fdio_pipe_create(info->pipe.s)) == NULL) {
-            return ZX_ERR_NO_RESOURCES;
-        }
-        return ZX_OK;
     case FDIO_PROTOCOL_VMOFILE: {
         if (info->vmofile.v == ZX_HANDLE_INVALID) {
             r = ZX_ERR_INVALID_ARGS;
@@ -532,6 +552,13 @@
         }
         return ZX_OK;
     }
+    case FDIO_PROTOCOL_PIPE:
+        if (info->pipe.s == ZX_HANDLE_INVALID) {
+            r = ZX_ERR_INVALID_ARGS;
+            break;
+        }
+        zx_handle_close(handle);
+        return fdio_acquire_socket(info->pipe.s, 0, out);
     case FDIO_PROTOCOL_SOCKET_CONNECTED:
     case FDIO_PROTOCOL_SOCKET: {
         int flags = (info->tag == FDIO_PROTOCOL_SOCKET_CONNECTED) ? IOFLAG_SOCKET_CONNECTED : 0;
@@ -540,10 +567,7 @@
             break;
         }
         zx_handle_close(handle);
-        if ((*out = fdio_socket_create(info->socket.s, flags)) == NULL) {
-            return ZX_ERR_NO_RESOURCES;
-        }
-        return ZX_OK;
+        return fdio_acquire_socket(info->socket.s, flags, out);
     }
     case FDIO_PROTOCOL_SOCKETPAIR:
         if (handle != ZX_HANDLE_INVALID) {
@@ -572,7 +596,6 @@
     zx_status_t r;
     int fd;
     zxrio_node_info_t info;
-    zx_handle_t control_channel = ZX_HANDLE_INVALID;
 
     // Pack additional handles into |info|, if possible.
     switch (PA_HND_TYPE(types[0])) {
@@ -620,7 +643,7 @@
         goto fail;
     }
 
-    if ((r = fdio_from_handles(control_channel, &info, &io)) != ZX_OK) {
+    if ((r = fdio_from_handles(ZX_HANDLE_INVALID, &info, &io)) != ZX_OK) {
         return r;
     }
 
diff --git a/system/ulib/fdio/socket.c b/system/ulib/fdio/socket.c
index 9650e23..15f36f8 100644
--- a/system/ulib/fdio/socket.c
+++ b/system/ulib/fdio/socket.c
@@ -833,13 +833,13 @@
     .shutdown = fdio_socket_shutdown,
 };
 
-fdio_t* fdio_socket_create(zx_handle_t s, int flags) {
+static fdio_t* fdio_socket_create(zx_handle_t s, int flags, fdio_ops_t* ops) {
     zxsio_t* sio = calloc(1, sizeof(*sio));
     if (sio == NULL) {
         zx_handle_close(s);
         return NULL;
     }
-    sio->io.ops = &fdio_socket_stream_ops; // default is stream
+    sio->io.ops = ops;
     sio->io.magic = FDIO_MAGIC;
     sio->io.refcount = 1;
     sio->io.ioflag = IOFLAG_SOCKET | flags;
@@ -848,12 +848,10 @@
     return &sio->io;
 }
 
-void fdio_socket_set_stream_ops(fdio_t* io) {
-    zxsio_t* sio = (zxsio_t*)io;
-    sio->io.ops = &fdio_socket_stream_ops;
+fdio_t* fdio_socket_create_stream(zx_handle_t s, int flags) {
+    return fdio_socket_create(s, flags, &fdio_socket_stream_ops);
 }
 
-void fdio_socket_set_dgram_ops(fdio_t* io) {
-    zxsio_t* sio = (zxsio_t*)io;
-    sio->io.ops = &fdio_socket_dgram_ops;
+fdio_t* fdio_socket_create_datagram(zx_handle_t s, int flags) {
+    return fdio_socket_create(s, flags, &fdio_socket_dgram_ops);
 }
diff --git a/system/ulib/fdio/unistd.c b/system/ulib/fdio/unistd.c
index 0b695f5..ba5c70e 100644
--- a/system/ulib/fdio/unistd.c
+++ b/system/ulib/fdio/unistd.c
@@ -586,21 +586,26 @@
             LOG(1, "fdio: inherit fd=%d (rio)\n", arg_fd);
             break;
         }
-        case PA_FDIO_PIPE:
-            fdio_fdtab[arg_fd] = fdio_pipe_create(h);
+        case PA_FDIO_SOCKET:
+        case PA_FDIO_PIPE: {
+            fdio_t* io = NULL;
+            zx_status_t status = fdio_acquire_socket(h, IOFLAG_SOCKET_CONNECTED, &io);
+            if (status != ZX_OK) {
+                LOG(1, "fdio: Failed to acquire for fd=%d (socket) status=%d (%s)\n",
+                    arg_fd, status, zx_status_get_string(status));
+                zx_handle_close(h);
+                continue;
+            }
+            fdio_fdtab[arg_fd] = io;
             fdio_fdtab[arg_fd]->dupcount++;
-            LOG(1, "fdio: inherit fd=%d (pipe)\n", arg_fd);
+            LOG(1, "fdio: inherit fd=%d (socket)\n", arg_fd);
             break;
+        }
         case PA_FDIO_LOGGER:
             fdio_fdtab[arg_fd] = fdio_logger_create(h);
             fdio_fdtab[arg_fd]->dupcount++;
             LOG(1, "fdio: inherit fd=%d (log)\n", arg_fd);
             break;
-        case PA_FDIO_SOCKET:
-            fdio_fdtab[arg] = fdio_socket_create(h, IOFLAG_SOCKET_CONNECTED);
-            fdio_fdtab[arg]->dupcount++;
-            LOG(1, "fdio: inherit fd=%d (socket)\n", arg_fd);
-            break;
         case PA_NS_DIR:
             // we always contine here to not steal the
             // handles from higher level code that may
diff --git a/system/utest/fdio/fdio_socket.c b/system/utest/fdio/fdio_socket.c
index 4338df6..72ef73d 100644
--- a/system/utest/fdio/fdio_socket.c
+++ b/system/utest/fdio/fdio_socket.c
@@ -15,7 +15,7 @@
 static bool create_socket_fdio_pair(zx_handle_t* socket_out, int* fd_out) {
     // Create new socket pair.
     zx_handle_t s1, s2;
-    ASSERT_EQ(ZX_OK, zx_socket_create(ZX_SOCKET_STREAM, &s1, &s2), "Socket create failed");
+    ASSERT_EQ(ZX_OK, zx_socket_create(ZX_SOCKET_STREAM | ZX_SOCKET_HAS_CONTROL, &s1, &s2), "Socket create failed");
 
     // Convert one socket to FDIO
     uint32_t type = PA_FDIO_SOCKET;