An open port with unspecified protocol.
pub const Socket = struct
pub const Socket = struct {
handle: Handle,
/// Contains the resolved ephemeral port number if requested.
address: IpAddress,
pub const Mode = enum {
/// Provides sequenced, reliable, two-way, connection-based byte
/// streams. An out-of-band data transmission mechanism may be
/// supported.
stream,
/// Supports datagrams (connectionless, unreliable messages of a fixed
/// maximum length).
dgram,
/// Provides a sequenced, reliable, two-way connection-based data
/// transmission path for datagrams of fixed maximum length; a consumer
/// is required to read an entire packet with each input system call.
seqpacket,
/// Provides raw network protocol access.
raw,
/// Provides a reliable datagram layer that does not guarantee ordering.
rdm,
};
/// Underlying platform-defined type which may or may not be
/// interchangeable with a file system file descriptor.
pub const Handle = std.posix.fd_t;
/// Leaves `address` in a valid state.
pub fn close(s: *const Socket, io: Io) void {
io.vtable.netClose(io.userdata, (&s.handle)[0..1]);
}
pub fn closeMany(io: Io, sockets: []const Socket) void {
io.vtable.netClose(io.userdata, sockets);
}
pub const SendError = error{
/// The socket type requires that message be sent atomically, and the
/// size of the message to be sent made this impossible. The message
/// was not transmitted, or was partially 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,
/// No route to network.
NetworkUnreachable,
/// Network reached but no route to host.
HostUnreachable,
/// The local network interface used to reach the destination is offline.
NetworkDown,
/// The destination address is not listening. Can still occur for
/// connectionless messages.
ConnectionRefused,
/// Operating system or protocol does not support the address family.
AddressFamilyUnsupported,
/// Another TCP Fast Open is already in progress.
FastOpenAlreadyInProgress,
/// Network session was unexpectedly closed by recipient.
ConnectionResetByPeer,
/// Local end has been shut down on a connection-oriented socket, or
/// the socket was never connected.
SocketUnconnected,
/// An attempt was made to send to a network/broadcast address as
/// though it was a unicast address.
AccessDenied,
} || Io.UnexpectedError || Io.Cancelable;
/// Transfers `data` to `dest`, connectionless, in one packet.
pub fn send(s: *const Socket, io: Io, dest: *const IpAddress, data: []const u8) SendError!void {
var message: OutgoingMessage = .{ .address = dest, .data_ptr = data.ptr, .data_len = data.len };
const err, const n = io.vtable.netSend(io.userdata, s.handle, (&message)[0..1], .{});
if (n != 1) return err.?;
if (message.data_len != data.len) return error.MessageOversize;
}
pub fn sendMany(s: *const Socket, io: Io, messages: []OutgoingMessage, flags: SendFlags) SendError!void {
const err, const n = io.vtable.netSend(io.userdata, s.handle, messages, flags);
if (n != messages.len) return err.?;
}
pub const ReceiveError = Io.Operation.NetReceive.Error || Io.Cancelable;
/// Waits for data. Connectionless.
///
/// See also:
/// * `receiveTimeout`
pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage {
var message: IncomingMessage = .init;
const maybe_err, const count = (try io.operate(.{ .net_receive = .{
.socket_handle = s.handle,
.message_buffer = (&message)[0..1],
.data_buffer = buffer,
.flags = .{},
} })).net_receive;
if (maybe_err) |err| return err;
assert(1 == count);
return message;
}
pub const ReceiveTimeoutError = ReceiveError || Io.Timeout.Error || Io.ConcurrentError;
/// Waits for data. Connectionless.
///
/// Returns `error.Timeout` if no message arrives early enough.
///
/// See also:
/// * `receive`
/// * `receiveManyTimeout`
pub fn receiveTimeout(
s: *const Socket,
io: Io,
buffer: []u8,
timeout: Io.Timeout,
) ReceiveTimeoutError!IncomingMessage {
var message: IncomingMessage = .init;
const maybe_err, const count = (try io.operateTimeout(.{ .net_receive = .{
.socket_handle = s.handle,
.message_buffer = (&message)[0..1],
.data_buffer = buffer,
.flags = .{},
} }, timeout)).net_receive;
if (maybe_err) |err| return err;
assert(1 == count);
return message;
}
/// Waits until at least one message is delivered, possibly returning more
/// than one message. Connectionless.
///
/// Returns number of messages received, or `error.Timeout` if no message
/// arrives early enough.
///
/// See also:
/// * `receive`
/// * `receiveTimeout`
pub fn receiveManyTimeout(
s: *const Socket,
io: Io,
/// Function assumes each element has initialized `control` field.
/// Initializing with `IncomingMessage.init` may be helpful.
message_buffer: []IncomingMessage,
data_buffer: []u8,
flags: ReceiveFlags,
timeout: Io.Timeout,
) struct { ?ReceiveTimeoutError, usize } {
const result = io.operateTimeout(.{ .net_receive = .{
.socket_handle = s.handle,
.message_buffer = message_buffer,
.data_buffer = data_buffer,
.flags = flags,
} }, timeout) catch |err| return .{ err, 0 };
return result.net_receive;
}
pub const CreatePairError = error{
OperationUnsupported,
AccessDenied,
AddressFamilyUnsupported,
ProtocolUnsupportedBySystem,
/// The per-process limit on the number of open file descriptors has been reached.
ProcessFdQuotaExceeded,
/// The system-wide limit on the total number of open files has been reached.
SystemFdQuotaExceeded,
/// Insufficient memory is available. The socket cannot be created
/// until sufficient resources are freed.
SystemResources,
ProtocolUnsupportedByAddressFamily,
SocketModeUnsupported,
} || Io.UnexpectedError || Io.Cancelable;
pub const CreatePairOptions = struct {
family: IpAddress.Family = .ip4,
mode: Mode = .stream,
protocol: ?Protocol = null,
};
/// Create a set of two sockets that are connected to each other.
///
/// Also known as "socketpair".
pub fn createPair(io: Io, options: CreatePairOptions) CreatePairError![2]Socket {
return io.vtable.netSocketCreatePair(io.userdata, options);
}
}