NAME

Linux::Event::IO::Sock::Listener - asynchronous listening SOCK_STREAM socket

SYNOPSIS

use v5.36;
use Linux::Event::Loop;
use Linux::Event::IO::Sock::Listener;
use Linux::Event::IO::Sock::Stream;

my $loop = Linux::Event::Loop->new;
my $listener = Linux::Event::IO::Sock::Listener->new(
    loop         => $loop,
    stream_class => 'Linux::Event::IO::Sock::Stream',
    host         => '127.0.0.1',
    port         => 9999,
    on_data      => sub ($stream, $bytes) {
        $stream->write($bytes);
    },
);

$loop->run;

DESCRIPTION

Linux::Event::IO::Sock::Listener owns a listening Linux SOCK_STREAM socket and constructs the configured Linux::Event::IO::Sock::Stream subclass for every accepted connection. It is a separate public object because bind/listen/accept lifecycle is different from connected byte-stream I/O.

TCP and Unix-domain listeners share this class. Socket family is selected by constructor options, not by subclass hierarchy.

ACCEPTED STREAM SUBCLASS POLICY AND TUNING

stream_class is a prominent part of the Listener design. The selected Linux::Event::IO::Sock::Stream subclass gives every accepted connection the same native framer, TLS server identity and verification policy, socket policy, and stream_options tuning for fairness, batching, limits, watermarks, and deadlines. Linux::Event validates and caches that policy once per stream class.

Listener constructor callbacks are complementary: on_data, on_message, and the other accepted-Stream callback templates can capture lexical server state, override same-named stream methods, and are shared rather than rebuilt for every accept. This keeps reusable protocol and tuning policy in the Stream subclass while preserving ordinary closure scope for a particular listener.

The Listener's own on_accept and listener-error policy remain named subclass methods because on_error in the constructor belongs to accepted Streams.

Listener acceptance tuning

Listener tuning is constructor policy; it is distinct from the accepted class's stream_options and socket_options:

my $listener = Linux::Event::IO::Sock::Listener->new(
    loop                => $loop,
    stream_class        => 'ServerConnection',
    host                => '0.0.0.0',
    port                => 9999,
    backlog             => 8_192,
    max_accept_per_tick => 512,
);

These settings are passed directly to new; Listener does not define a class-level tuning method. The complete set is:

  • backlog (default 4,096)

    Positive listen backlog requested from the kernel.

  • max_accept_per_tick (default 256)

    Non-negative accept fairness limit. Zero drains until EAGAIN and is required when edge_triggered is enabled.

  • edge_triggered (default 0)

    Boolean 0 or 1 selecting edge-triggered accept readiness.

  • reuseaddr (default 1)

    Boolean 0 or 1 controlling SO_REUSEADDR for a created listener.

  • reuseport (default 0)

    Boolean 0 or 1 controlling SO_REUSEPORT for a created listener.

  • v6only (default unspecified)

    Optional boolean 0 or 1 controlling IPV6_V6ONLY for a created IPv6 listener.

  • bind_device (default unspecified)

    Optional non-empty interface name used with SO_BINDTODEVICE for a created Internet listener.

Unix listener ownership controls are unlink (default 0), unlink_on_close (default 1), and optional permissions from 0 through 07777. owns_socket controls ownership of an adopted fh and is not a throughput-tuning option.

CONSTRUCTION

stream_class is required and names the stream-socket subclass created for each accepted connection. Exactly one listener source is selected:

Listener->new(
    stream_class => 'ServerConnection',
    host         => '0.0.0.0',
    port         => 9999,
);

Listener->new(
    stream_class => 'ServerConnection',
    unix         => '/run/example.sock',
);

Listener->new(
    stream_class => 'ServerConnection',
    fh           => $existing_listener,
);

loop => $loop attaches immediately; otherwise add the detached object with $loop->add($listener). Listener data is supplied to each accepted connection as its initial data value.

The Listener may also receive accepted-Stream callback templates directly:

my $database = ...;
my $listener = Listener->new(
    stream_class => 'Linux::Event::IO::Sock::Stream',
    host         => '0.0.0.0',
    port         => 9999,
    on_data      => sub ($stream, $bytes) {
        persist($database, $stream, $bytes);
    },
);

Supported templates and signatures are on_data($stream, $bytes), on_message($stream, $message), on_messages($stream, $messages), on_ready($stream), on_transport_ready($stream), on_drain($stream), on_eof($stream), on_error($stream, $error), and on_close($stream). These constructor options belong to each accepted Stream; on_error($listener, $error) for the Listener itself remains a Listener subclass method. One template CV is retained by the Listener and passed to every accepted Stream. Linux::Event does not create a new closure per accept.

TCP listener policy includes backlog, reuseaddr, reuseport, optional v6only, and bind_device. Unix listeners support path ownership controls including unlink, unlink_on_close, and permissions. Adopted handles default to caller ownership unless owns_socket is true.

ACCEPTANCE

Native code drains accept4 with nonblocking and close-on-exec flags. max_accept_per_tick bounds level-triggered acceptance for fairness; zero drains until EAGAIN and is required with edge-triggered operation.

For each accepted socket Linux::Event constructs stream_class, attaches it to the same Loop, then invokes optional on_accept($listener, $stream). A plain stream's on_ready follows. For TLS, on_accept still observes the new connection immediately after attachment while on_ready waits for the TLS handshake and verification to complete.

An on_accept exception closes only that accepted connection and is reported as a callback error; it does not silently kill the listener.

TLS

TLS policy belongs to the accepted stream-socket class, not the listener. A server class declares Linux::Event::TLS with cert_file and key_file. Listener validates that server policy during construction and creates fresh TLS state for every accepted connection.

METHODS AND LIFECYCLE

port reports the bound TCP port, including the kernel-selected value after port => 0. family, family_number, is_tcp, and is_unix identify the listening socket family.

pause and resume control acceptance while retaining the listening socket. close ends ownership. detach returns the still-open listening handle and is terminal. state reports listener lifecycle such as unattached, listening, paused, closed, failed, or detached.

Runtime errors are Linux::Event::Error values. Resource exhaustion pauses acceptance before error delivery to prevent a readable-backlog error spin. A subclass may define on_error($listener, $error) to implement application policy.

SEE ALSO

Linux::Event::IO::Sock::Stream, Linux::Event::TLS, docs/LISTENER-DESIGN.md, docs/SOCKET-CONFIGURATION.md, docs/FIRST-CLASS-STREAM-CALLBACKS.md.