NAME

Linux::Event::Listener - accepting socket that constructs Stream instances

SYNOPSIS

use Linux::Event::Listener;
use Linux::Event::Loop;

package EchoStream;
use parent 'Linux::Event::Stream';

sub on_data ($stream, $bytes) {
    $stream->write($bytes);
}

package EchoListener;
use parent 'Linux::Event::Listener';

sub on_accept ($listener, $stream) {
    say "accepted " . $stream->peer->host;
}

package main;
my $loop = Linux::Event::Loop->new;
my $listener = EchoListener->new(
    loop                => $loop,         # optional: attach immediately
    stream_class        => 'EchoStream',  # required
    host                => '0.0.0.0',     # required for TCP
    port                => 7000,          # required for TCP
    backlog             => 4096,          # default
    max_accept_per_tick => 256,           # default
    edge_triggered      => 0,             # default
);
$loop->run;

DESCRIPTION

Listener creates or adopts a listening TCP or Unix stream socket, drains accepted connections with native accept4, constructs the configured Stream subclass for every accepted connection, and attaches each Stream to the same Loop. Application code never handles accepted descriptors directly.

Every accepted Stream receives the Listener's data value. Stream-level buffer, deadline, framing, and TLS policy comes from the Stream subclass's cached declarations.

CONSTRUCTION

Construct Listener directly and name the Stream subclass that it should create for accepted connections.

Every Listener can be attached in either form:

my $listener = Linux::Event::Listener->new(
    loop         => $loop,          # optional: attach immediately
    stream_class => 'ServerStream', # required
    host         => '127.0.0.1',    # required for TCP
    port         => 9000,           # required for TCP
    reuseaddr    => 1,              # default
);

my $listener = Linux::Event::Listener->new(
    stream_class => 'ServerStream',  # required
    unix         => '/run/app.sock', # required for Unix
    unlink       => 1,               # optional; default 0
    permissions  => 0660,            # optional
);
$loop->add($listener);

$loop->add sets loop, starts accepting, and returns the same Listener. A Listener may be attached only once and to only one Loop.

SOCKET SOURCES

Exactly one of these sources is required:

  • host => $host, port => $port

    Creates a TCP listener. $host may be an address, hostname, or * for a passive wildcard bind. port => 0 asks the kernel to choose a port; port() then returns the assigned value.

  • unix => $path

    Creates a filesystem Unix stream listener.

  • fh => $listening_socket

    Adopts an existing listening socket. Listener sets nonblocking and close-on-exec flags. It does not close the handle by default; pass owns_socket => 1 to transfer ownership.

OPTIONS

Common options, shown with their actual defaults, are:

my $listener = Linux::Event::Listener->new(
    stream_class        => 'ServerStream', # required
    host                => '0.0.0.0',      # required for TCP
    port                => 9000,           # required for TCP
    loop                => $loop,          # optional
    data                => $server_state,  # optional
    backlog             => 4096,           # default
    max_accept_per_tick => 256,            # default
    edge_triggered      => 0,              # default
);

max_accept_per_tick bounds accepts per level-triggered dispatch. Zero drains until EAGAIN. edge_triggered => 1 requires that zero/unbounded setting.

TCP socket options are:

my $listener = Linux::Event::Listener->new(
    stream_class => 'ServerStream', # required
    host         => '::',           # required for TCP
    port         => 9000,           # required for TCP
    reuseaddr    => 1,              # default
    reuseport    => 0,              # default
    v6only       => 1,              # optional; kernel default if omitted
    bind_device  => 'eth0',         # optional
);

Unix socket options are:

my $listener = Linux::Event::Listener->new(
    stream_class    => 'ServerStream',  # required
    unix            => '/run/app.sock', # required for Unix
    unlink          => 0,               # default
    unlink_on_close => 1,               # default
    permissions     => 0660,            # optional
);

Adopted-socket options are:

my $listener = Linux::Event::Listener->new(
    stream_class => 'ServerStream', # required
    fh           => $socket,        # required for adoption
    owns_socket  => 0,              # default
);

