boost:asio IPv4 address and UDP comms - c++

Problem Solved - See bottom for solution notes
I'm trying to build a simple app to test an ethernet-capable microcontroller. All I want to do is send and receive small UDP packets. The code is using boost::asio for the networking, and is incredibly simple. For debugging I moved all the intialisation out of the constructors so I could check each step. Here's the body of my stuff:
boost::system::error_code myError;
boost::asio::ip::address_v4 targetIP;
targetIP.from_string("10.1.1.75", myError); // Configure output IP address. HACKHACK--Hardcoded for Debugging
std::cout << "GetIP - " << myError.message() << std::endl;
std::cout << "IP: " << targetIP << std::endl;
boost::asio::ip::udp::endpoint myEndpoint; // Create endpoint on specified IP.
myEndpoint.address(targetIP);
myEndpoint.port(0x1000);
std::cout << "Endpoint IP: " << myEndpoint.address().to_string() << std::endl;
std::cout << "Endpoint Port: " << myEndpoint.port() << std::endl;
boost::asio::io_service io_service; // Create socket and IO service, bind socket to endpoint.
udp::socket socket(io_service);
socket.open( myEndpoint.protocol(), myError );
std::cout << "Open - " << myError.message() << std::endl;
socket.bind( myEndpoint, myError );
std::cout << "Bind - " << myError.message() << std::endl;
char myMessage[] = "UDP Hello World!"; // Send basig string, enable socket level debugging.
socket.send(boost::asio::buffer(myMessage, sizeof(myMessage)), boost::asio::socket_base::debug(true), myError);
std::cout << "Send - " << myError.message() << std::endl;
boost::array<char, 128> recv_buf; // Receive something (hopefully an echo from the uP)
udp::endpoint sender_endpoint;
size_t len = socket.receive_from( boost::asio::buffer(recv_buf), myEndpoint );
std::cout.write(recv_buf.data(), len);
The snag happens right at the beginning. The address_v4 doesn't want to accept the IP that I'm passing into it. The output of this app is:
GetIP - The operation completed successfully
IP: 0.0.0.0
Endpoint IP: 0.0.0.0
Endpoint Port: 4096
Open - The operation completed successfully
Bind - The operation completed successfully
Send - A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
I'm assuming the send error is a result of the address_v4 not getting set correctly, but there is no reason that I can think of for such a thing to be taking place.
For those playing along at home, my PC has dual ethernet cards, one of which has been DHCP'd 10.1.1.7, so the target IP should be reachable without any routing. I'm using BOOST 1.46.1 on 32-bit Win7 and MSVS 10. It also fails when I try an IP of 127.0.0.1, correct me if I'm wrong but that should work for loopback in this context?
Edit with Updates:
So thanks to the earlier answers I've gotten the IP address into my address_v4, and I'm no longer trying to bind when I meant to use connect. The significanly changed section of code is the TX, which now looks like:
socket.open( targetEndpoint.protocol(), myError );
std::cout << "Open - " << myError.message() << std::endl;
char myMessage[] = "UDP Hello World!"; // Send basig string, enable socket level debugging.
socket.send_to(boost::asio::buffer(myMessage, sizeof(myMessage)), targetEndpoint, boost::asio::socket_base::debug(true), myError);
std::cout << "Send - " << myError.message() << std::endl;
(I renamed myEndpoint to targetEndpoint to help reduce confusion.....)
I now get the error while trying to send:
The attempted operation is not supported for the type of object referenced
I would give my firstborn for an informative error message at this point! The error is consistent regardless of which target port I use. The only thing I can think of is that I need to be setting the source port somewhere, but I don't see how you can do that in any of the boost::asio documentation.
Final Resolution
I have managed to make this work, so I'm going to post the gotchas that I found in a nice neat list for anyone else who stumbles across this answer with similar problems to me. I think the main issue I had was that none of the boost examples ever show how to connect to a specified IP, they all use a resolver. It made the examples a lot harder to understand for me.
When using the from_string call to convert a text IP, use the syntax from the first answer below rather than my syntax above!
When setting up the UDP socket, order of operations is crucial! If you don't want to do it in the constructor you need to:
Open the socket using the required protocol.
Bind the socket to a local endpoint which specifies the source UDP port number.
Connect the socket to the remote endpoint which specifies the destination IP and Port number.
Attempting to bind after the connect will cause the bind to fail. The transmission will operate just fine, but your packets will be sent from an arbitrary port number.
Use a send method to actually transmit. Do not attempt to enable debugging data with boost::asio::socket_base::debug(true)! All this flag seems to do is cause error messages within an otherwise functional send!
I'd also like to share that my most valuable debugging tool in this entire exercise was Wireshark. Maybe it's only because I'm used to having a CRO or Protocol Analyser when I'm working on comms like this, but I found being able to see the bytes-on-wire display helped me sort out a whole bucketload of stuff that I would otherwise never have tracked down.
Cheers for your help on the IP issues and helping me realise the difference between connect and bind.

