Network info

getprotoent#

Fetch the next entry from the protocols database.

getprotoent walks the system protocols database — on traditional Unix-likes that’s /etc/protocols, on modern systems whatever the C library and NSS stack map to it — returning one record per call until the database is exhausted. It is the iterating leg of the setprotoent / getprotoent / endprotoent triad. Reach for getprotobyname or getprotobynumber when you want a single targeted lookup; getprotoent is for enumerating every protocol known to the system.

The iteration cursor is shared process-wide and owned by the C library. setprotoent rewinds it and optionally pins the backing descriptor open; endprotoent closes it. Between those two calls getprotoent yields each record in order, then returns the empty list (or undef in scalar context) once there is nothing left.

Synopsis#

my ($name, $aliases, $proto) = getprotoent;
my $name = getprotoent;

What you get back#

List context — a three-element list mirroring the C struct protoent:

  • $name — the canonical protocol name, e.g. "tcp", "udp", "icmp".

  • $aliases — a space-separated string of alternate names for the same protocol. Often empty.

  • $proto — the numeric protocol number as used in IP headers and accepted by socket / getsockopt.

At end-of-database the return is the empty list. The upstream perlfunc note about “a single meaningless true value” for missing entries applies to the by-name and by-number lookups, not to getprotoent — running off the end of the iteration is a clean empty list.

Scalar context — the canonical $name only, or undef at end-of-database. Use list context whenever you need the number or the aliases; you cannot reconstruct them from the name after the fact.

Split the aliases into a list with a plain split:

my @alts = split ' ', $aliases;

Global state it touches#

  • The protocols database cursor, a per-process C-library-owned resource shared with setprotoent, endprotoent, getprotobyname, and getprotobynumber. A by-name or by-number lookup may reset the cursor mid-iteration on some platforms — see Edge cases.

  • No Perl-level special variables are read or written. Unlike gethostent, the protocols routines have no h_errno equivalent, so $? is not touched. End of database is not a failure and does not set $!.

Examples#

Enumerate every protocol the system knows about:

setprotoent(1);
while (my ($name, $aliases, $proto) = getprotoent) {
    print "$proto\t$name\t$aliases\n";
}
endprotoent;

Scalar context — list just the canonical names:

setprotoent(0);
while (defined(my $name = getprotoent)) {
    print "$name\n";
}
endprotoent;

Build a name-to-number map in one pass so later lookups don’t hit the database at all:

my %proto_num;
setprotoent(1);
while (my ($name, $aliases, $num) = getprotoent) {
    $proto_num{$name} = $num;
    $proto_num{$_}    = $num for split ' ', $aliases;
}
endprotoent;

print $proto_num{"tcp"}, "\n";          # 6

By-record interface via the Net::protoent override — accessor methods instead of positional unpacking:

use Net::protoent;
while (my $p = getprotoent) {
    printf "%-10s %3d\n", $p->name, $p->proto;
}

Edge cases#

  • No implicit rewind. getprotoent does not open or rewind the database on its own. The first call after program start works because the C library lazily opens the file, but once the end is reached further calls keep returning end-of-database until a setprotoent rewinds the cursor. Always bracket enumeration with an explicit setprotoent and endprotoent.

  • End-of-database is the empty list, not undef. In list context the loop condition while (my @r = getprotoent) works because the empty list is false. In scalar context use while (defined(my $name = getprotoent)) — a protocol name of "0" is theoretically valid and would falsely terminate a truthiness-based loop.

  • Aliases are one scalar, not a list. $aliases is a single space-separated string; split on whitespace if you want a list. An empty aliases field is the common case, not an error.

  • Interleaving with by-name / by-number lookups. A call to getprotobyname or getprotobynumber during a walk can reset the shared cursor on some platforms. Finish the iteration first, or restart it with setprotoent after the lookup.

  • Not reentrant. The database cursor is a single global resource inside the C library. Two concurrent iterations in the same process — across threads, signal handlers, or nested callbacks — corrupt each other’s state. Confine each walk to one thread at a time.

  • Platforms without a protocols database. On systems with no /etc/protocols equivalent, the call is a no-op that returns the empty list immediately rather than raising an error. See perlport for the full list of network-database quirks.

  • Tainting. Records come from a file the kernel reads on your behalf and are not marked tainted. Treat them as untrusted anyway when the file is user-writable.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • setprotoent — rewind the iterator and optionally pin the backing descriptor open for the full walk

  • endprotoent — close the iterator and release the database handle once enumeration is done

  • getprotobyname — targeted lookup by protocol name instead of full enumeration

  • getprotobynumber — targeted lookup by numeric protocol number

  • getservent — same iteration pattern for the services database, which references protocol names from this one

  • gethostent — same idiom for the hosts database