| author | |
| committer | |
| log | e8a2e6578a3f5e4cd82eb59388e49e152728791e |
| tree | 377c0313ad303dd7f6707801bec8934a44cab8cf |
| parent | f2f474fc785a9bc89f16f91067480e8c410dc773 |
5 files changed, 118 insertions(+), 0 deletions(-)
lib/std/Io.zig+1| ... | @@ -734,6 +734,7 @@ pub const VTable = struct { | ... | @@ -734,6 +734,7 @@ pub const VTable = struct { |
| 734 | netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, | 734 | netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, |
| 735 | netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.Writer.WriteFileError!usize, | 735 | netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.Writer.WriteFileError!usize, |
| 736 | netClose: *const fn (?*anyopaque, handle: []const net.Socket.Handle) void, | 736 | netClose: *const fn (?*anyopaque, handle: []const net.Socket.Handle) void, |
| 737 | netShutdown: *const fn (?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void, | ||
| 737 | netInterfaceNameResolve: *const fn (?*anyopaque, *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface, | 738 | netInterfaceNameResolve: *const fn (?*anyopaque, *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface, |
| 738 | netInterfaceName: *const fn (?*anyopaque, net.Interface) net.Interface.NameError!net.Interface.Name, | 739 | netInterfaceName: *const fn (?*anyopaque, net.Interface) net.Interface.NameError!net.Interface.Name, |
| 739 | netLookup: *const fn (?*anyopaque, net.HostName, *Queue(net.HostName.LookupResult), net.HostName.LookupOptions) net.HostName.LookupError!void, | 740 | netLookup: *const fn (?*anyopaque, net.HostName, *Queue(net.HostName.LookupResult), net.HostName.LookupOptions) net.HostName.LookupError!void, |
lib/std/Io/Kqueue.zig+13| ... | @@ -900,6 +900,7 @@ pub fn io(k: *Kqueue) Io { | ... | @@ -900,6 +900,7 @@ pub fn io(k: *Kqueue) Io { |
| 900 | .netConnectIp = netConnectIp, | 900 | .netConnectIp = netConnectIp, |
| 901 | .netConnectUnix = netConnectUnix, | 901 | .netConnectUnix = netConnectUnix, |
| 902 | .netClose = netClose, | 902 | .netClose = netClose, |
| 903 | .netShutdown = netShutdown, | ||
| 903 | .netRead = netRead, | 904 | .netRead = netRead, |
| 904 | .netWrite = netWrite, | 905 | .netWrite = netWrite, |
| 905 | .netSend = netSend, | 906 | .netSend = netSend, |
| ... | @@ -1549,12 +1550,22 @@ fn netWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, | ... | @@ -1549,12 +1550,22 @@ fn netWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, |
| 1549 | _ = splat; | 1550 | _ = splat; |
| 1550 | @panic("TODO"); | 1551 | @panic("TODO"); |
| 1551 | } | 1552 | } |
| 1553 | |||
| 1552 | fn netClose(userdata: ?*anyopaque, handle: net.Socket.Handle) void { | 1554 | fn netClose(userdata: ?*anyopaque, handle: net.Socket.Handle) void { |
| 1553 | const k: *Kqueue = @ptrCast(@alignCast(userdata)); | 1555 | const k: *Kqueue = @ptrCast(@alignCast(userdata)); |
| 1554 | _ = k; | 1556 | _ = k; |
| 1555 | _ = handle; | 1557 | _ = handle; |
| 1556 | @panic("TODO"); | 1558 | @panic("TODO"); |
| 1557 | } | 1559 | } |
| 1560 | |||
| 1561 | fn netShutdown(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void { | ||
| 1562 | const k: *Kqueue = @ptrCast(@alignCast(userdata)); | ||
| 1563 | _ = k; | ||
| 1564 | _ = handle; | ||
| 1565 | _ = how; | ||
| 1566 | @panic("TODO"); | ||
| 1567 | } | ||
| 1568 | |||
| 1558 | fn netInterfaceNameResolve( | 1569 | fn netInterfaceNameResolve( |
| 1559 | userdata: ?*anyopaque, | 1570 | userdata: ?*anyopaque, |
| 1560 | name: *const net.Interface.Name, | 1571 | name: *const net.Interface.Name, |
| ... | @@ -1564,12 +1575,14 @@ fn netInterfaceNameResolve( | ... | @@ -1564,12 +1575,14 @@ fn netInterfaceNameResolve( |
| 1564 | _ = name; | 1575 | _ = name; |
| 1565 | @panic("TODO"); | 1576 | @panic("TODO"); |
| 1566 | } | 1577 | } |
| 1578 | |||
| 1567 | fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { | 1579 | fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { |
| 1568 | const k: *Kqueue = @ptrCast(@alignCast(userdata)); | 1580 | const k: *Kqueue = @ptrCast(@alignCast(userdata)); |
| 1569 | _ = k; | 1581 | _ = k; |
| 1570 | _ = interface; | 1582 | _ = interface; |
| 1571 | @panic("TODO"); | 1583 | @panic("TODO"); |
| 1572 | } | 1584 | } |
| 1585 | |||
| 1573 | fn netLookup( | 1586 | fn netLookup( |
| 1574 | userdata: ?*anyopaque, | 1587 | userdata: ?*anyopaque, |
| 1575 | host_name: net.HostName, | 1588 | host_name: net.HostName, |
lib/std/Io/Threaded.zig+88| ... | @@ -891,6 +891,10 @@ pub fn io(t: *Threaded) Io { | ... | @@ -891,6 +891,10 @@ pub fn io(t: *Threaded) Io { |
| 891 | else => netConnectUnixPosix, | 891 | else => netConnectUnixPosix, |
| 892 | }, | 892 | }, |
| 893 | .netClose = netClose, | 893 | .netClose = netClose, |
| 894 | .netShutdown = switch (native_os) { | ||
| 895 | .windows => netShutdownWindows, | ||
| 896 | else => netShutdownPosix, | ||
| 897 | }, | ||
| 894 | .netRead = switch (native_os) { | 898 | .netRead = switch (native_os) { |
| 895 | .windows => netReadWindows, | 899 | .windows => netReadWindows, |
| 896 | else => netReadPosix, | 900 | else => netReadPosix, |
| ... | @@ -1007,6 +1011,7 @@ pub fn ioBasic(t: *Threaded) Io { | ... | @@ -1007,6 +1011,7 @@ pub fn ioBasic(t: *Threaded) Io { |
| 1007 | .netConnectIp = netConnectIpUnavailable, | 1011 | .netConnectIp = netConnectIpUnavailable, |
| 1008 | .netConnectUnix = netConnectUnixUnavailable, | 1012 | .netConnectUnix = netConnectUnixUnavailable, |
| 1009 | .netClose = netCloseUnavailable, | 1013 | .netClose = netCloseUnavailable, |
| 1014 | .netShutdown = netShutdownUnavailable, | ||
| 1010 | .netRead = netReadUnavailable, | 1015 | .netRead = netReadUnavailable, |
| 1011 | .netWrite = netWriteUnavailable, | 1016 | .netWrite = netWriteUnavailable, |
| 1012 | .netWriteFile = netWriteFileUnavailable, | 1017 | .netWriteFile = netWriteFileUnavailable, |
| ... | @@ -10390,6 +10395,89 @@ fn netCloseUnavailable(userdata: ?*anyopaque, handles: []const net.Socket.Handle | ... | @@ -10390,6 +10395,89 @@ fn netCloseUnavailable(userdata: ?*anyopaque, handles: []const net.Socket.Handle |
| 10390 | unreachable; // How you gonna close something that was impossible to open? | 10395 | unreachable; // How you gonna close something that was impossible to open? |
| 10391 | } | 10396 | } |
| 10392 | 10397 | ||
| 10398 | fn netShutdownPosix(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void { | ||
| 10399 | if (!have_networking) return error.NetworkDown; | ||
| 10400 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | ||
| 10401 | const current_thread = Thread.getCurrent(t); | ||
| 10402 | |||
| 10403 | const posix_how: i32 = switch (how) { | ||
| 10404 | .recv => posix.SHUT.RD, | ||
| 10405 | .send => posix.SHUT.WR, | ||
| 10406 | .both => posix.SHUT.RDWR, | ||
| 10407 | }; | ||
| 10408 | |||
| 10409 | try current_thread.beginSyscall(); | ||
| 10410 | while (true) { | ||
| 10411 | switch (posix.errno(posix.system.shutdown(handle, posix_how))) { | ||
| 10412 | .SUCCESS => { | ||
| 10413 | current_thread.endSyscall(); | ||
| 10414 | return; | ||
| 10415 | }, | ||
| 10416 | .INTR => { | ||
| 10417 | try current_thread.checkCancel(); | ||
| 10418 | continue; | ||
| 10419 | }, | ||
| 10420 | else => |e| { | ||
| 10421 | current_thread.endSyscall(); | ||
| 10422 | switch (e) { | ||
| 10423 | .BADF, .NOTSOCK, .INVAL => |err| return errnoBug(err), | ||
| 10424 | .NOTCONN => return error.SocketUnconnected, | ||
| 10425 | .NOBUFS => return error.SystemResources, | ||
| 10426 | else => |err| return posix.unexpectedErrno(err), | ||
| 10427 | } | ||
| 10428 | }, | ||
| 10429 | } | ||
| 10430 | } | ||
| 10431 | } | ||
| 10432 | |||
| 10433 | fn netShutdownWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void { | ||
| 10434 | if (!have_networking) return error.NetworkDown; | ||
| 10435 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | ||
| 10436 | const current_thread = Thread.getCurrent(t); | ||
| 10437 | |||
| 10438 | const wsa_how: i32 = switch (how) { | ||
| 10439 | .recv => ws2_32.SD_RECEIVE, | ||
| 10440 | .send => ws2_32.SD_SEND, | ||
| 10441 | .both => ws2_32.SD_BOTH, | ||
| 10442 | }; | ||
| 10443 | |||
| 10444 | try current_thread.beginSyscall(); | ||
| 10445 | while (true) { | ||
| 10446 | const rc = ws2_32.shutdown(handle, wsa_how); | ||
| 10447 | if (rc != ws2_32.SOCKET_ERROR) { | ||
| 10448 | current_thread.endSyscall(); | ||
| 10449 | return; | ||
| 10450 | } | ||
| 10451 | switch (ws2_32.WSAGetLastError()) { | ||
| 10452 | .EINTR => { | ||
| 10453 | try current_thread.checkCancel(); | ||
| 10454 | continue; | ||
| 10455 | }, | ||
| 10456 | .NOTINITIALISED => { | ||
| 10457 | try initializeWsa(t); | ||
| 10458 | try current_thread.checkCancel(); | ||
| 10459 | continue; | ||
| 10460 | }, | ||
| 10461 | else => |e| { | ||
| 10462 | current_thread.endSyscall(); | ||
| 10463 | switch (e) { | ||
| 10464 | .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled, | ||
| 10465 | .ECONNABORTED => return error.ConnectionAborted, | ||
| 10466 | .ECONNRESET => return error.ConnectionResetByPeer, | ||
| 10467 | .ENETDOWN => return error.NetworkDown, | ||
| 10468 | .ENOTCONN => return error.SocketUnconnected, | ||
| 10469 | .EINVAL, .ENOTSOCK => |err| return wsaErrorBug(err), | ||
| 10470 | else => |err| return windows.unexpectedWSAError(err), | ||
| 10471 | } | ||
| 10472 | }, | ||
| 10473 | } | ||
| 10474 | } | ||
| 10475 | } | ||
| 10476 | |||
| 10477 | fn netShutdownUnavailable(_: ?*anyopaque, _: net.Socket.Handle, _: net.ShutdownHow) net.ShutdownError!void { | ||
| 10478 | unreachable; // How you gonna shutdown something that was impossible to open? | ||
| 10479 | } | ||
| 10480 | |||
| 10393 | fn netInterfaceNameResolve( | 10481 | fn netInterfaceNameResolve( |
| 10394 | userdata: ?*anyopaque, | 10482 | userdata: ?*anyopaque, |
| 10395 | name: *const net.Interface.Name, | 10483 | name: *const net.Interface.Name, |
lib/std/Io/net.zig+14| ... | @@ -954,6 +954,16 @@ pub const SendFlags = packed struct(u8) { | ... | @@ -954,6 +954,16 @@ pub const SendFlags = packed struct(u8) { |
| 954 | _: u3 = 0, | 954 | _: u3 = 0, |
| 955 | }; | 955 | }; |
| 956 | 956 | ||
| 957 | pub const ShutdownHow = enum { recv, send, both }; | ||
| 958 | |||
| 959 | pub const ShutdownError = error{ | ||
| 960 | ConnectionAborted, | ||
| 961 | ConnectionResetByPeer, | ||
| 962 | NetworkDown, | ||
| 963 | SocketUnconnected, | ||
| 964 | SystemResources, | ||
| 965 | } || Io.UnexpectedError || Io.Cancelable; | ||
| 966 | |||
| 957 | pub const Interface = struct { | 967 | pub const Interface = struct { |
| 958 | /// Value 0 indicates `none`. | 968 | /// Value 0 indicates `none`. |
| 959 | index: u32, | 969 | index: u32, |
| ... | @@ -1191,6 +1201,10 @@ pub const Stream = struct { | ... | @@ -1191,6 +1201,10 @@ pub const Stream = struct { |
| 1191 | io.vtable.netClose(io.userdata, (&s.socket.handle)[0..1]); | 1201 | io.vtable.netClose(io.userdata, (&s.socket.handle)[0..1]); |
| 1192 | } | 1202 | } |
| 1193 | 1203 | ||
| 1204 | pub fn shutdown(s: *const Stream, io: Io, how: ShutdownHow) ShutdownError!void { | ||
| 1205 | return io.vtable.netShutdown(io.userdata, s.socket.handle, how); | ||
| 1206 | } | ||
| 1207 | |||
| 1194 | pub const Reader = struct { | 1208 | pub const Reader = struct { |
| 1195 | io: Io, | 1209 | io: Io, |
| 1196 | interface: Io.Reader, | 1210 | interface: Io.Reader, |
lib/std/Io/net/test.zig+2| ... | @@ -346,6 +346,8 @@ test "non-blocking tcp server" { | ... | @@ -346,6 +346,8 @@ test "non-blocking tcp server" { |
| 346 | const len = try socket_file.read(&buf); | 346 | const len = try socket_file.read(&buf); |
| 347 | const msg = buf[0..len]; | 347 | const msg = buf[0..len]; |
| 348 | try testing.expect(mem.eql(u8, msg, "hello from server\n")); | 348 | try testing.expect(mem.eql(u8, msg, "hello from server\n")); |
| 349 | |||
| 350 | try stream.shutdown(io, .both); | ||
| 349 | } | 351 | } |
| 350 | 352 | ||
| 351 | test "decompress compressed DNS name" { | 353 | test "decompress compressed DNS name" { |