When will a connected UDP socket be closed by the OS? - c++

I have a UDP file descriptor in a C++ program running under Linux. I call connect() on it to connect it to a remote address and then read and write from that socket.
According to UNIX Network Programming, "Asynchronous errors are returned to the process for connected UDP sockets." I'm guessing that these asynchronous errors will cause the UDP socket to be closed by the OS, but the book isn't that clear. It also isn't clear what types of asynchronous errors are possible, though it's suggested that if the port on the remote machine is not open, the socket will be closed.
So my question is: Under what conditions will Linux close the UDP file descriptor?
Bad port number?
Bad IP address?
Any others?

connect() on an UDP socket just records the port number and IP address you pass in, so it'll only accept packets from that IP/port, and you can use the socket fd to send/write data without specifying the remote address for each send/write call.
Regarding this, async errors means if you send() something, and that send call results in an error occuring later (e.g. when the TCP/IP stack actually sends the packet, or an ICMP packet is later returned), a subsequent send will return that error. Such async errors are only returned on a "connected" UDP socket. (The linux udp(7) manpage suggest errors are returned whether the socket is connected or not, but testing shows this is not the cases at least when a sent UDP packet generates an ICMP error. It might be that send() errors are returned if you recv() on that socket, instead of subsequent send() calls produce an error )
The socket is not closed though, you'll have to close it yourself either by calling close() or exiting the program. e.g. if you connect() your UDP socket, and send to a port noone is listening to, an ICMP packet is normally returned and a subsequent send() call will fail with errno set to ECONNREFUSED. You can continue sending on that socket though, it doesn't get closed by the OS, and if someone starts listening on the port in the mean time the packets will get through.

UDP sockets are connectionless, so there is no real sense of "openness" state attached to them - this is unlike TCP sockets where a socket may be in any number of connection states as determined by the exchange of packets up to a given point.
The only sense in which UDP sockets can be opened and closed is in the sense that they are system level objects with some internal state and a file descriptor. Sockets are never automatically closed in the event of an error and will remain open indefinitely, unless their owning process terminates or calls close on them.
To address your other concern, if the destination port on the destination host is not opened, the sender of a UDP packet will never know.** UDP provides no means of receiver acknowledgement. The packet is routed and, if it arrives at the host, checked for correctness and either successfully received or discarded. There are a number of reasons why send might return an error code when writing to a UDP socket, but none of them have to do with the state of the receiving host.** I recommend consulting the sendto manpage for possible failure modes.
On the other hand, in the case of a TCP socket attempting to connect to an unopened port, the sender will never receive an acknowledgement of its initial connection request, and ultimately connect will fail. At this point it would be up to the sender to stop sending data over the socket (as this will only generate more errors), but even in this case however, the socket file descriptor is never automatically closed.
** See response by #Zuljin in the comments.

The OS won't close your socket just because an error has happened. If the other end disappears, you can continue to send messages to it (but may receive further errors).

Related

Socket recv() function

