Sockets

getsockopt#

Read one socket option out of the kernel as an opaque packed string.

getsockopt asks the kernel for the current value of the option named OPTNAME at protocol level LEVEL on SOCKET. The kernel does not return a typed value — it returns a raw byte buffer whose layout is determined by the (LEVEL, OPTNAME) pair. You decode that buffer with unpack, usually with the "i" or "I" template, because most options are plain integers.

Synopsis#

getsockopt SOCKET, LEVEL, OPTNAME

What you get back#

A packed string holding the kernel’s reply on success, or undef on failure with $! set to the system error. The string’s contents are opaque bytes — its length and layout depend entirely on (LEVEL, OPTNAME):

  • Boolean and integer options (SO_KEEPALIVE, SO_REUSEADDR, TCP_NODELAY, …) come back as a packed int. Decode with unpack using "i" or "I".

  • Timeouts (SO_RCVTIMEO, SO_SNDTIMEO) come back as a packed struct timeval — two longs on most platforms.

  • Address-bound options (SO_PEERCRED, IP_MULTICAST_IF, linger structs, …) have their own layouts; consult getsockopt(2) and the relevant protocol man pages for the exact struct.

Always check the return value before decoding — calling unpack on undef yields an empty result and hides the real error recorded in $!.

Global state it touches#

  • $! is set on failure to the errno value from the underlying getsockopt(2) call. It is not cleared on success, so check the return value, not $! directly.

Examples#

Check whether Nagle’s algorithm is currently disabled (TCP_NODELAY set) on a TCP socket:

use Socket qw(IPPROTO_TCP TCP_NODELAY);

my $packed = getsockopt($sock, IPPROTO_TCP, TCP_NODELAY)
    or die "getsockopt TCP_NODELAY: $!";
my $nodelay = unpack("I", $packed);
print "Nagle is ", $nodelay ? "off" : "on", "\n";

Same idea, but obtaining the TCP protocol number at runtime from the system’s protocol database rather than a Socket constant:

use Socket qw(TCP_NODELAY);

defined(my $tcp = getprotobyname("tcp"))
    or die "no protocol entry for tcp";
my $packed = getsockopt($sock, $tcp, TCP_NODELAY)
    or die "getsockopt: $!";

Read SO_ERROR to drain and clear a pending asynchronous error on a non-blocking socket after connect or after select flags it writable:

use Socket qw(SOL_SOCKET SO_ERROR);

my $packed = getsockopt($sock, SOL_SOCKET, SO_ERROR)
    or die "getsockopt SO_ERROR: $!";
my $err = unpack("i", $packed);
if ($err) {
    $! = $err;
    die "asynchronous socket error: $!";
}

Read the socket type (SOCK_STREAM, SOCK_DGRAM, …) of an already opened handle:

use Socket qw(SOL_SOCKET SO_TYPE SOCK_STREAM);

my $packed = getsockopt($sock, SOL_SOCKET, SO_TYPE)
    or die "getsockopt SO_TYPE: $!";
my $type = unpack("i", $packed);
print "stream socket\n" if $type == SOCK_STREAM;

Read a struct timeval option. SO_RCVTIMEO returns two native longs — seconds and microseconds:

use Socket qw(SOL_SOCKET SO_RCVTIMEO);

my $packed = getsockopt($sock, SOL_SOCKET, SO_RCVTIMEO)
    or die "getsockopt SO_RCVTIMEO: $!";
my ($sec, $usec) = unpack("l!l!", $packed);
printf "receive timeout: %d.%06d s\n", $sec, $usec;

Edge cases#

  • SOCKET is not an open socket: the call fails, returns undef, and sets $! to ENOTSOCK ("Socket operation on non-socket") or EBADF ("Bad file descriptor") for a closed handle.

  • Unknown LEVEL / OPTNAME: the kernel rejects the request with ENOPROTOOPT ("Protocol not available"). There is no way to tell this apart from the success case except by checking the return value.

  • Truthy-return idiom: the common getsockopt(...) or die works because a successful call returns a non-empty packed string. A zero-length reply would make the idiom misfire, but no kernel option returns a zero-length buffer in practice — every defined option has at least one byte of payload.

  • Integer decode width: use "i" or "I" for int-sized options (SO_KEEPALIVE, TCP_NODELAY, SO_ERROR, …); use "l!" or "L!" only when the option’s documented layout genuinely uses a native long. Getting the width wrong silently returns the wrong number on LP64 platforms.

  • Do not hand-pack the reply: getsockopt returns whatever the kernel wrote, including any padding. Re-pack only on round-trips via setsockopt, and then pass the buffer back verbatim rather than reconstructing it.

  • No constants without Socket: SOL_SOCKET, IPPROTO_TCP, TCP_NODELAY, SO_ERROR, and friends are not built-in names. Import them from Socket with use Socket qw(...) or use Socket qw(:all).

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • setsockopt — the write half; sets the option whose value getsockopt reads back

  • Socket — source of the SOL_*, IPPROTO_*, SO_*, TCP_*, IP_* constants you pass as LEVEL and OPTNAME

  • unpack — required to decode the packed byte string the kernel hands back

  • getprotobyname — run-time way to obtain the LEVEL protocol number when you do not want to pull in the IPPROTO_* constants from Socket

  • getsockname — sibling introspection call; returns the local address bound to SOCKET rather than a single option

  • socket — creates the socket that getsockopt then queries