Source-specific options are rejected for other source types. bind_device applies Linux SO_BINDTODEVICE before a created TCP socket is bound. It is also accepted for an adopted Internet listener. The process must have the privilege required by the kernel; failure throws a structured socket_configuration Error naming bind_device.

ACCEPTED STREAMS

Listener uses native accept4 with SOCK_NONBLOCK and SOCK_CLOEXEC. For every success it constructs stream_class with fh and a lazy Linux::Event::Address peer, passes it this Listener's data, attaches the Stream to this Listener's Loop, calls the optional Listener on_accept, and then fires on_ready for a plain Stream. on_accept may replace the Stream's data when connection-specific state is needed.

A Stream subclass declares TLS directly:

package SecureStream;
use parent 'Linux::Event::Stream';
use Linux::Event::TLS
    cert_file         => '/etc/linux-event/server-cert.pem', # required
    key_file          => '/etc/linux-event/server-key.pem',  # required
    alpn              => ['echo/1'],                         # optional
    handshake_timeout => 10,                                 # default
    shutdown_timeout  => 5;                                  # default

sub on_data ($stream, $bytes) {
    $stream->write($bytes);
}

Naming SecureStream as stream_class makes every accepted connection use server TLS automatically. Listener loads and validates the declared server identity during construction. The TLS handshake begins after attachment and on_ready does not fire until it succeeds.

CALLBACKS

on_accept

A Listener subclass may define this optional callback:

sub on_accept ($listener, $stream) {
    $listener->data->{connections}{ $stream->fd } = $stream;
}

It receives the fully constructed Stream after attachment to the Listener's Loop. It runs before a plain Stream's on_ready and before a TLS Stream has completed its handshake. Use it for connection accounting, association with server state, initial policy, or immediate rejection with $stream->close.

An exception closes that accepted Stream, suppresses its pending on_ready, and delivers a nonfatal callback Error with operation on_accept to the Listener's on_error. The listening socket remains active when on_error handles the error.

on_error

Listener subclasses may override on_error($listener, $error) to implement runtime error policy. The base implementation dies. Resource-exhaustion errors pause acceptance before on_error runs; call resume after the application has restored descriptor or memory capacity.

ERROR POLICY

Runtime failures are Linux::Event::Error objects. Resource exhaustion pauses acceptance before notification to prevent an error spin. The base Listener dies after such a failure. Applications that need another policy may subclass Listener and override on_error:

package MyListener;
use parent 'Linux::Event::Listener';

sub on_error ($listener, $error) {
    warn "$error\n";
}

Constructor validation errors throw immediately, and socket-setup failures throw a structured Error.

METHODS

pause / resume

Disable or re-enable acceptance without closing the listening socket. Both return the Listener.

close

Stop accepting, remove native registration, close an owned handle, and remove an owned Unix path when configured. A terminal Listener releases its Loop.

detach

Stop accepting and return the still-open listener handle, transferring ownership to the caller. Returns undef after a terminal state.

loop / fh / fd / host / port / path

Return attachment and bound-socket information. loop is undef before attachment and after terminal cleanup. Fields that do not apply to the socket family are undefined.

family / family_number / is_tcp / is_unix

family returns inet, inet6, unix, or unknown. family_number returns the native numeric address-family constant. is_tcp is true for IPv4 and IPv6 listeners; is_unix is true for Unix listeners.

stream_class

Return the configured Stream subclass name.

state

Returns unattached, listening, paused, closed, failed, or detached.

accepted / last_error / data

Return the cumulative accepted connection count, most recent runtime error, and optional application value. data($new_value) replaces the value.

is_paused / is_running / is_terminal

Convenience predicates for the current lifecycle state.

PERFORMANCE

The Listener class caches its resolved native callbacks. XS drains accept4 in batches, while Perl is entered only for Stream construction and application policy. Accepted sockets never receive a temporary public registration before Stream attachment.