Sockets

getpeername#

Return the address of the remote end of a connected socket.

getpeername asks the kernel who is on the other side of SOCKET and returns the answer as a packed sockaddr byte string — the same shape connect took and the same shape accept returned. You then hand that byte string to an unpacker from Socket (or Socket::unpack_sockaddr_in, Socket::unpack_sockaddr_in6, Socket::unpack_sockaddr_un) to pull out the port, address, or path.

This is the companion to getsockname, which returns the local end of the same socket.

Synopsis#

use Socket;
my $peer = getpeername SOCKET;
my ($port, $iaddr) = unpack_sockaddr_in($peer);

What you get back#

A packed sockaddr byte string on success, undef on failure (with $! set — typically ENOTCONN when the socket has no peer, or EBADF when SOCKET is not an open file descriptor).

The byte string is opaque. Its layout depends on the socket’s address family; always decode it with an unpacker that matches the family you expect:

If you do not know the family at the call site, ask Socket::sockaddr_family first:

my $peer   = getpeername $sock;
my $family = sockaddr_family($peer);

Global state it touches#

getpeername reads the file-descriptor state of SOCKET. It sets $! on failure and does not otherwise touch interpreter globals. It does not interact with $_, the selected filehandle, or output separators.

Examples#

Look up the remote IPv4 peer of a client-side TCP socket and render it in dotted-quad form:

use Socket;
my $peer = getpeername($sock)
    or die "getpeername: $!";
my ($port, $iaddr) = unpack_sockaddr_in($peer);
printf "peer is %s:%d\n", inet_ntoa($iaddr), $port;

Server side: every socket returned by accept is already connected, and accept itself hands back the peer address. getpeername is useful later, when that packed address has not been kept around:

while (my $client = accept(my $conn, $listen)) {
    handle($conn);
}

sub handle {
    my ($conn) = @_;
    my $peer = getpeername($conn) or return;
    my ($port, $iaddr) = unpack_sockaddr_in($peer);
    warn "request from ", inet_ntoa($iaddr), ":$port\n";
    # ...
}

Resolve the peer back to a hostname — note that this issues a blocking DNS lookup:

use Socket;
my $peer = getpeername($sock);
my ($port, $iaddr) = unpack_sockaddr_in($peer);
my $name = gethostbyaddr($iaddr, AF_INET);
print "connected to ", $name // inet_ntoa($iaddr), "\n";

Mixed IPv4 / IPv6 code — decode generically via the address family:

use Socket qw(sockaddr_family unpack_sockaddr_in unpack_sockaddr_in6
              AF_INET AF_INET6 inet_ntop);

my $peer = getpeername($sock) or die "getpeername: $!";
my $fam  = sockaddr_family($peer);

if ($fam == AF_INET) {
    my ($port, $iaddr) = unpack_sockaddr_in($peer);
    printf "v4 %s:%d\n", inet_ntop(AF_INET, $iaddr), $port;
}
elsif ($fam == AF_INET6) {
    my ($port, $iaddr) = unpack_sockaddr_in6($peer);
    printf "v6 [%s]:%d\n", inet_ntop(AF_INET6, $iaddr), $port;
}

Probing whether a socket is connected at all — the ENOTCONN path is the well-defined way to ask:

if (defined getpeername($sock)) {
    # connected
} else {
    # $! == ENOTCONN for an unconnected socket
}

Edge cases#

  • Unconnected socket: a socket that has been socket’d but not yet connect’d or accept’d has no peer. getpeername returns undef and sets $! to ENOTCONN.

  • Non-socket filehandle: passing a plain file or pipe yields undef with $! set to ENOTSOCK.

  • Closed or invalid filehandle: returns undef with $! set to EBADF. Under use warnings a getpeername() on closed socket warning is emitted.

  • Datagram sockets: getpeername only returns an address when the SOCK_DGRAM socket has been connect’d to a default peer; otherwise it fails with ENOTCONN even though the socket is usable via recv / send.

  • AF_UNIX with an unbound peer: a Unix-domain socket whose peer never called bind returns a packed sockaddr_un with an empty path. Socket::unpack_sockaddr_un gives back the empty string.

  • After shutdown: getpeername still succeeds as long as the descriptor is open; shutdown tears down data flow, not the kernel’s record of the peer.

  • SOCKET is a parsed filehandle token: like other socket built-ins, the argument is parsed as a filehandle, not evaluated as a general expression. getpeername $handles[0] is a syntax error; use a scalar holding the handle, or *{...} dereferencing.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • getsockname — mirror call that returns the local end of the same socket; pairs with getpeername when logging both ends of a connection

  • accept — already hands you the peer address for a freshly accepted server-side socket; use getpeername later when that address was not retained

  • connect — the call that establishes the peer in the first place; the address you pass to connect is what getpeername will hand back afterwards

  • Socket — provides the unpackers (unpack_sockaddr_in, unpack_sockaddr_in6, unpack_sockaddr_un) and sockaddr_family needed to interpret the returned byte string

  • gethostbyaddr — turns the packed IPv4 address from the unpacker into a hostname

  • $! — carries the reason on failure (ENOTCONN, ENOTSOCK, EBADF)