authorgravatar for quae@daurnimator.comdaurnimator <quae@daurnimator.com> 2021-02-27 14:19:38+11:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-28 21:57:43+02:00
log1f17221bc4e17bcd7116fe12ab3f939346179799
tree6073c4569cb25b6d232bab68971896b16b135844
parent294ee1bbc93a00ead5182234f824b0a665c579d9

std: add sendmsg


5 files changed, 96 insertions(+), 10 deletions(-)

lib/std/os.zig+74-1
...@@ -4840,7 +4840,7 @@ pub const SendError = error{...@@ -4840,7 +4840,7 @@ pub const SendError = error{
4840 NetworkSubsystemFailed,4840 NetworkSubsystemFailed,
4841} || UnexpectedError;4841} || UnexpectedError;
48424842
4843pub const SendToError = SendError || error{4843pub const SendMsgError = SendError || error{
4844 /// The passed address didn't have the correct address family in its sa_family field.4844 /// The passed address didn't have the correct address family in its sa_family field.
4845 AddressFamilyNotSupported,4845 AddressFamilyNotSupported,
48464846
...@@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{...@@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{
4859 AddressNotAvailable,4859 AddressNotAvailable,
4860};4860};
48614861
4862pub fn sendmsg(
4863 /// The file descriptor of the sending socket.
4864 sockfd: socket_t,
4865 /// Message header and iovecs
4866 msg: msghdr_const,
4867 flags: u32,
4868) SendMsgError!usize {
4869 while (true) {
4870 const rc = system.sendmsg(sockfd, &msg, flags);
4871 if (builtin.os.tag == .windows) {
4872 if (rc == windows.ws2_32.SOCKET_ERROR) {
4873 switch (windows.ws2_32.WSAGetLastError()) {
4874 .WSAEACCES => return error.AccessDenied,
4875 .WSAEADDRNOTAVAIL => return error.AddressNotAvailable,
4876 .WSAECONNRESET => return error.ConnectionResetByPeer,
4877 .WSAEMSGSIZE => return error.MessageTooBig,
4878 .WSAENOBUFS => return error.SystemResources,
4879 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
4880 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
4881 .WSAEDESTADDRREQ => unreachable, // A destination address is required.
4882 .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.
4883 .WSAEHOSTUNREACH => return error.NetworkUnreachable,
4884 // TODO: WSAEINPROGRESS, WSAEINTR
4885 .WSAEINVAL => unreachable,
4886 .WSAENETDOWN => return error.NetworkSubsystemFailed,
4887 .WSAENETRESET => return error.ConnectionResetByPeer,
4888 .WSAENETUNREACH => return error.NetworkUnreachable,
4889 .WSAENOTCONN => return error.SocketNotConnected,
4890 .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.
4891 .WSAEWOULDBLOCK => return error.WouldBlock,
4892 .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function.
4893 else => |err| return windows.unexpectedWSAError(err),
4894 }
4895 } else {
4896 return @intCast(usize, rc);
4897 }
4898 } else {
4899 switch (errno(rc)) {
4900 0 => return @intCast(usize, rc),
4901
4902 EACCES => return error.AccessDenied,
4903 EAGAIN => return error.WouldBlock,
4904 EALREADY => return error.FastOpenAlreadyInProgress,
4905 EBADF => unreachable, // always a race condition
4906 ECONNRESET => return error.ConnectionResetByPeer,
4907 EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set.
4908 EFAULT => unreachable, // An invalid user space address was specified for an argument.
4909 EINTR => continue,
4910 EINVAL => unreachable, // Invalid argument passed.
4911 EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
4912 EMSGSIZE => return error.MessageTooBig,
4913 ENOBUFS => return error.SystemResources,
4914 ENOMEM => return error.SystemResources,
4915 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
4916 EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
4917 EPIPE => return error.BrokenPipe,
4918 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
4919 ELOOP => return error.SymLinkLoop,
4920 ENAMETOOLONG => return error.NameTooLong,
4921 ENOENT => return error.FileNotFound,
4922 ENOTDIR => return error.NotDir,
4923 EHOSTUNREACH => return error.NetworkUnreachable,
4924 ENETUNREACH => return error.NetworkUnreachable,
4925 ENOTCONN => return error.SocketNotConnected,
4926 ENETDOWN => return error.NetworkSubsystemFailed,
4927 else => |err| return unexpectedErrno(err),
4928 }
4929 }
4930 }
4931}
4932
4933pub const SendToError = SendMsgError;
4934
4862/// Transmit a message to another socket.4935/// Transmit a message to another socket.
4863///4936///
4864/// The `sendto` call may be used only when the socket is in a connected state (so that the intended4937/// The `sendto` call may be used only when the socket is in a connected state (so that the intended
lib/std/os/bits/linux/arm64.zig+4-4
...@@ -400,10 +400,10 @@ pub const msghdr = extern struct {...@@ -400,10 +400,10 @@ pub const msghdr = extern struct {
400 msg_namelen: socklen_t,400 msg_namelen: socklen_t,
401 msg_iov: [*]iovec,401 msg_iov: [*]iovec,
402 msg_iovlen: i32,402 msg_iovlen: i32,
403 __pad1: i32,403 __pad1: i32 = 0,
404 msg_control: ?*c_void,404 msg_control: ?*c_void,
405 msg_controllen: socklen_t,405 msg_controllen: socklen_t,
406 __pad2: socklen_t,406 __pad2: socklen_t = 0,
407 msg_flags: i32,407 msg_flags: i32,
408};408};
409409
...@@ -412,10 +412,10 @@ pub const msghdr_const = extern struct {...@@ -412,10 +412,10 @@ pub const msghdr_const = extern struct {
412 msg_namelen: socklen_t,412 msg_namelen: socklen_t,
413 msg_iov: [*]iovec_const,413 msg_iov: [*]iovec_const,
414 msg_iovlen: i32,414 msg_iovlen: i32,
415 __pad1: i32,415 __pad1: i32 = 0,
416 msg_control: ?*c_void,416 msg_control: ?*c_void,
417 msg_controllen: socklen_t,417 msg_controllen: socklen_t,
418 __pad2: socklen_t,418 __pad2: socklen_t = 0,
419 msg_flags: i32,419 msg_flags: i32,
420};420};
421421
lib/std/os/bits/linux/x86_64.zig+4-4
...@@ -495,10 +495,10 @@ pub const msghdr = extern struct {...@@ -495,10 +495,10 @@ pub const msghdr = extern struct {
495 msg_namelen: socklen_t,495 msg_namelen: socklen_t,
496 msg_iov: [*]iovec,496 msg_iov: [*]iovec,
497 msg_iovlen: i32,497 msg_iovlen: i32,
498 __pad1: i32,498 __pad1: i32 = 0,
499 msg_control: ?*c_void,499 msg_control: ?*c_void,
500 msg_controllen: socklen_t,500 msg_controllen: socklen_t,
501 __pad2: socklen_t,501 __pad2: socklen_t = 0,
502 msg_flags: i32,502 msg_flags: i32,
503};503};
504504
...@@ -507,10 +507,10 @@ pub const msghdr_const = extern struct {...@@ -507,10 +507,10 @@ pub const msghdr_const = extern struct {
507 msg_namelen: socklen_t,507 msg_namelen: socklen_t,
508 msg_iov: [*]iovec_const,508 msg_iov: [*]iovec_const,
509 msg_iovlen: i32,509 msg_iovlen: i32,
510 __pad1: i32,510 __pad1: i32 = 0,
511 msg_control: ?*c_void,511 msg_control: ?*c_void,
512 msg_controllen: socklen_t,512 msg_controllen: socklen_t,
513 __pad2: socklen_t,513 __pad2: socklen_t = 0,
514 msg_flags: i32,514 msg_flags: i32,
515};515};
516516
lib/std/os/linux.zig+1-1
...@@ -977,7 +977,7 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal...@@ -977,7 +977,7 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal
977 return syscall5(.getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));977 return syscall5(.getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
978}978}
979979
980pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize {980pub fn sendmsg(fd: i32, msg: *const msghdr_const, flags: u32) usize {
981 if (builtin.arch == .i386) {981 if (builtin.arch == .i386) {
982 return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags });982 return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags });
983 }983 }
lib/std/os/windows.zig+13
...@@ -1291,6 +1291,19 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so...@@ -1291,6 +1291,19 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so
1291 return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen));1291 return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen));
1292}1292}
12931293
1294pub fn sendmsg(
1295 s: ws2_32.SOCKET,
1296 msg: *const ws2_32.WSAMSG,
1297 flags: u32,
1298) i32 {
1299 var bytes_send: DWORD = undefined;
1300 if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) {
1301 return ws2_32.SOCKET_ERROR;
1302 } else {
1303 return @as(i32, @intCast(u31, bytes_send));
1304 }
1305}
1306
1294pub 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 {1307pub 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 {
1295 var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) };1308 var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) };
1296 var bytes_send: DWORD = undefined;1309 var bytes_send: DWORD = undefined;