posix: remove send, sendto, sendmsg

see #6600
This commit is contained in:
Andrew Kelley
2026-01-07 15:06:04 -08:00
parent 791baefff2
commit d96d735338
2 changed files with 9 additions and 284 deletions
+9 -1
View File
@@ -1874,7 +1874,7 @@ test "accept_direct" {
try testing.expect(cqe_accept.user_data == accept_userdata);
// send data
_ = try posix.send(client, buffer_send, 0);
_ = try send(client, buffer_send, 0);
// Example of how to use registered fd:
// Submit receive to fixed file returned by accept (fd_index).
@@ -2724,3 +2724,11 @@ fn getsockname(sock: posix.socket_t, addr: *posix.sockaddr, addrlen: *posix.sock
else => return error.GetSockNameFailure,
}
}
fn send(sockfd: posix.socket_t, buf: []const u8, flags: u32) !usize {
const rc = posix.system.sendto(sockfd, buf.ptr, buf.len, flags, null, 0);
switch (posix.errno(rc)) {
.SUCCESS => return @intCast(rc),
else => return error.SendFailed,
}
}
-283
View File
@@ -1545,289 +1545,6 @@ pub fn uname() utsname {
}
}
pub const SendError = error{
/// (For UNIX domain sockets, which are identified by pathname) Write permission is denied
/// on the destination socket file, or search permission is denied for one of the
/// directories the path prefix. (See path_resolution(7).)
/// (For UDP sockets) An attempt was made to send to a network/broadcast address as though
/// it was a unicast address.
AccessDenied,
/// The socket is marked nonblocking and the requested operation would block, and
/// there is no global event loop configured.
/// It's also possible to get this error under the following condition:
/// (Internet domain datagram sockets) The socket referred to by sockfd had not previously
/// been bound to an address and, upon attempting to bind it to an ephemeral port, it was
/// determined that all port numbers in the ephemeral port range are currently in use. See
/// the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
WouldBlock,
/// Another Fast Open is already in progress.
FastOpenAlreadyInProgress,
/// Connection reset by peer.
ConnectionResetByPeer,
/// The socket type requires that message be sent atomically, and the size of the message
/// to be sent made this impossible. The message is not transmitted.
MessageOversize,
/// The output queue for a network interface was full. This generally indicates that the
/// interface has stopped sending, but may be caused by transient congestion. (Normally,
/// this does not occur in Linux. Packets are just silently dropped when a device queue
/// overflows.)
/// This is also caused when there is not enough kernel memory available.
SystemResources,
/// The local end has been shut down on a connection oriented socket. In this case, the
/// process will also receive a SIGPIPE unless MSG.NOSIGNAL is set.
BrokenPipe,
FileDescriptorNotASocket,
/// Network is unreachable.
NetworkUnreachable,
/// The local network interface used to reach the destination is down.
NetworkDown,
/// The destination address is not listening.
ConnectionRefused,
} || UnexpectedError;
pub const SendMsgError = SendError || error{
/// The passed address didn't have the correct address family in its sa_family field.
AddressFamilyUnsupported,
/// Returned when socket is AF.UNIX and the given path has a symlink loop.
SymLinkLoop,
/// Returned when socket is AF.UNIX and the given path length exceeds `max_path_bytes` bytes.
NameTooLong,
/// Returned when socket is AF.UNIX and the given path does not point to an existing file.
FileNotFound,
NotDir,
/// The socket is not connected (connection-oriented sockets only).
SocketUnconnected,
AddressUnavailable,
};
pub fn sendmsg(
/// The file descriptor of the sending socket.
sockfd: socket_t,
/// Message header and iovecs
msg: *const msghdr_const,
flags: u32,
) SendMsgError!usize {
while (true) {
const rc = system.sendmsg(sockfd, msg, flags);
if (native_os == .windows) {
if (rc == windows.ws2_32.SOCKET_ERROR) {
switch (windows.ws2_32.WSAGetLastError()) {
.EACCES => return error.AccessDenied,
.EADDRNOTAVAIL => return error.AddressUnavailable,
.ECONNRESET => return error.ConnectionResetByPeer,
.EMSGSIZE => return error.MessageOversize,
.ENOBUFS => return error.SystemResources,
.ENOTSOCK => return error.FileDescriptorNotASocket,
.EAFNOSUPPORT => return error.AddressFamilyUnsupported,
.EDESTADDRREQ => unreachable, // A destination address is required.
.EFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small.
.EHOSTUNREACH => return error.NetworkUnreachable,
// TODO: EINPROGRESS, EINTR
.EINVAL => unreachable,
.ENETDOWN => return error.NetworkDown,
.ENETRESET => return error.ConnectionResetByPeer,
.ENETUNREACH => return error.NetworkUnreachable,
.ENOTCONN => return error.SocketUnconnected,
.ESHUTDOWN => 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.
.EWOULDBLOCK => return error.WouldBlock,
.NOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function.
else => |err| return windows.unexpectedWSAError(err),
}
} else {
return @intCast(rc);
}
} else {
switch (errno(rc)) {
.SUCCESS => return @intCast(rc),
.ACCES => return error.AccessDenied,
.AGAIN => return error.WouldBlock,
.ALREADY => return error.FastOpenAlreadyInProgress,
.BADF => unreachable, // always a race condition
.CONNRESET => return error.ConnectionResetByPeer,
.DESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set.
.FAULT => unreachable, // An invalid user space address was specified for an argument.
.INTR => continue,
.INVAL => unreachable, // Invalid argument passed.
.ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
.MSGSIZE => return error.MessageOversize,
.NOBUFS => return error.SystemResources,
.NOMEM => return error.SystemResources,
.NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
.OPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
.PIPE => return error.BrokenPipe,
.AFNOSUPPORT => return error.AddressFamilyUnsupported,
.LOOP => return error.SymLinkLoop,
.NAMETOOLONG => return error.NameTooLong,
.NOENT => return error.FileNotFound,
.NOTDIR => return error.NotDir,
.HOSTUNREACH => return error.NetworkUnreachable,
.NETUNREACH => return error.NetworkUnreachable,
.NOTCONN => return error.SocketUnconnected,
.NETDOWN => return error.NetworkDown,
else => |err| return unexpectedErrno(err),
}
}
}
}
pub const SendToError = SendMsgError || error{
/// The destination address is not reachable by the bound address.
UnreachableAddress,
/// The destination address is not listening.
ConnectionRefused,
};
/// 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
/// recipient is known). The following call
///
/// send(sockfd, buf, len, flags);
///
/// is equivalent to
///
/// sendto(sockfd, buf, len, flags, NULL, 0);
///
/// If sendto() is used on a connection-mode (`SOCK.STREAM`, `SOCK.SEQPACKET`) socket, the arguments
/// `dest_addr` and `addrlen` are asserted to be `null` and `0` respectively, and asserted
/// that the socket was actually connected.
/// Otherwise, the address of the target is given by `dest_addr` with `addrlen` specifying its size.
///
/// If the message is too long to pass atomically through the underlying protocol,
/// `SendError.MessageOversize` is returned, and the message is not transmitted.
///
/// There is no indication of failure to deliver.
///
/// When the message does not fit into the send buffer of the socket, `sendto` normally blocks,
/// unless the socket has been placed in nonblocking I/O mode. In nonblocking mode it would fail
/// with `SendError.WouldBlock`. The `select` call may be used to determine when it is
/// possible to send more data.
pub fn sendto(
/// The file descriptor of the sending socket.
sockfd: socket_t,
/// Message to send.
buf: []const u8,
flags: u32,
dest_addr: ?*const sockaddr,
addrlen: socklen_t,
) SendToError!usize {
if (native_os == .windows) {
switch (windows.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen)) {
windows.ws2_32.SOCKET_ERROR => switch (windows.ws2_32.WSAGetLastError()) {
.EACCES => return error.AccessDenied,
.EADDRNOTAVAIL => return error.AddressUnavailable,
.ECONNRESET => return error.ConnectionResetByPeer,
.EMSGSIZE => return error.MessageOversize,
.ENOBUFS => return error.SystemResources,
.ENOTSOCK => return error.FileDescriptorNotASocket,
.EAFNOSUPPORT => return error.AddressFamilyUnsupported,
.EDESTADDRREQ => unreachable, // A destination address is required.
.EFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small.
.EHOSTUNREACH => return error.NetworkUnreachable,
// TODO: EINPROGRESS, EINTR
.EINVAL => unreachable,
.ENETDOWN => return error.NetworkDown,
.ENETRESET => return error.ConnectionResetByPeer,
.ENETUNREACH => return error.NetworkUnreachable,
.ENOTCONN => return error.SocketUnconnected,
.ESHUTDOWN => 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.
.EWOULDBLOCK => return error.WouldBlock,
.NOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function.
else => |err| return windows.unexpectedWSAError(err),
},
else => |rc| return @intCast(rc),
}
}
while (true) {
const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);
switch (errno(rc)) {
.SUCCESS => return @intCast(rc),
.ACCES => return error.AccessDenied,
.AGAIN => return error.WouldBlock,
.ALREADY => return error.FastOpenAlreadyInProgress,
.BADF => unreachable, // always a race condition
.CONNREFUSED => return error.ConnectionRefused,
.CONNRESET => return error.ConnectionResetByPeer,
.DESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set.
.FAULT => unreachable, // An invalid user space address was specified for an argument.
.INTR => continue,
.INVAL => return error.UnreachableAddress,
.ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
.MSGSIZE => return error.MessageOversize,
.NOBUFS => return error.SystemResources,
.NOMEM => return error.SystemResources,
.NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
.OPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
.PIPE => return error.BrokenPipe,
.AFNOSUPPORT => return error.AddressFamilyUnsupported,
.LOOP => return error.SymLinkLoop,
.NAMETOOLONG => return error.NameTooLong,
.NOENT => return error.FileNotFound,
.NOTDIR => return error.NotDir,
.HOSTUNREACH => return error.NetworkUnreachable,
.NETUNREACH => return error.NetworkUnreachable,
.NOTCONN => return error.SocketUnconnected,
.NETDOWN => return error.NetworkDown,
else => |err| return unexpectedErrno(err),
}
}
}
/// Transmit a message to another socket.
///
/// The `send` call may be used only when the socket is in a connected state (so that the intended
/// recipient is known). The only difference between `send` and `write` is the presence of
/// flags. With a zero flags argument, `send` is equivalent to `write`. Also, the following
/// call
///
/// send(sockfd, buf, len, flags);
///
/// is equivalent to
///
/// sendto(sockfd, buf, len, flags, NULL, 0);
///
/// There is no indication of failure to deliver.
///
/// When the message does not fit into the send buffer of the socket, `send` normally blocks,
/// unless the socket has been placed in nonblocking I/O mode. In nonblocking mode it would fail
/// with `SendError.WouldBlock`. The `select` call may be used to determine when it is
/// possible to send more data.
pub fn send(
/// The file descriptor of the sending socket.
sockfd: socket_t,
buf: []const u8,
flags: u32,
) SendError!usize {
return sendto(sockfd, buf, flags, null, 0) catch |err| switch (err) {
error.AddressFamilyUnsupported => unreachable,
error.SymLinkLoop => unreachable,
error.NameTooLong => unreachable,
error.FileNotFound => unreachable,
error.NotDir => unreachable,
error.NetworkUnreachable => unreachable,
error.AddressUnavailable => unreachable,
error.SocketUnconnected => unreachable,
error.UnreachableAddress => unreachable,
else => |e| return e,
};
}
pub const PollError = error{
/// The network subsystem has failed.
NetworkDown,