| author | |
| committer | |
| log | b587a42233728a523c89a24caab1c68d60774fac |
| tree | 0c532dd35852e7f6ee04162564254bfec6658641 |
| parent | baa075ac8cf3ff666b9f3d5c5a75e139f33b5d86 |
9 files changed, 100 insertions(+), 0 deletions(-)
lib/std/c.zig+1| ... | @@ -145,6 +145,7 @@ pub extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int; | ... | @@ -145,6 +145,7 @@ pub extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int; |
| 145 | pub extern "c" fn uname(buf: *utsname) c_int; | 145 | pub extern "c" fn uname(buf: *utsname) c_int; |
| 146 | 146 | ||
| 147 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; | 147 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; |
| 148 | pub extern "c" fn shutdown(socket: fd_t, how: c_int) c_int; | ||
| 148 | pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int; | 149 | pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int; |
| 149 | pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int; | 150 | pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int; |
| 150 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; | 151 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; |
lib/std/os.zig+56| ... | @@ -2706,6 +2706,62 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t | ... | @@ -2706,6 +2706,62 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t |
| 2706 | } | 2706 | } |
| 2707 | } | 2707 | } |
| 2708 | 2708 | ||
| 2709 | pub const ShutdownError = error{ | ||
| 2710 | ConnectionAborted, | ||
| 2711 | |||
| 2712 | /// Connection was reset by peer, application should close socket as it is no longer usable. | ||
| 2713 | ConnectionResetByPeer, | ||
| 2714 | |||
| 2715 | BlockingOperationInProgress, | ||
| 2716 | |||
| 2717 | /// The network subsystem has failed. | ||
| 2718 | NetworkSubsystemFailed, | ||
| 2719 | |||
| 2720 | /// The socket is not connected (connection-oriented sockets only). | ||
| 2721 | SocketNotConnected, | ||
| 2722 | |||
| 2723 | SystemResources | ||
| 2724 | } || UnexpectedError; | ||
| 2725 | |||
| 2726 | pub const ShutdownHow = enum { recv, send, both }; | ||
| 2727 | |||
| 2728 | /// Shutdown socket send/receive operations | ||
| 2729 | pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { | ||
| 2730 | if (builtin.os.tag == .windows) { | ||
| 2731 | const result = windows.ws2_32.shutdown(sock, switch (how) { | ||
| 2732 | .recv => windows.SD_RECEIVE, | ||
| 2733 | .send => windows.SD_SEND, | ||
| 2734 | .both => windows.SD_BOTH, | ||
| 2735 | }); | ||
| 2736 | if (0 != result) switch (windows.ws2_32.WSAGetLastError()) { | ||
| 2737 | .WSAECONNABORTED => return error.ConnectionAborted, | ||
| 2738 | .WSAECONNRESET => return error.ConnectionResetByPeer, | ||
| 2739 | .WSAEINPROGRESS => return error.BlockingOperationInProgress, | ||
| 2740 | .WSAEINVAL => unreachable, | ||
| 2741 | .WSAENETDOWN => return error.NetworkSubsystemFailed, | ||
| 2742 | .WSAENOTCONN => return error.SocketNotConnected, | ||
| 2743 | .WSAENOTSOCK => unreachable, | ||
| 2744 | .WSANOTINITIALISED => unreachable, | ||
| 2745 | else => |err| return windows.unexpectedWSAError(err), | ||
| 2746 | }; | ||
| 2747 | } else { | ||
| 2748 | const rc = system.shutdown(sock, switch (how) { | ||
| 2749 | .recv => SHUT_RD, | ||
| 2750 | .send => SHUT_WR, | ||
| 2751 | .both => SHUT_RDWR, | ||
| 2752 | }); | ||
| 2753 | switch (errno(rc)) { | ||
| 2754 | 0 => return, | ||
| 2755 | EBADF => unreachable, | ||
| 2756 | EINVAL => unreachable, | ||
| 2757 | ENOTCONN => return error.SocketNotConnected, | ||
| 2758 | ENOTSOCK => unreachable, | ||
| 2759 | ENOBUFS => return error.SystemResources, | ||
| 2760 | else => |err| return unexpectedErrno(err), | ||
| 2761 | } | ||
| 2762 | } | ||
| 2763 | } | ||
| 2764 | |||
| 2709 | pub fn closeSocket(sock: socket_t) void { | 2765 | pub fn closeSocket(sock: socket_t) void { |
| 2710 | if (builtin.os.tag == .windows) { | 2766 | if (builtin.os.tag == .windows) { |
| 2711 | windows.closesocket(sock) catch unreachable; | 2767 | windows.closesocket(sock) catch unreachable; |
lib/std/os/bits/darwin.zig+4| ... | @@ -1523,3 +1523,7 @@ pub const rlimit = extern struct { | ... | @@ -1523,3 +1523,7 @@ pub const rlimit = extern struct { |
| 1523 | /// Hard limit | 1523 | /// Hard limit |
| 1524 | max: rlim_t, | 1524 | max: rlim_t, |
| 1525 | }; | 1525 | }; |
| 1526 | |||
| 1527 | pub const SHUT_RD = 0; | ||
| 1528 | pub const SHUT_WR = 1; | ||
| 1529 | pub const SHUT_RDWR = 2; |
lib/std/os/bits/freebsd.zig+4| ... | @@ -1388,3 +1388,7 @@ pub const rlimit = extern struct { | ... | @@ -1388,3 +1388,7 @@ pub const rlimit = extern struct { |
| 1388 | /// Hard limit | 1388 | /// Hard limit |
| 1389 | max: rlim_t, | 1389 | max: rlim_t, |
| 1390 | }; | 1390 | }; |
| 1391 | |||
| 1392 | pub const SHUT_RD = 0; | ||
| 1393 | pub const SHUT_WR = 1; | ||
| 1394 | pub const SHUT_RDWR = 2; |
lib/std/os/bits/netbsd.zig+4| ... | @@ -1196,3 +1196,7 @@ pub const rlimit = extern struct { | ... | @@ -1196,3 +1196,7 @@ pub const rlimit = extern struct { |
| 1196 | /// Hard limit | 1196 | /// Hard limit |
| 1197 | max: rlim_t, | 1197 | max: rlim_t, |
| 1198 | }; | 1198 | }; |
| 1199 | |||
| 1200 | pub const SHUT_RD = 0; | ||
| 1201 | pub const SHUT_WR = 1; | ||
| 1202 | pub const SHUT_RDWR = 2; |
lib/std/os/bits/openbsd.zig+4| ... | @@ -1134,3 +1134,7 @@ pub const rlimit = extern struct { | ... | @@ -1134,3 +1134,7 @@ pub const rlimit = extern struct { |
| 1134 | /// Hard limit | 1134 | /// Hard limit |
| 1135 | max: rlim_t, | 1135 | max: rlim_t, |
| 1136 | }; | 1136 | }; |
| 1137 | |||
| 1138 | pub const SHUT_RD = 0; | ||
| 1139 | pub const SHUT_WR = 1; | ||
| 1140 | pub const SHUT_RDWR = 2; |
lib/std/os/test.zig+19| ... | @@ -627,3 +627,22 @@ test "getrlimit and setrlimit" { | ... | @@ -627,3 +627,22 @@ test "getrlimit and setrlimit" { |
| 627 | try os.setrlimit(resource, limit); | 627 | try os.setrlimit(resource, limit); |
| 628 | } | 628 | } |
| 629 | } | 629 | } |
| 630 | |||
| 631 | test "shutdown socket" { | ||
| 632 | if (builtin.os.tag == .wasi) | ||
| 633 | return error.SkipZigTest; | ||
| 634 | if (builtin.os.tag == .windows) { | ||
| 635 | _ = try std.os.windows.WSAStartup(2, 2); | ||
| 636 | } | ||
| 637 | defer { | ||
| 638 | if (builtin.os.tag == .windows) { | ||
| 639 | std.os.windows.WSACleanup() catch unreachable; | ||
| 640 | } | ||
| 641 | } | ||
| 642 | const sock = try os.socket(os.AF_INET, os.SOCK_STREAM, 0); | ||
| 643 | os.shutdown(sock, .both) catch |err| switch (err) { | ||
| 644 | error.SocketNotConnected => {}, | ||
| 645 | else => |e| return e, | ||
| 646 | }; | ||
| 647 | os.closeSocket(sock); | ||
| 648 | } |
lib/std/os/windows/bits.zig+4| ... | @@ -1602,3 +1602,7 @@ pub const MOUNTMGR_MOUNT_POINTS = extern struct { | ... | @@ -1602,3 +1602,7 @@ pub const MOUNTMGR_MOUNT_POINTS = extern struct { |
| 1602 | MountPoints: [1]MOUNTMGR_MOUNT_POINT, | 1602 | MountPoints: [1]MOUNTMGR_MOUNT_POINT, |
| 1603 | }; | 1603 | }; |
| 1604 | pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008; | 1604 | pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008; |
| 1605 | |||
| 1606 | pub const SD_RECEIVE = 0; | ||
| 1607 | pub const SD_SEND = 1; | ||
| 1608 | pub const SD_BOTH = 2; |
lib/std/os/windows/ws2_32.zig+4| ... | @@ -877,3 +877,7 @@ pub extern "ws2_32" fn setsockopt( | ... | @@ -877,3 +877,7 @@ pub extern "ws2_32" fn setsockopt( |
| 877 | optval: ?*const c_void, | 877 | optval: ?*const c_void, |
| 878 | optlen: socklen_t, | 878 | optlen: socklen_t, |
| 879 | ) callconv(WINAPI) c_int; | 879 | ) callconv(WINAPI) c_int; |
| 880 | pub extern "ws2_32" fn shutdown( | ||
| 881 | s: SOCKET, | ||
| 882 | how: c_int, | ||
| 883 | ) callconv(WINAPI) c_int; |