| 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 | 734 | netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, |
| 735 | 735 | netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.Writer.WriteFileError!usize, |
| 736 | 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 | 738 | netInterfaceNameResolve: *const fn (?*anyopaque, *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface, |
| 738 | 739 | netInterfaceName: *const fn (?*anyopaque, net.Interface) net.Interface.NameError!net.Interface.Name, |
| 739 | 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 | 900 | .netConnectIp = netConnectIp, |
| 901 | 901 | .netConnectUnix = netConnectUnix, |
| 902 | 902 | .netClose = netClose, |
| 903 | .netShutdown = netShutdown, | |
| 903 | 904 | .netRead = netRead, |
| 904 | 905 | .netWrite = netWrite, |
| 905 | 906 | .netSend = netSend, |
| ... | ... | @@ -1549,12 +1550,22 @@ fn netWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, |
| 1549 | 1550 | _ = splat; |
| 1550 | 1551 | @panic("TODO"); |
| 1551 | 1552 | } |
| 1553 | ||
| 1552 | 1554 | fn netClose(userdata: ?*anyopaque, handle: net.Socket.Handle) void { |
| 1553 | 1555 | const k: *Kqueue = @ptrCast(@alignCast(userdata)); |
| 1554 | 1556 | _ = k; |
| 1555 | 1557 | _ = handle; |
| 1556 | 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 | 1569 | fn netInterfaceNameResolve( |
| 1559 | 1570 | userdata: ?*anyopaque, |
| 1560 | 1571 | name: *const net.Interface.Name, |
| ... | ... | @@ -1564,12 +1575,14 @@ fn netInterfaceNameResolve( |
| 1564 | 1575 | _ = name; |
| 1565 | 1576 | @panic("TODO"); |
| 1566 | 1577 | } |
| 1578 | ||
| 1567 | 1579 | fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { |
| 1568 | 1580 | const k: *Kqueue = @ptrCast(@alignCast(userdata)); |
| 1569 | 1581 | _ = k; |
| 1570 | 1582 | _ = interface; |
| 1571 | 1583 | @panic("TODO"); |
| 1572 | 1584 | } |
| 1585 | ||
| 1573 | 1586 | fn netLookup( |
| 1574 | 1587 | userdata: ?*anyopaque, |
| 1575 | 1588 | host_name: net.HostName, |
lib/std/Io/Threaded.zig+88| ... | ... | @@ -891,6 +891,10 @@ pub fn io(t: *Threaded) Io { |
| 891 | 891 | else => netConnectUnixPosix, |
| 892 | 892 | }, |
| 893 | 893 | .netClose = netClose, |
| 894 | .netShutdown = switch (native_os) { | |
| 895 | .windows => netShutdownWindows, | |
| 896 | else => netShutdownPosix, | |
| 897 | }, | |
| 894 | 898 | .netRead = switch (native_os) { |
| 895 | 899 | .windows => netReadWindows, |
| 896 | 900 | else => netReadPosix, |
| ... | ... | @@ -1007,6 +1011,7 @@ pub fn ioBasic(t: *Threaded) Io { |
| 1007 | 1011 | .netConnectIp = netConnectIpUnavailable, |
| 1008 | 1012 | .netConnectUnix = netConnectUnixUnavailable, |
| 1009 | 1013 | .netClose = netCloseUnavailable, |
| 1014 | .netShutdown = netShutdownUnavailable, | |
| 1010 | 1015 | .netRead = netReadUnavailable, |
| 1011 | 1016 | .netWrite = netWriteUnavailable, |
| 1012 | 1017 | .netWriteFile = netWriteFileUnavailable, |
| ... | ... | @@ -10390,6 +10395,89 @@ fn netCloseUnavailable(userdata: ?*anyopaque, handles: []const net.Socket.Handle |
| 10390 | 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 | 10481 | fn netInterfaceNameResolve( |
| 10394 | 10482 | userdata: ?*anyopaque, |
| 10395 | 10483 | name: *const net.Interface.Name, |
lib/std/Io/net.zig+14| ... | ... | @@ -954,6 +954,16 @@ pub const SendFlags = packed struct(u8) { |
| 954 | 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 | 967 | pub const Interface = struct { |
| 958 | 968 | /// Value 0 indicates `none`. |
| 959 | 969 | index: u32, |
| ... | ... | @@ -1191,6 +1201,10 @@ pub const Stream = struct { |
| 1191 | 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 | 1208 | pub const Reader = struct { |
| 1195 | 1209 | io: Io, |
| 1196 | 1210 | interface: Io.Reader, |
lib/std/Io/net/test.zig+2| ... | ... | @@ -346,6 +346,8 @@ test "non-blocking tcp server" { |
| 346 | 346 | const len = try socket_file.read(&buf); |
| 347 | 347 | const msg = buf[0..len]; |
| 348 | 348 | try testing.expect(mem.eql(u8, msg, "hello from server\n")); |
| 349 | ||
| 350 | try stream.shutdown(io, .both); | |
| 349 | 351 | } |
| 350 | 352 | |
| 351 | 353 | test "decompress compressed DNS name" { |