Calling connect() multiple times on UDP socket to send to different target address - valid? - c++

I'm working on a UDP communication protocol implementation.
I've got a question in regards to connect() call for UDP.
I want to use connect() and send() rather than sendto(). Usually the receiver end does not change. However, under certain circumstances, it might.
Is it valid to call connect() on a UDP socket that already is connected to set a different target without closing and re-opening the socket (and by that loosing buffered received datagrams)?
I didn't find any documentation whether that is valid or not (so, testing might only tell me if it happens to work, which might not be portable). I am currently working with winsock2 on Windows 7, but want to be portable to other (newer) Windows versions and to linux.

At least for Linux, the manpage (man 2 connect) says OK:
' Generally, connection-based protocol sockets may successfully connect() only once; connectionless protocol sockets may use connect() multiple times to change their association. Connectionless sockets may dissolve the asso‐
ciation by connecting to an address with the sa_family member of sockaddr set to AF_UNSPEC (supported on Linux since kernel 2.2).
'

Related

Only one socket receives data. Two UDP server sockets bound to same port, different addresses on Windows

[Similar Questions]:
Problems using UDP sockets bound to the same port on Windows
Handling multiple UDP sockets listening on the same endpoint
None of which ever got resolved.
[Situation]:
On Microsoft Windows, I bind two UDP server sockets in the same process. This particular (not to say peculiar) operating system supports only SO_REUSEADDR, it does not support SO_REUSEPORT; and on top of that, SO_REUSEADDR acts like SO_REUSEPORT.
So, considering the above, I am left with binding socket A to 0.0.0.0:1234 and socket B to say 192.168.1.1:1234; if I'm to reuse the same port on the same machine.
Namely, I cannot bind both to the same IP address, since Microsoft Windows would not agree with that; since yet again, it does not support two sockets to be bound to exactly the same tuple of {SRC_ADDR,DST_ADDR, SRC_PORT,DST_PORT,PROTOCOL} even when SO_REUSEADDR is used on BOTH sockets.
So, I'm forced to bind to two distinct addresses, if I'm to use the same port on the same machine. Even though 0.0.0.0 represents any address, but in any case Microsoft Windows agrees, and binds the two sockets in such a configuration, without any error.
The binding operations, in such a configuration for the two UDP sockets, do succeed.
Problem:
Now, I'm having trouble getting these sockets to receive data as expected. Namely, I expect the two sockets to receive data. In reality, only the socket which got bound first receives data.
Any ideas?
Is it that the data is always received by the socket best matching the destination? If you wonder why I'm playing that way, it's because I'm trying to multiplex two libraries with two protocols over the same port, with the least amount of modifications.
If you want two ports are received same udp packet you should set option/flag broadcast for transmit socket.
Something like:
socket_.set_option(boost::asio::socket_base::broadcast(true));
In some cases (for some OS's) you should transmit packet to broadcast address instead of exact ip-address.

C - Detecting TCP socket broken connection

I am implementing a tcp server socket. The server communicates with a client socket in another device.
The problem is: if the connection suddenly broken (cable removed), the recv() function didn't return.
I cannot implement ping pong (heartbeat) mechanism because I don't control the device implementation.
After searching on internet for a while, I found this tutorial: http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
But I don't fully understand the tutor. If I call setsockopt() on SO_KEEPALIVE, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL, the tutor says it will override system-wide variables (tcp_keepalive_time, tcp_keepalive_intvl, tcp_keepalive_probes)
Does it affect other sockets created by another thread/process?
TCP keep-alive functionality does allow you to detect broken connections. You need to enable it explicitly for your socket and change the defaults so that it detects a broken connection earlier, like your tutor instructed you.
But I don't fully understand the tutor. If I call setsockopt() on SO_KEEPALIVE, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL, the tutor says it will override system-wide variables (tcp_keepalive_time, tcp_keepalive_intvl, tcp_keepalive_probes)
Does it affect other sockets created by another thread/process?
It doesn't, setsockopt only affects the socket you pass as the argument to it.
TCP provides no good way to detect a broken connection on a side that is not sending. If the protocol the device uses does not provide any way for the server to detect a broken connection, the protocol is broken. About all you can do is implement a receive timeout, but that kind of sucks.
Does the protocol have documentation? What does it say to do?

keep_alive options for boost tcp acceptor and boost tcp socket

I have few questions, all related to keep_alive.
What is the difference between basic_socket_acceptor::keep_alive and basic_stream_socket::keep_alive? When to use which?
Do we need to use any kind of keep_alive for ip::tcp::acceptor? It doesn't make sense to me, as there is no connection as such for acceptor but there is a keep_alive option for it as well, hence the confusion.
If keep_alive is set, then what is the behaviour of Boost Asio when it detects broken connection? How/when does it notify the user-code? Does it throw exception? If so, which exception? I don't see any such details in the documentation.
What is the difference between basic_socket_acceptor::keep_alive and
basic_stream_socket::keep_alive? When to use which?
Both are same. In the documentation, it appears under basic_socket_acceptor and basic_stream_socket because both are derived from socket_base in which keepalive option is actually visible (it's a typedef).
As per the example in the documentation, you will always use it like:
boost::asio::socket_base::keep_alive option(true);
socket.set_option(option);
Do we need to use any kind of keep_alive for ip::tcp::acceptor?
No you don't have to and you cannot. set_option anyways can be called only on a socket object (I believe only after socket is opened).
If keep_alive is set, then what is the behaviour of Boost Asio when it
detects broken connection?
This is dependent on the platform. On linux you would be getting broken pipe error or EPOLLERR/EPOLLHUP when keep_alive probe fails.
UPDATE (from my comment below):
This failure is not propagated to the user code. So, either probably you need to implement an application level ping or use the timeout socket option.
The basic_socket_acceptor::keep_alive and basic_stream_socket::keep_alive are the same. The documentation notes that they are both inherited from the socket_base class which defines the socket_base::keep_alive option.
basic_stream_socket::keep_alive
Inherited from socket_base.
Socket option to send keep-alives.
While keep-alive on the listening socket is not directly useful for the listening socket, on some systems the newly accepted socket inherits some socket options from the listening socket. The inherited socket options are generally options that would affect the TCP three-way handshake that must complete before accept() returns, such as SO_KEEPALIVE. Consequently, Asio supports setting the keep-alive option on an acceptor; however, Asio does not copy socket options to the new socket.
The keep-alive feature allows for write operations to be notified that a connection is broken as determined by the keep-alive mechanism1. Hence, when the keep-alive probe fails, the next Asio write operation on the socket will fail2, passing the error_code to the application in the same way other error codes are provided. One should consult the operating system's documentation to determine the expected error code from the write operation:
On Windows, WSASend() is documented as returning WSAENETRESET (boost::asio::error:: connection_reset)
On Linux, the error will vary based on how the keep-alive probe fails. If no responses occur, then ETIMEOUT (boost::asio::error::timed_out) will occur. If an ICMP error is returned in response to a keep-alive probe, then the relevant ICMP error will be returned instead. For example, one could observe EHOSTUNREACH (boost::asio::error::host_unreachable) being returned
1. See 4.2.3.6 on the Requirements for Internet Hosts—Communication Layers specified in RFC 1122
2. SO_KEEPALIVE notifies thread writing to the socket via a SIGPIPE signal, but Asio explicitly disables receiving SIGPIPE on write operations. Consequently, the underlying system call will return with the relevant error
This depends on the platform you are running on. On linux if you do exactly the following,
boost::asio::socket_base::keep_alive option(true);
socket.set_option(option);
then you are basically protected from minor network interruptions that can occur and cause a read or write error on the socket. If you set keep_alive to true on the socket pointer then there are couple of certain ways to detect an error on the socket you are reading/writing on:
Firstly, you can detect a socket error by implementing a ping pong mechanism of sending a health packet in intervals between the peers.
Or, you can also detect an error when you are returned with a boost::asio::error::eof error from the socket which basically means that the peer has closed the connection. Note that a read on the socket can still return an boost::asio::error::eof error if the connection is closed by the peer.

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

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

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.