In c++, in windows OS, on the recv() call for TCP socket , if the socket connection is closed somehow, the recv() will return immediately or will it hang?
What would be result(immediately returns or hangs) in the blocking and non blocking socket?
I am using socket version 2.
Thanks in advance.
As documented depending of how the connection was closed it should more or less immediately with a return value of SOCKET_ERROR in a non graceful case and set WSAGetLastError to one of the possible reasons like WSAENOTCONN or would just return 0 in the graceful connection close scenario. This would be the same between blocking and nonblocking sockets.
If the socket is connection oriented and the remote side has shut down the connection gracefully, and all data has been received, a recv will complete immediately with zero bytes received. If the connection has been reset, a recv will fail with the error WSAECONNRESET.
However, since I know the Windows API does not always work as documented, I recommend to test it.
If your recv() is based on BSD - as almost all are - it will return immediately if the connection is closed (per the local side's status), regardless of whether the socket is blocking or non-blocking.
recv() will return 0 upon a graceful disconnect, ie the peer shutdown its end of the connection and its socket stack sent a FIN packet to your socket stack. You are pretty much guaranteed to get this result immediately, whether you use a blocking or non-blocking socket.
recv() will return -1 on any other error, including an abnormal connection loss.
You need to use WSAGetLastError() to find out what actually happened. For a lost connection on a blocking socket, you will usually get an error code such as WSAECONNRESET or WSAECONNABORTED. For a lost connection on a non-blocking socket, it is possible that recv() may report an WSAEWOULDBLOCK error immediately and then report the actual error at some later time, maybe via select() with an exception fd_set, or an asynchronous notification, depending on how you implement your non-blocking logic.
However, either way, you are NOT guaranteed to get a failure result on a lost connection in any timely manner! It MAY take some time (seconds, minutes, can even be hours in rare cases) before the OS deems the connection is actually lost and invalidates the socket connection. TCP is designed to recover lost connections when possible, so it has to account for temporary network outages and such, so there are internal timeouts. You don't see that in your code, it happens in the background.
If you don't want to wait for the OS to timeout internally, you can always use your own timeout in your code, such as via select(), setsocktopt(SO_RCVTIMEO), TCP keep-alives (setsockopt(SO_KEEPALIVE) or WSAIoCtl(SIO_KEEPALIVE_VALS)), etc. You may still not get a failure immediately, but you will get it sooner rather than later.

select() for UDP connection

Can someone explain to me why we use the select() function before recvfrom() (on the server side) instead of before sendto() (on the client side) when waiting for a timeout? It seems to me that the timeout should be on the sender's side.
//EX
CLIENT SERVER
------ ------
select() /* start timeout */
sendto() /* --send packet--> */ recvfrom()
recvfrom() /* <--send ACK-- */ sendto()
And as long as the ACK has been received before the timeout is reached, the sender could send another file.
You do not normally use select with UDP at all, except you want one of the following:
receive from several ports (or one port and an unix socket, etc.) with a single thread
detect other events as soon as they happen, without waiting for an unrelated recvfrom or sendto to unblock
sleep in a maximally portable way
you want to use the Linux-specific recvmmsg (but then, you really want to use epoll_wait) to receive a whole bunch of datagrams with one syscall
select is regularly used with TCP as it is able to multiplex between several sockets, one for every connected client. This is not necessary with UDP, since one socket is sufficient to recieve packets from each and every client (assuming they use the same port).
select blocks until the condition you wait for (e.g. ready to receive or ready to send) is true. recvfrom blocks anyway if there is nothing to receive, so if this is the only thing you're intersted in, calling select is useless.
UDP doesn't have built-in acknowledgements. So sendto() simply sends the packet to the network and returns immediately, it doesn't have any built-in way of waiting for a response or acknowledgement. Your application knows that it expects the server to send a response, so it waits for a response with recvfrom().

Send buffer empty of Socket in Linux?

Is there a way to check if the send buffer of an TCP Connection is completely empty?
I haven't found anything until now and just want to make sure a connection is not closed by my server while there are still data being transmitted to a certain client.
I'm using poll to check if I'm able to send data on a non-blocking socket. But by that I'm not able to find out if EVERYTHING has been sent in buffer, am I?
In Linux, you can query a socket's send queue with ioctl(sd, SIOCOUTQ, &bytes). See man ioctl for details.
The information is not completely reliable in the sense that it is possible that the data has been received by the remote host, since the buffer cannot be emptied until an ACK is received. You probably should not use it to add another level of flow-control on top of TCP.
If the remote host actually closes the connection (or half-closes it), then the socket become unwriteable, regardless of how much data might have been in the buffer. You can detect this condition by writing 0 bytes to the socket.
The more difficult (and often more likely) condition is the remote host becoming unreachable, because of network issues or because it crashes. In that case, data will pile up in the send buffer, but that can also happen because the remote host's receive buffer is full (perhaps because the process reading the buffer doesn't have enough resources to process its input). In the case of network routing issues, you might get a router notification (an ICMP error), which should make the socket unwritable; unfortunately, there are many network errors which just result in black holes.

