How to find local/epheremal port number? - c

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.

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.

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).

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.

Related

Raw sockets receiving messages sent by itself

I was trying to write some codes using raw sockets, while I observed some strange phenomenon. Consider the code:
int rsfd = socket(AF_INET,SOCK_RAW,253);
if(rsfd<0)
{
perror("Raw socket not created");
}
else
{
struct sockaddr_in addr2;
memset(&addr2,0,sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = inet_addr("127.0.0.2");
/* if(connect(rsfd,(struct sockaddr*)&addr2,sizeof(addr2))<0)
{
perror("Could not connect");continue;
} */
}
Now if I remove the commented portion, whatever message I am sending through this rsfd is also being received by itself. On the other end I have already bound a socket with the ip address 127.0.0.2. When I printed the ip address of the sender socket, it is printing 127.0.0.1 but still it is receiving packets which is meant for 127.0.0.2. This problem was solved when I added that connect request which is mentioned in the commented portion. This seems weird because on the other side, no one is accepting or listen on this address and moreover, I am using sendto and recvfrom functions for sending and receiving packets which is used for connection less sockets. My question is, why is this happening? How is this connect request solvong the problem here?
Now if I [don't connect() the socket], whatever message I am sending through this rsfd is also being received by itself.
I note first that raw sockets are an extension to POSIX. Linux offers them, and I think other systems do too, but details of their behavior are not certain to be consistent across implementations.
With that said, the problem seems likely to be that you are not bind()ing your socket to any address. On Linux, for example, the docs for raw sockets note that
A raw socket can be bound to a specific local address using the
bind(2) call. If it isn't bound, all packets with the specified IP
protocol are received.
(Emphasis added.) On a system where raw sockets have that behavior, if you're sending packets to an IP loopback address via a raw IP socket that is neither bound nor connected then yes, the source socket will receive them, or at least may do.
It's unclear why connecting the socket solves the problem, or why it is even successful at all. The behavior of connect() is unspecified for socket types other than the standard ones, SOCK_DGRAM, SOCK_STREAM, and SOCK_SEQPACKET. However, the behavior you observe is consistent with connect() having an effect on raw sockets like that it has on datagram sockets, which are also connectionless:
If the socket sockfd is of type SOCK_DGRAM, then addr is the address
to which datagrams are sent by default, and the only address from
which datagrams are received.
Instead of relying on that discovered behavior, however, I suggest following the documented (at least on Linux) procedure of binding the socket to an address (including a port), and communicating with it at that address.

recvfrom with Raw Sockets, get just the data

I'm trying to implement my own transport layer protocol, but I'm perfectly happy to leave the network layer as-is and not need to mess with the actual IP header information.
But of course, when calling recvfrom() on a raw socket, you are given the raw IP datagram, while the sockaddr struct is not filled in.
Is there anyway to coax the stack to fill in those structs and leave the ip header out of the data portion, or does that need to be implemented by hand?
Receiver:
struct sockaddr_in sender;
int sender_len;
raw_socket = socket(AF_INET, SOCK_RAW, 56);
...
if((n = recvfrom(raw_socket, buf, 1024, 0, (struct sockaddr*)&sender, &sender_len)) == -1){
perror("recvfrom");
return -1;
}
The IP header will always be included when receiving on a SOCK_RAW socket.
Per raw(7):
The IPv4 layer generates an IP header when sending a packet unless the IP_HDRINCL socket option is enabled on the socket. When it is enabled, the packet must contain an IP header. For receiving the IP header is always included in the packet.
Reference:
ip(7) man page
SOCK_RAW Demystified
Advanced TCP/IP - THE RAW SOCKET PROGRAM EXAMPLES
Use recvmsg() with the msg[] buffers initialized so that the first one receives the IP header, then the second one will only contain data.

Socket bind with wildcard ip

I have a created a UDP socket and bind that socket to inaddr_any (0.0.0.0) and and some
well known port number. As per my understanding this socket can receive data over all the interfaces of the machine over the specified port number.
But When i will call send() it will use the default IP address as the source address.
How is the default IP address chosen?
If I want to use some other interface (other than the default) for sending the data, how can this be done?
Context of the problem:
I am implementing LDP protocol. It can have many hello adjacencies. Thus i am creating a server to recv data from the other interfaces of the router. Once the hello adjacency is formed, then hello messages are to sent be on the specific interface over UDP over which the hello adjacency is created.
The default IP address is chosen based on the network the packet is sent to. For example if you have two interfaces, one connected to network A and the other connected to network B, if you send a packet to network B the packet will be sent with the IP address of the second interface. For this reason, most of the time you don't have to worry about it.
If you have two network interfaces connected to the same network, you can bind the socket to the address of one of them, and the packet will go out with that address. For example, this will bind an IP socket to 192.168.122.1, if allowed by the network stack:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.122.1");
addr.sin_port = 0;
if (bind(s, (struct sockaddr*) &addr, sizeof addr) == -1) {
perror("bind");
}

When the client socket should be bound in order to receive UDP messages from a server?

I have seen two examples that illustrate how the client socket can receive messages from server.
Example 1:
server code
http://man7.org/tlpi/code/online/book/sockets/ud_ucase_sv.c.html
client code
http://man7.org/tlpi/code/online/book/sockets/ud_ucase_cl.c.html
The client program creates a socket and binds the socket to an address, so that the server can send its reply.
if (bind(sfd, (struct sockaddr *) &claddr, sizeof(struct sockaddr_un)) == -1)
errExit("bind"); // snippet from ud_ucase_cl.c
Example 2:
server code
http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_sv.c.html
client code
http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_cl.c.html
In example 2, client code doesn't bind its socket with an address.
Question:
Is it necessary for the client code to bind the socket with an address in order to receive message from server?
Why in the first example, we have to bind the client socket with an address, why we don't have to in the second example?
The difference is the socket family - first example uses AF_UNIX, while the second does AF_INET6. According to Stevens UNP you need to explicitly bind pathname to Unix client socket so that the server has a pathname to which it can send its reply:
... sending a datagram to an unbound Unix domain datagram socket does not implicitly bind a pathname to the socket. Therefore, if we omit this step, the server's call to recvfrom ... returns a null pathname ...
This is not required for INET{4,6} sockets since they are "auto-bound" to an ephemeral port.
For the client (TCP) or sender (UDP), calling bind() is optional; it is a way to specify the interface. Suppose you have two interfaces, which are both routable to your destination:
eth0: 10.1.1.100/24
eth1: 10.2.2.100/24
route: 10.1.1.0/24 via 10.2.2.254 # router for eth1
0.0.0.0 via 10.1.1.254 # general router
Now if you just say connect() to 12.34.56.78, you don't know which local interface furnishes the local side of the connection. By calling bind() first, you make this specific.
The same is true for UDP traffic: Without bind()ing, your sendto() will use a random source address and port, but with bind() you make the source specific.
If you have not bound AF_INET/AF_INET6 client socket before connecting/sending something, TCP/IP stack will automatically bind it to ephemeral port on outbound address.
Unlike this, UNIX domain sockets (AF_UNIX) do not automatically bind when sending, so you can send messages via SOCK_DGRAM but can't get any replies.

Unix Domain Socket: Using datagram communication between one server process and several client processes

I would like to establish an IPC connection between several processes on Linux. I have never used UNIX sockets before, and thus I don't know if this is the correct approach to this problem.
One process receives data (unformated, binary) and shall distribute this data via a local AF_UNIX socket using the datagram protocol (i.e. similar to UDP with AF_INET). The data sent from this process to a local Unix socket shall be received by multiple clients listening on the same socket. The number of receivers may vary.
To achieve this the following code is used to create a socket and send data to it (the server process):
struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());
int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
// buf contains the data, buflen contains the number of bytes
int bytes = write(socket, buf, buflen);
...
close(socket);
unlink(ipcFile.sun_path);
This write returns -1 with errno reporting ENOTCONN ("Transport endpoint is not connected"). I guess this is because no receiving process is currently listening to this local socket, correct?
Then, I tried to create a client who connects to this socket.
struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());
int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
char buf[1024];
int bytes = read(socket, buf, sizeof(buf));
...
close(socket);
Here, the bind fails ("Address already in use"). So, do I need to set some socket options, or is this generally the wrong approach?
Thanks in advance for any comments / solutions!
There's a trick to using Unix Domain Socket with datagram configuration. Unlike stream sockets (tcp or unix domain socket), datagram sockets need endpoints defined for both the server AND the client. When one establishes a connection in stream sockets, an endpoint for the client is implicitly created by the operating system. Whether this corresponds to an ephemeral TCP/UDP port, or a temporary inode for the unix domain, the endpoint for the client is created for you. Thats why you don't normally need to issue a call to bind() for stream sockets in the client.
The reason you're seeing "Address already in use" is because you're telling the client to bind to the same address as the server. bind() is about asserting external identity. Two sockets can't normally have the same name.
With datagram sockets, specifically unix domain datagram sockets, the client has to bind() to its own endpoint, then connect() to the server's endpoint. Here is your client code, slightly modified, with some other goodies thrown in:
char * server_filename = "/tmp/socket-server";
char * client_filename = "/tmp/socket-client";
struct sockaddr_un server_addr;
struct sockaddr_un client_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, server_filename, 104); // XXX: should be limited to about 104 characters, system dependent
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sun_family = AF_UNIX;
strncpy(client_addr.sun_path, client_filename, 104);
// get socket
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
// bind client to client_filename
bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr));
// connect client to server_filename
connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
...
char buf[1024];
int bytes = read(sockfd, buf, sizeof(buf));
...
close(sockfd);
At this point your socket should be fully setup. I think theoretically you can use read()/write(), but usually I'd use send()/recv() for datagram sockets.
Normally you'll want to check error after each of these calls and issue a perror() afterwards. It will greatly aid you when things go wrong. In general, use a pattern like this:
if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
}
This goes for pretty much any C system calls.
The best reference for this is Steven's "Unix Network Programming". In the 3rd edition, section 15.4, pages 415-419 show some examples and lists many of the caveats.
By the way, in reference to
I guess this is because no receiving process is currently listening to this local socket, correct?
I think you're right about the ENOTCONN error from write() in the server. A UDP socket would normally not complain because it has no facility to know if the client process is listening. However, unix domain datagram sockets are different. In fact, the write() will actually block if the client's receive buffer is full rather than drop the packet. This makes unix domain datagram sockets much superior to UDP for IPC because UDP will most certainly drop packets when under load, even on localhost. On the other hand, it means you have to be careful with fast writers and slow readers.
The proximate cause of your error is that write() doesn't know where you want to send the data to. bind() sets the name of your side of the socket - ie. where the data is coming from. To set the destination side of the socket, you can either use connect(); or you can use sendto() instead of write().
The other error ("Address already in use") is because only one process can bind() to an address.
You will need to change your approach to take this into account. Your server will need to listen on a well-known address, set with bind(). Your clients will need to send a message to the server at this address to register their interest in receiving datagrams. The server will recieve the registration messages from clients using recvfrom(), and record the address used by each client. When it wants to send a message, it will have to loop over all the clients it knows about, using sendto() to send the message to each one in turn.
Alternatively, you could use local IP multicast instead of UNIX domain sockets (UNIX domain sockets don't support multicast).
If the question intended to be about broadcasting (as I understand it), then according to unix(4) - UNIX-domain protocol family, broadcasting it is not available with UNIX Domain Sockets:
The Unix Ns -domain protocol family does not support
broadcast addressing or any form of "wildcard" matching
on incoming messages. All addresses are absolute- or
relative-pathnames of other Unix Ns -domain sockets.
May be multicast could be an option, but I feel to know it's not available with POSIX, although Linux supports UNIX Domain Socket multicast.
Also see: Introducing multicast Unix sockets.
It will happen because of
server or client die before unlink/remove for bind() file associate.
any of client/server using this bind path, try to run server again.
solutions :
when you want to bind again just check that file is already associate then unlink that file.
How to step :
first check access of this file by access(2);
if yes then unlink(2) it.
put this peace of code before bind() call,position is independent.
if(!access(filename.c_str()))
unlink(filename.c_str());
for more reference read unix(7)
Wouldn't it be easier to use shared memory or named pipes? A socket is a connection between two processes (on the same or a different machine). It isn't a mass communication method.
If you want to give something to multiple clients, you create a server that waits for connections and then all the clients can connect and it gives them the information. You can accept concurrent connections by making the program multi-threaded or by forking processes. The server establishes multiple socket-based connections with multiple clients, rather than having one socket that multiple clients connect to.
You should look into IP multicasting instead of Unix-domain anything. At present you are just trying to write to nowhere. And if you connect to one client you will only be writing to that client.
This stuff doesn't work the way you seem to think it does.
You can solve the bind error with the following code:
int use = yesno;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&use, sizeof(int));
With UDP protocol, you must invoke connect() if you want to use write() or send(), otherwise you should use sendto() instead.
To achieve your requirements, the following pseudo code may be of help:
sockfd = socket(AF_INET, SOCK_DGRAM, 0)
set RESUSEADDR with setsockopt
bind()
while (1) {
recvfrom()
sendto()
}

Resources