boost::asio failed to connect to localhost without WLAN - c++

On my computer(Surface Pro 2), there is only one network adapter,
it is a wireless LAN adapter.
I worked on a small C++ project, it uses boost::asio to connect to
localhost and do its work, everything is just fine.
But today I found that if I disconnect the WLAN from the Internet,
this program does not work.
An exception will be thrown by resolver of boost::asio :
tcp::resolver::query query("localhost", "10127");
tcp::resolver resolver(io_service_);
tcp::resolver::iterator iterator;
try {
iterator = resolver.resolve(query);
}
catch (boost::system::system_error& e) {
log(e.what());
}
And the error message was: the requested name is valid but no data
of the requested type was found.
Ping to localhost is OK.
I feel puzzled, does a local network program need Internet ?
Does a local network program need a LAN adapter ?
Why ping works fine ?

I just had the same problem on a linux machine and looked up the boost asio documentation. You just need to add a flag argument to the query constructor:
tcp::resolver::query query("localhost","10127",tcp::resolver::query::canonical_name);
Note: the full scoped name of query is boost::asio::ip::tcp::resolver::query.
This happens because the default flags argument passed here is boost::asio::ip::tcp::resolver::query::address_configured, which means that the call should only resolve IPv4/IPv6 addresses if a non-loopback IPv4/IPv6 address is configured for the system.

I have no explanation of why you have this error. However, what I did in a project was not by specifying the port number directly, but rather by constructing the endpoint instance in two steps. I don't recall the rationale at the time for doing it this way, but it might help you.
My proposed solution is something like this:
ip::tcp::resolver::query query(ip::tcp::v4(), "localhost", ""); // empty service name
tcp::resolver::iterator it_endpoint = resolver.resolve(query);
ip::tcp::endpoint endpoint(ip::tcp::endpoint(*it_endpoint).address(), port);
This is a summarized excerpt of what I did, so it may not compile as-is.

local network does not required internet to work. In your case, I don't know exact the problem of Windows TCP/IP layer with resolve localhost when it does not have any DNS server config(Network card is not connected, ..etc). But you can use tcp::resolver::query query("127.0.0.1", "10127"); instead of tcp::resolver::query query("localhost", "10127");
which works always.

Related

Winsock connect is slow

I have a program that uses Boost.Asio to connect to a server on localhost. Here is the relevant part of the code:
TcpClient::TcpClient(uint16_t port_number) : socket_(service_)
{
boost::asio::ip::tcp::resolver resolver(service_);
boost::asio::ip::tcp::resolver::query resolver_query("localhost", std::to_string(port_number));
auto endpoint_iterator = resolver.resolve(resolver_query);
boost::asio::connect(socket_, endpoint_iterator);
}
The code functions just fine. On Ubuntu, the connect function returns almost immediately. However, on Windows it takes over 2 seconds to complete.
Stepping through the boost code, I found the 2 seconds are spent on the Winsock connect function call.
Am I missing something (either in code, or in the environment) that can speed up this call?
Thank you!
If you have IPv6 enabled then resolver_query("localhost", std::to_string(port_number)); will return an IPv4 and IPv6 address (from experience with the IPv6 listed first). If your server isn't listening on IPv6 then boost::asio::connect will try IPv6 first, wait for it to fail and only then try IPv4.
Either get your server to listen on IPv6, use "127.0.0.1" instead of localhost or restrict the resolver to only return IPv4:
resolver_query(boost::asio::ip::tcp::v4(), "localhost", std::to_string(port_number));

Boost Asio UDP server set socket to listen on specified IP

When I'm working on a UDP server I usually set the socket to listen on specified port and accept any IP. Keep in mind that sync receive works properly here.
std::unique_ptr<boost::asio::ip::udp::socket> socketUDP;
socketUDP.reset(new udp::socket(io_serviceUDP, udp::endpoint(udp::v4(), 9999)));
However, I would really like to have 2 different server applications listening at the same port (9999) but accepting only a single IP (I already know that IP). Each of the apps has its own client with its own IP.
But for some reason the following doesn't work (not receiving any packets in the app, while Wireshark can see it)
socketUDP.reset(new udp::socket(m_io_serviceUDP, udp::endpoint(asio::ip::address::from_string("169.254.1.2"), 9999)));
Please note :
1) According to the answer for : Issue with broadcast using Boost.Asio this should actually work. Of course my understanding isn't quite correct as I'm missing something
2) The provided IP is valid, works, sends data(confirmed by wireshark) and can be pinged
The issue is that your socketUDP's are not configured with:
set_option(boost::asio::ip::udp::socket::reuse_address(true));
However, simply calling the line above on your sockets won't work, because you must call reuse_address before the socket is bound to an endpoint... But you're constructing udp::socket with an endpoint which opens it and binds it to the endpoint, see basic_datagram_socket.
The solution is to call the constructor which just takes an io_service; open it, set the reuse_addressoption and then bind it, e.g.:
// construct the socket
boost::asio::ip::udp::socket socket_(io_service_);
// open it
boost::asio::ip::udp::endpoint rx_endpoint_(udp::v4(), 9999);
socket_.open(rx_endpoint_.protocol(), error);
if (error)
return false;
// then set it for reuse and bind it
socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true));
socket_.bind(rx_endpoint_, error);
if (error)
return false;
// set multicast group, etc.
socket_.set_option(boost::asio::ip::multicast::join_group(ip_address));
...