The problem you are currently seeing appears to be your usage of this line:
targetIP.from_string("10.1.1.75", myError);
boost::asio::ip::address::from_string is a static function, that returns a constructed ip::address object. Change it to look like this:
targetIP = boost::asio::ip::address::from_string("10.1.1.75", myError);
And your IP address should be populated properly.

On the top of my head, you try to bind the socket to an endpoint with address 10.1.1.75, but that seems to be a remote endpoint? I would assume you would like to bind it locally and use send_to, as it is UDP

In this line there is an error:
targetIP = boost::asio::ip::address::from_string("10.1.1.75", myError);
You should put:
targetIP = boost::asio::ip::address_v4::from_string("10.1.1.75", myError);
and then targetIP has the right value!

Related

How to close tcp server socket correctly

can anyone explain me, what I am doing wrong with my tcp server termination?
In my program (single instance), I started another program which starts a tcp server. For the tcp server it is only allowed to listen to one connection.
After a connection was established between client and my server, a few messages are shared. As soon as the message protocoI has passed through, I want to terminate the server socket, reset my internal states and close my sub-programm.
After a few seconds, it will be possible to open my sub-programm again.
If so, I open the socket again... The same network device, the same ip address and the same port as before will be used...
My problem: my sub-programm crashes when running the 2nd time.
With netstat I analyzed my socket and found out, it stays in state LAST_ACK.
This can take more than 60 seconds (timeout?) till the socket is finally closed.
For closing the socket, I used the following code:
if (0 != shutdown(socketDescriptor_, SHUT_RDWR)) {
std::cout << "Read/write of socket deactivated" << std::endl;
}
if (0 == close(socketDescriptor_)) {
std::cout << "Socket is destroyed" << std::endl;
socketDescriptor_ = -1;
}
Any ideas? Thanks for your help!
Kind regards,
Matthias

TCP packet drop (ns3)

I am new to ns3 network simulator and wanted to know how to get the number of packet drops in a TCP connection. I know of the following command:
devices.Get (1)->TraceConnectWithoutContext ("PhyRxDrop", MakeBoundCallback (&RxDrop, stream));
But this is helpful only for a single TCP connection over a p2p link. In my topology, there is a single p2p connection but 2 applications using TCP over that same p2p link and I would like to know individually for each TCP connection the number of dropped packets. I have researched online quite a lot but was unable to find any resources. Kindly point to some resources or give the class name which I can use to detect TCP connection-specific packet losses.
The above command as of now combines the packet losses for both the connections and outputs them to the stream because they are over the same p2p link.
The usage of RxDrop tells me you're using referring to fourth.cc in the ns-3 tutorial. Connecting to the PhyRxDrop TraceSource will result in the requested CallBack being invoked for each dropped packet. ns-3 doesn't have a packet filter such that the CallBack would only be invoked for some packets.
However, you can determine which connection a packet corresponds to. Simply strip the packet headers, and inspect the port numbers. Remember every connection is defined by a unique 4-tuple: (host IP, host port, destination IP, destination port).
static void
RxDrop(Ptr<const Packet> packet) {
/*
* Need to copy packet since headers need to be removed
* to be inspected. Alternatively, remove the headers,
* and add them back.
*/
Ptr<Packet> copy = packet->Copy();
// Headers must be removed in the order they're present.
PppHeader pppHeader;
copy->RemoveHeader(pppHeader);
Ipv4Header ipHeader;
copy->RemoveHeader(ipHeader);
TcpHeader tcpHeader;
copy->RemoveHeader(tcpHeader);
std::cout << "Source IP: ";
ipHeader.GetSource().Print(std::cout);
std::cout << std::endl;
std::cout << "Source Port: " << tcpHeader.GetSourcePort() << std::endl;
std::cout << "Destination IP: ";
ipHeader.GetDestination().Print(std::cout);
std::cout << std::endl;
std::cout << "Destination Port: " << tcpHeader.GetDestinationPort() << std::endl;
}

