NAME
Linux::Event::Datagram - connected and unconnected packet sockets
SYNOPSIS
package LE::Discovery;
use parent 'Linux::Event::Datagram';
sub on_datagram ($socket, $payload, $peer) {
$socket->send($payload, to => $peer); # required when unconnected
}
package main;
my $socket = $loop->add(LE::Discovery->new(
host => '0.0.0.0', # required for UDP bind
port => 9999, # required for UDP bind
));
DESCRIPTION
Datagram preserves packet boundaries and peer addresses for UDP and Unix datagram sockets. A concrete subclass defines one named on_datagram method. Connected and unconnected endpoints share one lifecycle and native packet I/O engine; Datagram does not reuse byte-stream buffering or framing semantics.
An Internet or Unix server socket is created and bound during new. It starts in unattached state until added to a Loop. A connected socket is created when connect attaches, so hostname resolution and connection failure are reported through the asynchronous lifecycle. Output queued before attachment is retained whole.
UNCONNECTED UDP
my $socket = LE::Discovery->new(
loop => $loop, # optional: attach immediately
host => '0.0.0.0', # required
port => 9999, # required; 0 selects an ephemeral port
reuseaddr => 0, # default
reuseport => 0, # default
broadcast => 0, # default
);
Send each packet to an explicit Linux::Event::Address:
$socket->send($payload, to => $peer); # required when unconnected
CONNECTED UDP
my $socket = LE::Telemetry->connect(
loop => $loop, # optional
host => 'collector.example.com', # required
port => 9000, # required
local_host => '0.0.0.0', # optional
local_port => 0, # optional; default 0
);
Hostname resolution uses the Loop's native resolver workers. on_ready runs on a later Loop turn after the socket is available. UDP connect stores a default peer and filters input; it does not establish a network session.
local_host accepts a numeric IPv4 or IPv6 address only. It never starts a second DNS lookup. local_port without local_host binds the matching wildcard family. An incompatible local and peer family produces a structured socket_configuration error.
Send without a destination:
$socket->send($payload);
UNIX DATAGRAMS
my $server = LE::LocalServer->new(
unix => '/run/app.sock', # required
unlink => 0, # default
unlink_on_close => 1, # default
permissions => 0660, # optional
);
my $client = LE::LocalClient->connect(
unix => '/run/app.sock', # required peer path
local_unix => '/run/app-client.sock', # optional reply path
unlink => 0, # default
unlink_on_close => 1, # default
permissions => 0600, # optional
);
ADOPTED SOCKETS
my $socket = LE::Existing->new(
fh => $fh, # required
owns_socket => 0, # default
);
Datagram sets nonblocking and close-on-exec flags and detects whether the socket has a default peer. owns_socket => 1 transfers close ownership.
CLASS POLICY
sub datagram_options ($class) {
return (
max_datagram_size => 65_535, # default
max_datagrams_per_tick => 256, # default
edge_triggered => 0, # default
high_watermark => 1_048_576, # default
low_watermark => 262_144, # default
max_pending_bytes => 0, # default: unlimited
max_pending_datagrams => 0, # default: unlimited
reuseaddr => 0, # default
reuseport => 0, # default
broadcast => 0, # default
v6only => 1, # optional
send_buffer => 262_144, # optional; bytes
receive_buffer => 262_144, # optional; bytes
);
}
The method runs once per concrete subclass. Constructor values override class policy. An omitted optional socket setting leaves the kernel setting unchanged. edge_triggered => 1 requires max_datagrams_per_tick => 0 so readiness always drains to EAGAIN.
reuseaddr, reuseport, broadcast, v6only, and bind_device apply only to Internet sockets. broadcast is IPv4-only and v6only is IPv6-only. unlink, unlink_on_close, and permissions apply only to created Unix paths. Source-specific options are rejected even when explicitly set to a false value, preventing configuration that appears accepted but has no effect. Send and receive buffers apply to Internet, Unix, and adopted sockets.
CALLBACKS
sub on_datagram ($socket, $payload, $peer) { # required
$socket->is_connected
? $socket->send("ack:$payload")
: $socket->send("ack:$payload", to => $peer); # required unconnected
}
sub on_drain ($socket) { # optional
$socket->data->{blocked} = 0 if $socket->data;
}
sub on_ready ($socket) { # optional
$socket->send('started') if $socket->is_connected;
}
sub on_error ($socket, $error) { # optional
warn "$error\n";
}
sub on_close ($socket) { # optional
$socket->data->{closed} = 1 if $socket->data;
}
$peer is always an Address. Callback CVs are cached per subclass. Callback exceptions propagate from Loop dispatch.
An advanced subclass may customize a newly acquired socket:
use Socket qw(SOL_SOCKET SO_RCVBUF);
sub configure_socket ($socket, $fh, $role, $address) {
setsockopt($fh, SOL_SOCKET, SO_RCVBUF, pack('i', 524_288))
or die "setsockopt(SO_RCVBUF): $!";
}
$role is bind, connect, or adopted. For bind, $address is the effective local Address and the hook runs after the socket has been bound. Built-in policy is applied before this hook and before a connected socket performs local binding or connect.
on_error receives connection, packet-I/O, queue-limit, truncation, and socket-configuration failures. A terminal connection failure has already released native resources, but $socket->loop remains available during the callback and is released when it returns. Without on_error, Datagram warns and retains the failure in last_error.
OUTPUT AND BACKPRESSURE
send represents exactly one packet. A packet that would block is queued whole. The return is false when accepted output is above the soft high watermark; on_drain runs after it reaches the low watermark. A hard byte or packet limit rejects only the new packet and reports an output_limit error.
Input larger than max_datagram_size is detected with MSG_TRUNC, discarded whole, and reported as datagram_size. Partial packets are never delivered.
METHODS
send($payload) / send($payload, to => $address)
Send on a connected endpoint or to an explicit peer on an unconnected one. The payload must be a byte string.
local / peer
Return the local Address and the connected peer. peer is undef for an unconnected endpoint.
pause_read / resume_read
Disable or re-enable input readiness without closing the socket.
send_buffer([$bytes]) / receive_buffer([$bytes]) / broadcast([$boolean])
Get or live-set the effective Linux socket value. Linux may round or double buffer requests, so buffer setters return the value read back from the kernel. broadcast is available only on IPv4 sockets.
pending_bytes / pending_datagrams
Return queued output totals.
close / detach
close ends ownership. detach cancels readiness and returns the still-open handle without unlinking a Unix path or calling on_close. on_close runs for explicit close while the Loop remains available, then the object releases its Loop.
data([$value]) / loop / fh / fd / state / last_error
Return or update ordinary instance and lifecycle information.
is_connected / is_active / is_terminal / is_read_paused
Report socket and lifecycle categories.