From 0a40a61548ad9f666ed5300a8910f9040cc1390b Mon Sep 17 00:00:00 2001 From: Bas van den Berg Date: Thu, 3 Sep 2020 13:23:48 +0200 Subject: [PATCH] os.send(to) and os.recv(from) functions made to work on windows. --- lib/std/os.zig | 114 +++++++++++++++++++++------------- lib/std/os/windows.zig | 21 +++++++ lib/std/os/windows/ws2_32.zig | 2 +- 3 files changed, 92 insertions(+), 45 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index ee0c8848f3..abf72529ad 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4630,7 +4630,7 @@ pub const SendError = error{ /// possible to send more data. pub fn sendto( /// The file descriptor of the sending socket. - sockfd: fd_t, + sockfd: socket_t, /// Message to send. buf: []const u8, flags: u32, @@ -4639,32 +4639,43 @@ pub fn sendto( ) SendError!usize { while (true) { const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen); - switch (errno(rc)) { - 0 => return @intCast(usize, rc), - - EACCES => return error.AccessDenied, - EAGAIN => if (std.event.Loop.instance) |loop| { - loop.waitUntilFdWritable(sockfd); - continue; + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + // TODO: handle errors + else => |err| return windows.unexpectedWSAError(err), + } } else { - return error.WouldBlock; - }, - EALREADY => return error.FastOpenAlreadyInProgress, - EBADF => unreachable, // always a race condition - ECONNRESET => return error.ConnectionResetByPeer, - EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set. - EFAULT => unreachable, // An invalid user space address was specified for an argument. - EINTR => continue, - EINVAL => unreachable, // Invalid argument passed. - EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified - EMSGSIZE => return error.MessageTooBig, - ENOBUFS => return error.SystemResources, - ENOMEM => return error.SystemResources, - ENOTCONN => unreachable, // The socket is not connected, and no target has been given. - ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. - EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type. - EPIPE => return error.BrokenPipe, - else => |err| return unexpectedErrno(err), + return @intCast(usize, rc); + } + } else { + switch (errno(rc)) { + 0 => return @intCast(usize, rc), + + EACCES => return error.AccessDenied, + EAGAIN => if (std.event.Loop.instance) |loop| { + loop.waitUntilFdWritable(sockfd); + continue; + } else { + return error.WouldBlock; + }, + EALREADY => return error.FastOpenAlreadyInProgress, + EBADF => unreachable, // always a race condition + ECONNRESET => return error.ConnectionResetByPeer, + EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set. + EFAULT => unreachable, // An invalid user space address was specified for an argument. + EINTR => continue, + EINVAL => unreachable, // Invalid argument passed. + EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified + EMSGSIZE => return error.MessageTooBig, + ENOBUFS => return error.SystemResources, + ENOMEM => return error.SystemResources, + ENOTCONN => unreachable, // The socket is not connected, and no target has been given. + ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. + EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type. + EPIPE => return error.BrokenPipe, + else => |err| return unexpectedErrno(err), + } } } } @@ -4690,7 +4701,7 @@ pub fn sendto( /// possible to send more data. pub fn send( /// The file descriptor of the sending socket. - sockfd: fd_t, + sockfd: socket_t, buf: []const u8, flags: u32, ) SendError!usize { @@ -5125,8 +5136,12 @@ pub const RecvFromError = error{ SystemResources, } || UnexpectedError; +pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize { + return recvfrom(sock, buf, flags, null, null); +} + pub fn recvfrom( - sockfd: fd_t, + sockfd: socket_t, buf: []u8, flags: u32, src_addr: ?*sockaddr, @@ -5134,23 +5149,34 @@ pub fn recvfrom( ) RecvFromError!usize { while (true) { const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen); - switch (errno(rc)) { - 0 => return @intCast(usize, rc), - EBADF => unreachable, // always a race condition - EFAULT => unreachable, - EINVAL => unreachable, - ENOTCONN => unreachable, - ENOTSOCK => unreachable, - EINTR => continue, - EAGAIN => if (std.event.Loop.instance) |loop| { - loop.waitUntilFdReadable(sockfd); - continue; + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + // TODO: handle errors + else => |err| return windows.unexpectedWSAError(err), + } } else { - return error.WouldBlock; - }, - ENOMEM => return error.SystemResources, - ECONNREFUSED => return error.ConnectionRefused, - else => |err| return unexpectedErrno(err), + return @intCast(usize, rc); + } + } else { + switch (errno(rc)) { + 0 => return @intCast(usize, rc), + EBADF => unreachable, // always a race condition + EFAULT => unreachable, + EINVAL => unreachable, + ENOTCONN => unreachable, + ENOTSOCK => unreachable, + EINTR => continue, + EAGAIN => if (std.event.Loop.instance) |loop| { + loop.waitUntilFdReadable(sockfd); + continue; + } else { + return error.WouldBlock; + }, + ENOMEM => return error.SystemResources, + ECONNREFUSED => return error.ConnectionRefused, + else => |err| return unexpectedErrno(err), + } } } } diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index df15907482..2da8d05ec6 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -1190,6 +1190,27 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so return rc; } +pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 { + var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) }; + var bytes_send: DWORD = undefined; + if (ws2_32.WSASendTo(s, @ptrCast([*]ws2_32.WSABUF, &buffer), 1, &bytes_send, flags, to, to_len, null, null) == ws2_32.SOCKET_ERROR) { + return ws2_32.SOCKET_ERROR; + } else { + return @as(i32, @intCast(u31, bytes_send)); + } +} + +pub fn recvfrom(s: ws2_32.SOCKET, buf: [*]u8, len: usize, flags: u32, from: ?*ws2_32.sockaddr, from_len: ?*ws2_32.socklen_t) i32 { + var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = buf }; + var bytes_received: DWORD = undefined; + var flags_inout = flags; + if (ws2_32.WSARecvFrom(s, @ptrCast([*]ws2_32.WSABUF, &buffer), 1, &bytes_received, &flags_inout, from, from_len, null, null) == ws2_32.SOCKET_ERROR) { + return ws2_32.SOCKET_ERROR; + } else { + return @as(i32, @intCast(u31, bytes_received)); + } +} + pub fn WSAIoctl( s: ws2_32.SOCKET, dwIoControlCode: DWORD, diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig index e226dfa967..11fcf6c70d 100644 --- a/lib/std/os/windows/ws2_32.zig +++ b/lib/std/os/windows/ws2_32.zig @@ -786,7 +786,7 @@ pub extern "ws2_32" fn WSASendTo( lpNumberOfBytesSent: ?*DWORD, dwFlags: DWORD, lpTo: ?*const sockaddr, - iTolen: socklen_t, + iTolen: c_int, lpOverlapped: ?*WSAOVERLAPPED, lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, ) callconv(.Stdcall) c_int;