QTcpSocket: selecting source interface using bind() for connection to remote host with connectToHost(): need a workaround

i want to use certain source interface for connection to remote host. I have
3 interfaces: eth0 (192.168.230.100), wlan0(10.0.9.100), and lo:
Assuming mSocket is class member:
QTcpSocket mSocket;
And in constructor we use:
bool ret = mSocket.bind(QHostAddress("10.0.9.100"));
And then in timer we try to connect:
void CamComponent::tryToConnect()
{
mSocket.connectToHost(QHostAddress(CameraIpAddr), CameraPort);
}
And after this i use TCPDUMP to view outgoing packets, and they dont have source IP 10.0.9.100. Using strace i had checked that Qt makes calls to:
socket()
bind()
socket() <- this causes problem, it’s QT internal
problem
connect()
What is workaround for this problem ?
This issue is not Qt related. You just have to understand a bit how a TCP/IP stack work.
When you try to connect to a remote server, your provide its IP address. Internally, your operating system will choose an appropriate out interface to send these connection packets, according to its routing table. (I will not speak to much about conflicts and default routing here, Google should be enough to make your culture)
So, you just have to use your QTcpSocket as client socket, connectToHost and let the resolution magic happened. The socket binding is only meaningful in a server application.

Boost Asio tcp::resolver: service not found

I'm trying to create an HTTP client using Boost Asio. I copied the sync client example from asio, compile, then run. Unfortunately, on my logs, it shows Service not found. When I traced the code, I found it that it is thrown from the following code:
boost::asio::io_service io_service;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
//->if i removed the http, it has no error
tcp::resolver::query query("host.com", "http");
//->This part throws the service not found
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
Can anybody explain why it is throwing service not found or on how can I solve this?
This means the OS does not know which port number corresponds to the TCP service with the name "http".
On a unix-like OS, this would mean the line http 80/tcp is missing from /etc/services, I am able to reproduce the error on Linux by commenting that line out.
If the OS cannot be configured to use services, you may use any service "" in the resolver, and specify the port number explicitly when creating the endpoint object for the connect call:
tcp::endpoint connectionEndpoint(endpoint_iterator->address(), 80);
boost::system::error_code ec;
socket.connect(connectionEndpoint, ec);

How boost.asio discover which port is my server app listening on?

it is a little bit strange to me that boost.asio doesn`t use basic concept when client app connecting to the server - using IP address and port. May be I am a little bit noobie in Boost - and I accept that - but anyway I do not understand.
So, I have code like this to get client connected to the server on the localhost:
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query("localhost", "daytime");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
tcp::socket socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
while(error && endpoint_iterator != end) {
socket.close();
socket.connect(*endpoint_iterator++, error);
}
Windows in its WinSock 2.0 uses two parameters - IP and port - to identify the server. So, the qurestion is - how exactly Asio finds out which port is server listening to connections on? Does it scans all ports? And, if it does, what will happen if two servers listening on different ports at the same time?
Try,
tcp::resolver::query query("localhost", boost::lexical_cast<string>(port));//assuming port is an int
To answer your question, recall that you are starting the server on port 13. This happens to be the port which runs the Linux daytime service (http://www.sorgonet.com/linux/linuxdaemons/). Hence, they are subsequently able to use query("localhost","daytime") rather than specifying the port.
You are telling it that you want to connect to localhost on the port used by the daytime service. It will look up the appropriate port number in the services file (usually C:\WINDOWS\system32\drivers\etc\services under Windows, I believe /etc/services under Unix). You could also use an explicit port number there.
open netcat listen on port 13 on the localhost
it will accept the demo's connection. type some blabla when it connects and you'll see the output on the demo program
to run the netcat, run:
nc -l -p 13
windows? no netcat? install cygwin, and add netcat