Binding to specific IP address using Websocket++

Using websocket++ as a client to a websocket server I want to connect using a specific IP of my client server. So I am trying to figure out how to bind to a specific IP, but it's not working out.
I've figured the on_socket_init handler might be used to configure the socket, however this handler:
void on_socket_init(websocketpp::connection_hdl hdl, boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &s) {
boost::asio::ip::tcp::endpoint localEndpoint(
boost::asio::ip::address::from_string("192.168.178.28"), 0);
std::cout << "Before bind is done " << s.lowest_layer().local_endpoint().address().to_string() << std::endl;
s.lowest_layer().bind(localEndpoint);
std::cout << "Bind is done " << s.lowest_layer().local_endpoint().address().to_string() << std::endl;
causes this to happen:
Before bind is done 192.168.178.28
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
what(): bind: Invalid argument
On my local machine I do not have more than one IP, so I am just trying to tell it to bind to the one IP I have, which should just not change anything for now, except validate that I can call bind(). However it blows up and I have no idea why.
Testing on a server with a 2nd IP I get the same error.
Using gdb I've only found that the exception is thrown by a function that checks for some error code of some internal bind call. I have no idea where the code of that internal bind call would be and there is no further information except "Invalid argument" or error code 22. Which is just the number for invalid argument.
Trying to assign a bogus address I do not have on my machine yields a different error "bind: Cannot assign requested address", so guess the address I pass in is fine.
Is this the right way of doing this at all?

Multithreading in C++, receive message from socket

I have studied Java for 8 months but decided to learn some c++ to on my spare time.
I'm currently making a multithreaded server in QT with minGW. My problem is that when a client connects, I create an instance of Client( which is a class) and pass the socket in the client class contructor.
And then I start a thread in the client object (startClient()) which is going to wait for messages, but it doesn't. Btw, startClient is a method that I create a thread from. See code below.
What happens then? Yes, when I try to send messages to the server, only errors, the server won't print out that a new client connects, and for some reason my computer starts working really hard. And qtcreator gets super slow until I close the server-program.
What I actually is trying to achieve is an object which derives the thread, but I have heard that it isn't a very good idea to do so in C++.
The listener loop in the server:
for (;;)
{
if ((sock_CONNECTION = accept(sock_LISTEN, (SOCKADDR*)&ADDRESS, &AddressSize)))
{
cout << "\nClient connected" << endl;
Client client(sock_CONNECTION); // new object and pass the socket
std::thread t1(&Client::startClient, client); //create thread of the method
t1.detach();
}
}
the Client class:
Client::Client(SOCKET socket)
{
this->socket = socket;
cout << "hello from clientconstructor ! " << endl;
}
void Client::startClient()
{
cout << "hello from clientmethod ! " << endl;
// WHEN I ADD THE CODE BELOW I DON'T GET ANY OUTPUT ON THE CONSOLE!
// No messages gets received either.
char RecvdData[100] = "";
int ret;
for(;;)
{
try
{
ret = recv(socket,RecvdData,sizeof(RecvdData),0);
cout << RecvdData << endl;
}
catch (int e)
{
cout << "Error sending message to client" << endl;
}
}
}
It looks like your Client object is going out of scope after you detach it.
if (/* ... */)
{
Client client(sock_CONNECTION);
std::thread t1(&Client::startClient, client);
t1.detach();
} // GOING OUT OF SCOPE HERE
You'll need to create a pointer of your client object and manage it, or define it at a higher level where it won't go out of scope.
The fact that you never see any output from the Server likely means that your client is unable to connect to your Server in the first place. Check that you are doing your IP addressing correctly in your connect calls. If that looks good, then maybe there is a firewall blocking the connection. Turn that off or open the necessary ports.
Your connecting client is likely getting an error from connect that it is interpreting as success and then trying to send lots of traffic on an invalid socket as fast as it can, which is why your machine seems to be working hard.
You definitely need to check the return values from accept, connect, read and write more carefully. Also, make sure that you aren't running your Server's accept socket in non-blocking mode. I don't think that you are because you aren't seeing any output, but if you did it would infinitely loop on error spawning tons of threads that would also infinitely loop on errors and likely bring your machine to its knees.
If I misunderstood what is happening and you do actually get a client connection and have "Client connected" and "hello from client method ! " output, then it is highly likely that your calls to recv() are failing and you are ignoring the failure. So, you are in a tight infinite loop that is repeatedly outputting "" as fast as possible.
You also probably want to change your catch block to catch (...) rather than int. I doubt either recv() or cout throw an int. Even so, that catch block won't be invoked when recv fails because recv doesn't throw any exceptions AFAIK. It returns its failure indicator through its return value.

UDP bind failures

{Windows 7, MinGW 4.8, boost 1.55}
I'm having some problems with UDP binds. I've a client that broadcasts datagrams for listeners listening on specific port and binds to a port itself if the listeners want to communicate something back.
The port on which the client needs to bind is X and the servers are listening on Y.
Problem:
If I simulate a client-crash (eg., by causing segmentation fault by dereferencing a nullptr) after binding the UDP socket to the port, then once the client application is no longer running (no longer listed in Windows Task Manager) netstat -ano | find "X" still shows that someone is bound to port X and ip address of 0.0.0.0 (the client had specified the IP address as any address). The PID cannot be found in Windows Task Manager. However when I downloaded application TCPView I can see that a <non-existent> process is still bound to 50000. On starting the client (without making it crash this time) subsequently.
I get two behaviors:
<1> On some machines the client is unable to bind to the socket again (although reuse_address option is set to true) and the error message is: An attempt was made to access a socket in a way forbidden by its access permissions.
<2> On other machines the client binds successfully but the read handler is not called and the client does not receive any datagram on port X although the servers are unicasting to the client port X. Infact <2> is true even for launching multiple instances of the client on the same machine even if none of the clients were deliberately made to crash and exist as zombie processes. Only the 1st one gets datagrams.
Here is how client socket is set up:
if(!m_udpSocket.is_open())
{
m_udpSocket.open(m_localEndpoint.protocol(), errorCode); //m_localEndpoint is address 0.0.0.0 and port X
if(errorCode)
{
std::cerr << "Unable to open socket: " << errorCode.message() << std::endl;
}
else
{
m_udpSocket.set_option(boost::asio::socket_base::reuse_address(true), errorCode);
if(errorCode)
{
std::cerr << "Reuse address option set failure. " << errorCode.message() << std::endl;
}
m_udpSocket.set_option(boost::asio::socket_base::broadcast(true), errorCode);
if(errorCode)
{
std::cerr << "Socket cannot send broadcast. " << errorCode.message() << std::endl;
}
else
{
m_udpSocket.bind(m_localEndpoint, errorCode);
if(errorCode)
{
std::cerr << "Socket cannot bind...!! " << errorCode.message() << std::endl;
}
}
}
}
Can you explain why do I get <1> and <2> and what can I do to avoid them and make socket bind even if there is some other process bound to that socket? I need to support Windows, Linux and MAC.