changed: rewrote `core.net` in terms of new platform layer
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 16 Oct 2023 03:19:40 +0000 (22:19 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 16 Oct 2023 03:19:40 +0000 (22:19 -0500)
core/io/io.onyx
core/net/net.onyx
core/runtime/platform/onyx/net.onyx [new file with mode: 0644]
docs/ideas/platform_layer.md

index bc92c60b87bc984068fd81aecb88290db388e7b6..12b783b6749bc8a605ca301287f1b3bac33ea73c 100644 (file)
@@ -35,4 +35,10 @@ Error :: enum {
 
     // When reading from a stream, no data was read, and data will not become available soon.
     ReadLater      :: 0x0b;
+
+    // A socket tried to connect to an endpoint and failed.
+    ConnectFailed  :: 0x0c;
+
+    // Sockets only. Signals that no data was recieved from a non-blocking operation.
+    NoData     :: 0x0d;
 }
index a866c97814e7866cad4fa99fe91b823831ad3ae9..0dffaaa7a1bd81dcb23dabd7d1243b868022e242 100644 (file)
@@ -8,12 +8,12 @@ use core {*}
 use runtime
 
 Socket :: struct {
-    Handle :: #distinct i32
-
     use stream : io.Stream;
-    handle: Handle;
+    handle: runtime.platform.SocketData;
+
     type: SocketType;
-    family: SocketDomain;
+    family: SocketFamily;
+    proto: SocketProto;
 }
 
 // Inject methods for the socket
@@ -35,17 +35,11 @@ Socket :: struct {
     poll      :: socket_poll
 }
 
-SocketError :: enum {
-    None :: 0x00;
-    BadSettings :: 0x01;
-    NoHost :: 0x02;
-    ConnectFailed :: 0x03;
-}
-
-SocketDomain :: enum {
-    Unix  :: 0x00;
-    Inet  :: 0x01;
-    Inet6 :: 0x02;
+SocketFamily :: enum {
+    Unknown :: 0x00;
+    Inet    :: 0x01;
+    Inet6   :: 0x02;
+    Unix    :: 0x03;
 }
 
 SocketType :: enum {
@@ -53,6 +47,15 @@ SocketType :: enum {
     Dgram  :: 0x01;
 }
 
+SocketProto :: enum {
+    IP   :: 0x00;
+    ICMP :: 0x01;
+    IGMP :: 0x02;
+    TCP  :: 0x06;
+    UDP  :: 0x11;
+    IPV6 :: 0x29;
+}
+
 SocketSetting :: enum {
     NonBlocking  :: 0x01;
     Broadcast    :: 0x02;
@@ -67,33 +70,47 @@ SocketShutdown :: enum {
 
 #local UNIX_SOCKET_PATH_LEN :: 256
 
-Socket_Address :: struct #size (8 + UNIX_SOCKET_PATH_LEN) {
-    family: u16;
-    port: u16;
-    addr: u32;
+SocketAddress :: union {
+    // Null-terminated string
+    Unix: [UNIX_SOCKET_PATH_LEN] u8;
 
-    addr_as_str :: (use this: &Socket_Address, allocator := context.allocator) -> str {
-        str_addr := ipv4_to_str(this.addr);
-        return string.alloc_copy(str_addr, allocator=allocator);
-    }
+    Inet: struct {
+        port: u16;
+        addr: u32;
+    };
+
+    Inet6: struct {
+        port: u16;
+        addr_h: u64;
+        addr_l: u64;
+    };
 }
 
-make_ipv4_address :: (out: &Socket_Address, addr: u32, port: u16) {
-    out.family = ~~ SocketDomain.Inet;
-    out.port = port;
-    out.addr = addr;
+#inject
+SocketAddress.addr_as_str :: (this: &SocketAddress, allocator := context.allocator) -> str {
+    return switch *this {
+        case path: .Unix => string.as_str(cast(cstr) path);
+        case inet: .Inet => do {
+            str_addr := ipv4_to_str(inet.addr);
+            out := make(dyn_str, allocator);
+            return conv.format(&out, "{}:{}", str_addr, inet.port);
+        }
+        case inet6: .Inet6 => do {
+            str_addr := ipv6_to_str(inet6.addr_h, inet6.addr_l);
+            out := make(dyn_str, allocator);
+            return conv.format(&out, "{}:{}", str_addr, inet6.port);
+        }
+    };
 }
 
-make_unix_address :: (out: &Socket_Address, path: str) {
-    out.family = ~~ SocketDomain.Unix;
-    out.port   = 0;
+make_ipv4_address :: (out: &SocketAddress, addr: u32, port: u16) {
+    *out = .{ Inet = .{ port = port, addr = addr } };
+}
+
+make_unix_address :: (out: &SocketAddress, path: str) {
+    *out = .{ Unix = .{} };
 
-    //
-    // If we are constructing a unix socket, we have to write the path
-    // at the address where the addr field is in the Socket_Address.
-    // We also have to append a null-terminator, as that is what will
-    // be expected from any C function.
-    out_path := cast([&] u8) &out.addr;
+    out_path := cast([&] u8) out + alignof out.tag_enum;
     offset   := 0;
     while offset < math.min(path.count, UNIX_SOCKET_PATH_LEN - 1) {
         defer offset += 1;
@@ -104,68 +121,75 @@ make_unix_address :: (out: &Socket_Address, path: str) {
     out_path[offset] = 0;
 }
 
-socket_create :: (domain: SocketDomain, type: SocketType) -> (Socket, SocketError) {
+socket_create :: (family: SocketFamily, type: SocketType, proto: SocketProto) -> Result(Socket, io.Error) {
     s: Socket;
     s.type = type;
-    s.family = domain;
+    s.family = family;
+    s.proto = proto;
 
-    err := __net_create_socket(&s.handle, domain, type);
-    if err == .None {
-        s.vtable = &__net_socket_vtable;
-        s.flags |= .Block_On_Read;
-    }
+    socket := runtime.platform.__net_sock_create(family, type, proto)?;
+    s.handle = socket;
 
-    return s, err;
+    s.flags |= .Block_On_Read;
+
+    return .{ Ok = s };
 }
 
-socket_close :: (s: &Socket) {
-    __net_close_socket(s.handle);
-    s.vtable = null;
+socket_from_fd :: (fd: runtime.platform.SocketData) -> Socket {
+    return Socket.{
+        stream = .{ vtable = &__net_socket_vtable },
+        handle = fd,
+    };
 }
 
-socket_setting :: (s: &Socket, setting: SocketSetting, value: u32) {
-    __net_setting(s.handle, setting, value);
+socket_close :: (s: &Socket) {
+    runtime.platform.__net_sock_close(s.handle);
+}
 
-    if setting == .NonBlocking {
-        if value > 0 do s.flags = ~~ (cast(u32) s.flags & cast(u32) ~io.Stream_Flags.Block_On_Read);
-        else do         s.flags |= io.Stream_Flags.Block_On_Read;
+socket_setting :: (s: &Socket, setting: SocketSetting, flag: bool) {
+    if runtime.platform.__net_sock_opt_flag(s.handle, setting, flag) {
+        if setting == .NonBlocking {
+            if flag do s.flags = ~~ (cast(u32) s.flags & cast(u32) ~io.Stream_Flags.Block_On_Read);
+            else do    s.flags |= io.Stream_Flags.Block_On_Read;
+        }
     }
 }
 
 socket_is_alive :: (s: &Socket) -> bool {
-    return s.vtable != null;
+    return runtime.platform.__net_sock_status(s.handle) == .Open;
 }
 
-socket_connect :: (s: &Socket, host: str, port: u16 = 0) -> SocketError {
-    return switch s.family {
-        case .Inet => __net_connect_ipv4(s.handle, host, port);
-        case .Unix => __net_connect_unix(s.handle, host);
-        case #default => .BadSettings;
-    };
+socket_connect :: (s: &Socket, addr: &SocketAddress) -> io.Error {
+    return runtime.platform.__net_sock_connect(s.handle, addr);
 }
 
 socket_bind :: (s: &Socket, bind_address: &Socket_Address) -> bool {
-    return __net_bind(s.handle, bind_address);
+    return runtime.platform.__net_sock_bind(s.handle, bind_address);
 }
 
-socket_listen :: (s: &Socket, backlog := 32) {
-    __net_listen(s.handle, backlog);
+socket_listen :: (s: &Socket, backlog := 32) -> bool {
+    return runtime.platform.__net_sock_listen(s.handle, backlog);
 }
 
-socket_shutdown :: (s: &Socket, how: SocketShutdown) {
-    __net_shutdown(s.handle, cast(u32) how);
+socket_shutdown :: (s: &Socket, how: SocketShutdown) -> io.Error {
+    return runtime.platform.__net_socket_shutdown(s.handle, how);
 }
 
-socket_accept :: (s: &Socket) -> (Socket, Socket_Address) {
-    new_socket: Socket;
-    new_addr: Socket_Address;
-    new_socket.handle = __net_accept(s.handle, &new_addr);
+SocketAcceptResult :: struct {
+    socket: Socket;
+    addr:   SocketAddress;
+}
 
-    if cast(i32) new_socket.handle >= 0 {
-        new_socket.vtable = &__net_socket_vtable;
-    }
+socket_accept :: (s: &Socket) -> Result(SocketAcceptResult, io.Error) {
+    new_addr: SocketAddress;
+    sock_fd := runtime.platform.__net_sock_accept(s.handle, &new_addr)?;
 
-    return new_socket, new_addr;
+    return .{
+        Ok = .{
+            socket = socket_from_fd(sock_fd),
+            addr   = new_addr
+        }
+    };
 }
 
 Socket_Poll_Status :: enum {
@@ -174,10 +198,7 @@ Socket_Poll_Status :: enum {
     Closed    :: 2;
 }
 
-// TODO: Cleanup this function. The stat_buff should be something that is at least
-// as big as the sockets array, and the timeout should be the last parameter because
-// it is not required.
-socket_poll_all :: (sockets: [] &Socket, timeout := -1, stat_buff: [] Socket_Poll_Status = .[]) {
+socket_poll_all :: (sockets: [] &Socket, stat_buff: [] Socket_Poll_Status, timeout := -1) {
     if sockets.count > stat_buff.count do return;
 
     handles := alloc.array_from_stack(runtime.platform.PollDescription, sockets.count);
@@ -212,98 +233,134 @@ socket_poll :: (socket: &Socket, timeout := -1) -> Socket_Poll_Status {
 }
 
 socket_send :: (s: &Socket, data: [] u8) -> i32 {
-    sent := __net_send(s.handle, data);
-    if sent < 0 { s.vtable = null; }
-    return sent;
+    res := runtime.platform.__net_sock_send(s.handle, data);
+    return res.Ok ?? -1;
 }
 
-socket_sendto :: (s: &Socket, data: [] u8, addr: &Socket_Address) -> i32 {
-    sent := __net_sendto(s.handle, data, addr);
-    return sent;
+socket_sendto :: (s: &Socket, data: [] u8, addr: &SocketAddress) -> i32 {
+    res := runtime.platform.__net_sock_sendto(s.handle, data, addr);
+    return res.Ok ?? -1;
 }
 
 socket_sendall :: (s: &Socket, data: [] u8) {
     to_send := data;
 
     while to_send.count > 0 {
-        sent := __net_send(s.handle, to_send);
-        if sent < 0 { s.vtable = null; return; }
+        sent := socket_send(s, to_send);
+        if sent < 0 { return; }
         else        do to_send = to_send[sent .. to_send.count];
     }
 }
 
-socket_recv :: (s: &Socket, maxlen := 1024, allocator := context.allocator) -> [] u8 {
-    buffer := alloc.from_stack(maxlen);
-    would_block: bool;
-    received := __net_recv(s.handle, .{ buffer, maxlen }, &would_block);
-    if received < 0 { 
-        if !would_block do s.vtable = null;
-        return .[];
+socket_recv :: (s: &Socket, maxlen := 1024, allocator := context.allocator) -> ? [] u8 {
+    buffer := alloc.array_from_stack(u8, maxlen);
+    res := runtime.platform.__net_sock_recv(s.handle, buffer);
+    if res.Err {
+        return .{};
     }
 
-    result := memory.make_slice(u8, received, allocator=allocator);
-    memory.copy(result.data, buffer, received);
+    return slice.copy(buffer[0 .. res.Ok->unwrap()], allocator);
+
+    // buffer := alloc.from_stack(maxlen);
+    // would_block: bool;
+    // received := __net_recv(s.handle, .{ buffer, maxlen }, &would_block);
+    // if received < 0 { 
+    //     if !would_block do s.vtable = null;
+    //     return .[];
+    // }
 
-    return result;
+    // result := memory.make_slice(u8, received, allocator=allocator);
+    // memory.copy(result.data, buffer, received);
+
+    // return result;
 }
 
 socket_recv_into :: (s: &Socket, buffer: [] u8) -> i32 {
-    would_block: bool;
-    received := __net_recv(s.handle, buffer, &would_block);
-    if received < 0 && !would_block do s.vtable = null;
-    if would_block do return 0;
+    res := runtime.platform.__net_sock_recv(s.handle, buffer);
+    if res.Err {
+        return 0;
+    }
+
+    return res.Ok->unwrap();
 
-    return received;
+    // would_block: bool;
+    // received := __net_recv(s.handle, buffer, &would_block);
+    // if received < 0 && !would_block do s.vtable = null;
+    // if would_block do return 0;
+
+    // return received;
+}
+
+SocketRecvFromResult :: struct {
+    addr: SocketAddress;
+    count: i32;
 }
 
-socket_recvfrom :: (s: &Socket, buffer: [] u8) -> (Socket_Address, i32) {
-    would_block: bool;
-    sa: Socket_Address;
+socket_recvfrom :: (s: &Socket, buffer: [] u8) -> ? SocketRecvFromResult {
+    sender_addr: SocketAddress;
+    res := runtime.platform.__net_sock_recvfrom(s.handle, buffer, &sender_addr);
+    if res.Err do return .{};
 
-    received := __net_recvfrom(s.handle, buffer, &sa, &would_block);
-    if received < 0 && !would_block do s.vtable = null;
-    if would_block do return sa, 0;
+    return .{ Some = .{ addr = sender_addr, res.Ok->unwrap() } };
 
-    return sa, received;
+    // would_block: bool;
+    // sa: SocketAddress;
+
+    // received := __net_recvfrom(s.handle, buffer, &sa, &would_block);
+    // if received < 0 && !would_block do s.vtable = null;
+    // if would_block do return sa, 0;
+
+    // return sa, received;
 }
 
-host_to_network :: #match #local {}
-#match host_to_network (x: u16) => __net_host_to_net_s(x);
-#match host_to_network (x: u32) => __net_host_to_net_l(x);
+// TODO: Add these back
+// host_to_network :: #match #local {}
+// #match host_to_network (x: u16) => __net_host_to_net_s(x);
+// #match host_to_network (x: u32) => __net_host_to_net_l(x);
 
-network_to_host :: #match #local {}
-#match network_to_host (x: u16) => __net_net_to_host_s(x);
-#match network_to_host (x: u32) => __net_net_to_host_l(x);
+// network_to_host :: #match #local {}
+// #match network_to_host (x: u16) => __net_net_to_host_s(x);
+// #match network_to_host (x: u32) => __net_net_to_host_l(x);
 
 #local __net_socket_vtable := io.Stream_Vtable.{
     read = (use s: &Socket, buffer: [] u8) -> (io.Error, u32) {
         if cast(i32) handle == 0 do return .BadFile, 0;
         
-        would_block := false;
-        bytes_read := __net_recv(handle, buffer, &would_block);
-        if bytes_read < 0 && !would_block do s.vtable = null;
+        res := runtime.platform.__net_sock_recv(handle, buffer);
+        res->ok()->with([bytes_read] {
+            if bytes_read == 0 do return .EOF, 0;
 
-        if would_block do return .ReadLater, bytes_read;
+            return .None, bytes_read;
+        });
 
-        if bytes_read == 0 do return .EOF, bytes_read;
+        res->err()->with([err] {
+            if err == .NoData do return .ReadLater, 0;
 
-        return .None, bytes_read;
+            return err, 0;
+        });
     },
 
     write_byte = (use s: &Socket, byte: u8) -> io.Error {
         if cast(i32) handle == 0 do return .BadFile;
 
-        bytes_written := __net_send(handle, .[ byte ]);
-        if bytes_written < 0 { s.vtable = null; return .BufferFull; }
-        return .None;
+        res := runtime.platform.__net_sock_send(handle, .[ byte ]);
+        res->err()->with([err] {
+            return err;
+        });
+
+        if res->ok()->unwrap() > 0 do return .None;
+        return .BufferFull;
     },
 
     write = (use s: &Socket, buffer: [] u8) -> (io.Error, u32) {
         if cast(i32) handle == 0 do return .BadFile, 0;
         
-        bytes_written := __net_send(handle, buffer);
-        if bytes_written < 0 { s.vtable = null; return .EOF, 0; }
-        return .None, bytes_written;
+        res := runtime.platform.__net_sock_send(handle, .[ byte ]);
+        res->err()->with([err] {
+            return err, 0;
+        });
+
+        return .None, res->ok()->unwrap();
     },
 
     poll = (use s: &Socket, ev: io.PollEvent, timeout: i32) -> (io.Error, bool) {
@@ -319,42 +376,11 @@ network_to_host :: #match #local {}
     },
 
     close = (use p: &Socket) -> io.Error {
-        __net_close_socket(handle);
+        socket_close(p);
         return .None;
     }
 };
 
-//
-// This will be moved into the platform layer later.
-// I think this is most everything you would need, but
-// I need to see how WASI does sockets to see if this
-// makes sense as an abstraction.
-#foreign "onyx_runtime" {
-    #package __net_create_socket :: (out_handle: &Socket.Handle, domain: SocketDomain, type: SocketType) -> SocketError ---
-    #package __net_close_socket  :: (handle: Socket.Handle)               -> void ---
-    #package __net_setting       :: (handle: Socket.Handle, setting: SocketSetting, value: i32) -> void ---
-    #package __net_bind          :: (handle: Socket.Handle, bind_address: &Socket_Address)    -> bool ---
-    #package __net_listen        :: (handle: Socket.Handle, backlog: i32) -> void ---
-    #package __net_accept        :: (handle: Socket.Handle, out_address: &Socket_Address) -> Socket.Handle ---
-    #package __net_connect_unix  :: (handle: Socket.Handle, path: str) -> SocketError ---
-    #package __net_connect_ipv4  :: (handle: Socket.Handle, host: str, port: u16) -> SocketError ---
-    #package __net_shutdown      :: (handle: Socket.Handle, how: u32) -> void ---
-    #package __net_send          :: (handle: Socket.Handle, data: [] u8)  -> i32 ---
-    #package __net_sendto        :: (handle: Socket.Handle, data: [] u8, addr: &Socket_Address)  -> i32 ---
-    #package __net_recv          :: (handle: Socket.Handle, data: [] u8, async_would_block: &bool) -> i32 ---
-    #package __net_recvfrom      :: (handle: Socket.Handle, data: [] u8, out_recv_addr: &Socket_Address, async_would_block: &bool) -> i32 ---
-
-    #package __net_host_to_net_s :: (s: u16) -> u16 ---
-    #package __net_host_to_net_l :: (s: u32) -> u32 ---
-    #package __net_net_to_host_s :: (s: u16) -> u16 ---
-    #package __net_net_to_host_l :: (s: u32) -> u32 ---
-}
-
-#operator >= macro (a, b: Socket.Handle) => cast(u32) a >= cast(u32) b;
-#operator == macro (a, b: Socket.Handle) => cast(u32) a == cast(u32) b;
-
-
-
 //
 // Non-socket related helper functions
 //
@@ -384,3 +410,19 @@ ipv4_to_str :: (addr: u32) -> str {
         (addr >>  0) & 0xff);
     return str_addr;
 }
+
+// This returns a volatile buffer that should be copied.
+ipv6_to_str :: (addr_h: u64, addr_l: u64) -> str {
+    #persist out: [64] u8;
+    str_addr := conv.format(out, "{w2b16}:{w2b16}:{w2b16}:{w2b16}:{w2b16}:{w2b16}:{w2b16}:{w2b16}",
+        (addr_h >> 24) & 0xff,
+        (addr_h >> 16) & 0xff,
+        (addr_h >>  8) & 0xff,
+        (addr_h >>  0) & 0xff,
+        (addr_l >> 24) & 0xff,
+        (addr_l >> 16) & 0xff,
+        (addr_l >>  8) & 0xff,
+        (addr_l >>  0) & 0xff);
+    return str_addr;
+}
+
diff --git a/core/runtime/platform/onyx/net.onyx b/core/runtime/platform/onyx/net.onyx
new file mode 100644 (file)
index 0000000..2d76888
--- /dev/null
@@ -0,0 +1,92 @@
+package runtime.platform
+
+use core.io
+use core.net {
+    SocketFamily,
+    SocketProto,
+    SocketType
+}
+
+SocketData :: #distinct i32
+
+__net_sock_create :: (af: SocketFamily, type: SocketType, proto: SocketProto) -> Result(SocketData, io.Error) {
+
+}
+
+__net_sock_status :: (s: SocketData) -> SocketStatus {
+
+}
+
+__net_sock_opt_flag :: (s: SocketData, sockopt: SocketOption, flag: bool) -> bool {
+}
+
+__net_sock_opt_time :: (s: SocketData, sockopt: SocketOption, time: ? u64) -> bool {
+
+}
+
+__net_sock_opt_size :: (s: SocketData, sockopt: SocketOption, size: i64) -> bool {
+
+}
+
+__net_sock_bind :: (s: SocketData, addr: &SocketAddress) -> bool {
+
+}
+
+__net_sock_listen :: (s: SocketData, backlog: i32) -> bool {
+
+}
+
+__net_sock_accept :: (s: SocketData, addr: &SocketAddress) -> Result(SocketData, io.Error) {
+
+}
+
+__net_sock_connect :: (s: SocketData, addr: &SocketAddress) -> io.Error {
+
+}
+
+__net_sock_recv_from :: (s: SocketData, buf: [] u8, addr: &SocketAddress) -> Result(i32, io.Error) {
+
+}
+
+__net_sock_send_to :: (s: SocketData, buf: [] u8, addr: &SocketAddress) -> Result(i32, io.Error) {
+
+}
+
+__net_sock_recv :: (s: SocketData, buf: [] u8) -> Result(i32, io.Error) {
+
+}
+
+__net_sock_send :: (s: SocketData, buf: [] u8) -> Result(i32, io.Error) {
+
+}
+
+__net_sock_shutdown :: (s: SocketData, how: SocketShutdown) -> io.Error {
+
+}
+
+__net_sock_close :: (s: SocketData) -> void {
+
+}
+
+__net_resolve :: (host: str, port: u16, out_addrs: [] SocketAddress) -> i32 {
+
+}
+
+
+#package {
+    #foreign "onyx_runtime" {
+        __net_create_socket :: (out_handle: &Socket.Handle, domain: SocketDomain, type: SocketType) -> SocketError ---
+        __net_close_socket  :: (handle: Socket.Handle)               -> void ---
+        __net_setting       :: (handle: Socket.Handle, setting: SocketSetting, value: i32) -> void ---
+        __net_bind          :: (handle: Socket.Handle, bind_address: &Socket_Address)    -> bool ---
+        __net_listen        :: (handle: Socket.Handle, backlog: i32) -> void ---
+        __net_accept        :: (handle: Socket.Handle, out_address: &Socket_Address) -> Socket.Handle ---
+        __net_connect_unix  :: (handle: Socket.Handle, path: str) -> SocketError ---
+        __net_connect_ipv4  :: (handle: Socket.Handle, host: str, port: u16) -> SocketError ---
+        __net_shutdown      :: (handle: Socket.Handle, how: u32) -> void ---
+        __net_send          :: (handle: Socket.Handle, data: [] u8)  -> i32 ---
+        __net_sendto        :: (handle: Socket.Handle, data: [] u8, addr: &Socket_Address)  -> i32 ---
+        __net_recv          :: (handle: Socket.Handle, data: [] u8, async_would_block: &bool) -> i32 ---
+        __net_recvfrom      :: (handle: Socket.Handle, data: [] u8, out_recv_addr: &Socket_Address, async_would_block: &bool) -> i32 ---
+    }
+}
\ No newline at end of file
index 9caf9f33b44cd376e491215a17c6ddb2bc187299..06d1065ff7975e1995478e23d5a2598ae3a01ede 100644 (file)
@@ -166,13 +166,14 @@ this document will serve as that "header file"
 - `__net_sock_opt_size(SocketData, sockopt: SocketOption, size: i64) -> bool`
 - `__net_sock_bind(SocketData, addr: &SocketAddress) -> bool`
 - `__net_sock_listen(SocketData, backlog: i32) -> bool`
-- `__net_sock_accept(SocketData, addr: &SocketAddress) -> Result(i32, io.Error)`
+- `__net_sock_accept(SocketData, addr: &SocketAddress) -> Result(SocketData, io.Error)`
 - `__net_sock_connect(SocketData, addr: &SocketAddress) -> io.Error`
 - `__net_sock_recv_from(SocketData, buf: [] u8, addr: &SocketAddress) -> Result(i32, io.Error)`
 - `__net_sock_send_to(SocketData, buf: [] u8, addr: &SocketAddress) -> Result(i32, io.Error)`
 - `__net_sock_recv(SocketData, buf: [] u8) -> Result(i32, io.Error)`
 - `__net_sock_send(SocketData, buf: [] u8) -> Result(i32, io.Error)`
 - `__net_sock_shutdown(SocketData, how: SocketShutdown) -> io.Error`
+- `__net_sock_close(SocketData) -> void`
 - `__net_resolve(host: str, port: u16, out_addrs: [] SocketAddress) -> i32`