diff --git a/lib/std/os.zig b/lib/std/os.zig index 24d9041639..a2e62ed0ae 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4840,7 +4840,7 @@ pub const SendError = error{ NetworkSubsystemFailed, } || UnexpectedError; -pub const SendToError = SendError || error{ +pub const SendMsgError = SendError || error{ /// The passed address didn't have the correct address family in its sa_family field. AddressFamilyNotSupported, @@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{ AddressNotAvailable, }; +pub fn sendmsg( + /// The file descriptor of the sending socket. + sockfd: socket_t, + /// Message header and iovecs + msg: msghdr_const, + flags: u32, +) SendMsgError!usize { + while (true) { + const rc = system.sendmsg(sockfd, &msg, flags); + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSAEACCES => return error.AccessDenied, + .WSAEADDRNOTAVAIL => return error.AddressNotAvailable, + .WSAECONNRESET => return error.ConnectionResetByPeer, + .WSAEMSGSIZE => return error.MessageTooBig, + .WSAENOBUFS => return error.SystemResources, + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, + .WSAEDESTADDRREQ => unreachable, // A destination address is required. + .WSAEFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small. + .WSAEHOSTUNREACH => return error.NetworkUnreachable, + // TODO: WSAEINPROGRESS, WSAEINTR + .WSAEINVAL => unreachable, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAENETRESET => return error.ConnectionResetByPeer, + .WSAENETUNREACH => return error.NetworkUnreachable, + .WSAENOTCONN => return error.SocketNotConnected, + .WSAESHUTDOWN => unreachable, // The socket has been shut down; it is not possible to WSASendTo on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH. + .WSAEWOULDBLOCK => return error.WouldBlock, + .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. + else => |err| return windows.unexpectedWSAError(err), + } + } else { + return @intCast(usize, rc); + } + } else { + switch (errno(rc)) { + 0 => return @intCast(usize, rc), + + EACCES => return error.AccessDenied, + EAGAIN => 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, + 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, + EAFNOSUPPORT => return error.AddressFamilyNotSupported, + ELOOP => return error.SymLinkLoop, + ENAMETOOLONG => return error.NameTooLong, + ENOENT => return error.FileNotFound, + ENOTDIR => return error.NotDir, + EHOSTUNREACH => return error.NetworkUnreachable, + ENETUNREACH => return error.NetworkUnreachable, + ENOTCONN => return error.SocketNotConnected, + ENETDOWN => return error.NetworkSubsystemFailed, + else => |err| return unexpectedErrno(err), + } + } + } +} + +pub const SendToError = SendMsgError; + /// Transmit a message to another socket. /// /// The `sendto` call may be used only when the socket is in a connected state (so that the intended diff --git a/lib/std/os/bits/linux/arm64.zig b/lib/std/os/bits/linux/arm64.zig index a069b6adf1..e373d978e1 100644 --- a/lib/std/os/bits/linux/arm64.zig +++ b/lib/std/os/bits/linux/arm64.zig @@ -400,10 +400,10 @@ pub const msghdr = extern struct { msg_namelen: socklen_t, msg_iov: [*]iovec, msg_iovlen: i32, - __pad1: i32, + __pad1: i32 = 0, msg_control: ?*c_void, msg_controllen: socklen_t, - __pad2: socklen_t, + __pad2: socklen_t = 0, msg_flags: i32, }; @@ -412,10 +412,10 @@ pub const msghdr_const = extern struct { msg_namelen: socklen_t, msg_iov: [*]iovec_const, msg_iovlen: i32, - __pad1: i32, + __pad1: i32 = 0, msg_control: ?*c_void, msg_controllen: socklen_t, - __pad2: socklen_t, + __pad2: socklen_t = 0, msg_flags: i32, }; diff --git a/lib/std/os/bits/linux/x86_64.zig b/lib/std/os/bits/linux/x86_64.zig index 52fee679c5..88d277a0c5 100644 --- a/lib/std/os/bits/linux/x86_64.zig +++ b/lib/std/os/bits/linux/x86_64.zig @@ -495,10 +495,10 @@ pub const msghdr = extern struct { msg_namelen: socklen_t, msg_iov: [*]iovec, msg_iovlen: i32, - __pad1: i32, + __pad1: i32 = 0, msg_control: ?*c_void, msg_controllen: socklen_t, - __pad2: socklen_t, + __pad2: socklen_t = 0, msg_flags: i32, }; @@ -507,10 +507,10 @@ pub const msghdr_const = extern struct { msg_namelen: socklen_t, msg_iov: [*]iovec_const, msg_iovlen: i32, - __pad1: i32, + __pad1: i32 = 0, msg_control: ?*c_void, msg_controllen: socklen_t, - __pad2: socklen_t, + __pad2: socklen_t = 0, msg_flags: i32, }; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 035cdabe63..900e3f2871 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -977,7 +977,7 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal return syscall5(.getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); } -pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize { +pub fn sendmsg(fd: i32, msg: *const msghdr_const, flags: u32) usize { if (builtin.arch == .i386) { return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); } diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 6f67b65252..1791fec956 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -1291,6 +1291,19 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen)); } +pub fn sendmsg( + s: ws2_32.SOCKET, + msg: *const ws2_32.WSAMSG, + flags: u32, +) i32 { + var bytes_send: DWORD = undefined; + if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) { + return ws2_32.SOCKET_ERROR; + } else { + return @as(i32, @intCast(u31, bytes_send)); + } +} + 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;