Commit e85c89630e

Loris Cro <kappaloris@gmail.com>
2020-06-16 22:38:51
accept
Signed-off-by: Loris Cro <kappaloris@gmail.com>
1 parent bd89bd6
Changed files (3)
lib
lib/std/event/loop.zig
@@ -720,6 +720,40 @@ pub const Loop = struct {
         }
     }
 
+    /// ------- I/0 APIs -------
+    pub fn accept(
+        self: *Loop,
+        /// This argument is a socket that has been created with `socket`, bound to a local address
+        /// with `bind`, and is listening for connections after a `listen`.
+        sockfd: os.fd_t,
+        /// This argument is a pointer to a sockaddr structure.  This structure is filled in with  the
+        /// address  of  the  peer  socket, as known to the communications layer.  The exact format of the
+        /// address returned addr is determined by the socket's address  family  (see  `socket`  and  the
+        /// respective  protocol  man  pages).
+        addr: *os.sockaddr,
+        /// This argument is a value-result argument: the caller must initialize it to contain  the
+        /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size
+        /// of the peer address.
+        ///
+        /// The returned address is truncated if the buffer provided is too small; in this  case,  `addr_size`
+        /// will return a value greater than was supplied to the call.
+        addr_size: *os.socklen_t,
+        /// The following values can be bitwise ORed in flags to obtain different behavior:
+        /// * `SOCK_CLOEXEC`  - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor.   See  the
+        ///   description  of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
+        flags: u32,
+    ) os.AcceptError!os.fd_t {
+        while (true) {
+            return os.accept(sockfd, addr, addr_size, flags | os.SOCK_NONBLOCK) catch |err| switch (err) {
+                error.WouldBlock => {
+                    self.waitUntilFdReadable(sockfd);
+                    continue;
+                },
+                else => return err,
+            };
+        }
+    }
+
     /// Performs an async `os.open` using a separate thread.
     pub fn openZ(self: *Loop, file_path: [*:0]const u8, flags: u32, mode: os.mode_t) os.OpenError!os.fd_t {
         var req_node = Request.Node{
lib/std/net.zig
@@ -1661,18 +1661,23 @@ pub const StreamServer = struct {
 
     /// If this function succeeds, the returned `Connection` is a caller-managed resource.
     pub fn accept(self: *StreamServer) AcceptError!Connection {
-        const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
-        const accept_flags = nonblock | os.SOCK_CLOEXEC;
         var accepted_addr: Address = undefined;
         var adr_len: os.socklen_t = @sizeOf(Address);
-        if (os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| {
+        const accept_result = blk: {
+            if (std.io.is_async) {
+                const loop = std.event.Loop.instance orelse return error.UnexpectedError;
+                break :blk loop.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK_CLOEXEC);
+            } else {
+                break :blk os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK_CLOEXEC);
+            }
+        };
+
+        if (accept_result) |fd| {
             return Connection{
                 .file = fs.File{ .handle = fd },
                 .address = accepted_addr,
             };
         } else |err| switch (err) {
-            // We only give SOCK_NONBLOCK when I/O mode is async, in which case this error
-            // is handled by os.accept4.
             error.WouldBlock => unreachable,
             else => |e| return e,
         }
lib/std/os.zig
@@ -2890,12 +2890,7 @@ pub fn accept(
                 return fd;
             },
             EINTR => continue,
-            EAGAIN => if (std.event.Loop.instance) |loop| {
-                loop.waitUntilFdReadable(sockfd);
-                continue;
-            } else {
-                return error.WouldBlock;
-            },
+            EAGAIN => return error.WouldBlock,
             EBADF => unreachable, // always a race condition
             ECONNABORTED => return error.ConnectionAborted,
             EFAULT => unreachable,