How to find local/epheremal port number?

1.2k views Asked by At

I have a UDP client program that uses Berkley sockets and Winsock (depending on the platform).

Basically it uses getaddrinfo(), then socket(), then sendto(). sendto() takes the address info returned by getaddrinfo(). My code looks like this:

struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_socktype = SOCK_DGRAM;
struct addrinfo *address;
getaddrinfo("127.0.0.1", "9999", &hint, &address);

SOCKET s = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
sendto(s, "test", 4, 0, address->ai_addr, address->ai_addrlen);

My question is, when is the local/ephemeral port number set? Is it set with the call to sendto()? If I send more data to a different server, does sendto() reuse the same ephemeral port number? How can I get the ephemeral port number (in a protocol independent way)? I know that knowing this may not be useful, and NAT can change it anyway, but I'm just trying to understand how it all works better.

I also know I can use bind() to set the local port, but my question is about what happens when the OS chooses the local port for me.

3

There are 3 answers

3
dbush On

You want the getsockname function:

struct sockaddr_storage ss;
socklen_t len;

len = sizeof(ss);
if (getsockname(s, (struct sockaddr *)&ss, &len) == 0) {
    // print contents of ss
}

It populates the given sockaddr with the address and port that the socket is bound to.

This function is available in both winsock and Berkely sockets.

0
Remy Lebeau On

MSDN's documentation for sendto() states:

Note If a socket is opened, a setsockopt call is made, and then a sendto call is made, Windows Sockets performs an implicit bind function call.

If the socket is unbound, unique values are assigned to the local association by the system, and the socket is then marked as bound. If the socket is connected, the getsockname function can be used to determine the local IP address and port associated with the socket.

If the socket is not connected, the getsockname function can be used to determine the local port number associated with the socket but the IP address returned is set to the wildcard address for the given protocol (for example, INADDR_ANY or "0.0.0.0" for IPv4 and IN6ADDR_ANY_INIT or "::" for IPv6).

0
Antti Haapala -- Слава Україні On

You can bind to port zero (0) which will cause OS to find an open ephemeral port that you can discover with getsockname, or return EADDRINUSE, even before you tried to send anything.


As for when an ephemeral port is allocated by the operating system, from ip(7) Linux manual page:

[...] An ephemeral port is allocated to a socket in the following circumstances:

  • the port number in a socket address is specified as 0 when calling bind(2);

  • listen(2) is called on a stream socket that was not previously bound;

  • connect(2) was called on a socket that was not previously bound;

  • sendto(2) is called on a datagram socket that was not previously bound.