c++ detect if the client closed the connection (multi sockets)

In my program I have several sockets on the server. Each socket has its own port. I tried to detect if the client closed the connection with:
signal(SIGPIPE, sig_pipe);
But I have the problem that I don't know on which socket the connection was closed.
Is there some method to get it to know?
More about code:
In main program I started 3 Sockets on different ports. Accept, receive and send for each socket I put in one thread. So I have 3 threads at the end.
Thank you.
You should setup SIGPIPE to be ignored (see sigaction(2)) and handle EPIPE error code from write(2) and the likes.
Note, that reading zero bytes from TCP socket is the real indication of the other side closing the connection.

How to UDP send and receive on same port?

I need to be able to send and receive UDP packets on the same port.
I am able to listen, on say port 5000, but my send uses a random high port.
The system I am working written in VB with does this and my need is to write a UDP responder for debugging various protocol issues.
I am using the Open Source C++ Sockets Library from http://www.alhem.net (Anders Hedstrom) and have been able to use the UdpSocket::Bind() to receive incoming UDP packets using the virtual function UdpSocket::OnRawData(), but have been unable to cause the UdpSocket::Open() (calls connect) to make the UdpSocket::Send() use the port chosen in Bind() (it uses random high number port instead).
Moving the Open() function doesn't help. I have posted a request on their forum - but believe from what I have read that it should be possible to do this, and I'm probably not understanding how to use UDP.
Does anyone have any ideas on what I should try?
--thanks--
System consists of a number of nodes
listening on same port (different ip
addr's). System [A] sends datagram to
System [B]. System [B] asynchronously
responds and send datagram(s) back to
[A] all using same port. Even if [B]
identifies [A]'s port, [A] is not
listening on that port
I'm not sure I understand the "all using the same port" phrase in that sentence. If A sends a datagram to B, B will know A's IP and port right away (a quick check of your library documentation reveals OnRawData has a struct sockaddr *sa parameter, if you cast it to sockaddr_in* you'll be able to extract the IP:port pair). You can use that IP:port to send datagrams to and A will receive them. A is not "listening" on that port in the sense that it haven't called listen() on the socket, but since A owns a socket that is bound to that port (whether explicitly by calling bind() or assigned random port by the OS) it will receive the data.
Now if you want ALL your communication between nodes to go through your fixed port, you can do that. You just have to send all your datagrams through your "listening" socket. If every node "listens" on the same port, it means every node owns a socket that is bound to that port. If you want datagrams sent from A to B to appear coming from this fixed port you have to send them through that socket. I'm guessing that's why bind() doesn't work for your sending socket - A has a socket bound to port X, then you create another socket and try to bind it to the same port X, bind() fails since the port is already taken (and you don't check for errors :), and then the OS assigns random free port above 1024.
Note 1: I use "listening" in quotes everywhere, because the concept is not very clear in the context of UDP sockets. Once you have created socket and bound it to a port, either by calling bind() explicitly or by sending data and letting the OS bind it to a port, you can receive data from everywhere through it. No listen() or accept() calls needed.
Note 2: You say that UdpSocket::Open() calls connect(), but that doesn't make much sense - connect() does very little for UDP sockets - it merely establishes a default address so you can use send() instead of sendto() and not specify address on every send.
Hope that clears things up.
Edit to address OP's comment: I've never used this library but according their UdpSocket documentation there are 4 overloads of the Bind() method and every single one of them accepts port in some way. None of them works for you?
A bidirectional communication link always involves two participants: a server-side and a client-side.
The client expects to communicate to a server on a defined port: that's why on the server-side one must bind() to a socket.
On the client-side, one must open a socket to the server: it doesn't really matter which socket is chosen (except for the need for it to be free).
In other words, don't try to specify a socket on the client-side: the network protocol stack will assign it to your client.