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?
Related
I am trying to implement gRPC server/ client for the first time using Windows Subsystem for Linux kernel and CLion as the IDE (on Windows). My code does not have any other bugs/ issues except this communication failure.
The following lines of code
if(status.ok()) {
cv::imshow("Rotated image", decrypt_img);
} else {
std::cout << status.error_code() << " : " << status.error_message() << std::endl;
}
yields the following message
14 : failed to connect to all addresses
This is a kind of generic error message from grpc which can have multiple causes.
In my experience, it can be one of the following things:
Your server isn't running (either you forgot to call grpc::ServerBuilder::BuildAndStart or you didn't start your server application all along).
When running the server for the first time Windows Firewall should ask you if you want to allow your application to access the network (I don't recall the actual wording). You want to accept this, of course.
You have a wrong address specified in your client application (i.e. a different one than you have set in your server application via grpc::ServerBuilder::AddListeningPort)
Not knowing your actual server and client code these are just assumptions I can make based on my experience with grpc.
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.
{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.
Now, in the simplified snippet below, if my query returns results,
everything is ok.
If query returns no results, then everything still goes as expected,
an Exception is thrown and caught.
After this query, if I try to execute yet another query, the
statement dbConn->query(collection, queryObj) throws a mongo::SocketException. And the message printed is:
socket exception [SEND_ERROR] for 127.0.0.1:27017 // 9001 socket exception [2] server [127.0.0.1:27017]
From this one on, the following queries all throw the same exception, with a different message:
socket exception [FAILED_STATE] for localhost:27017 // 9001 socket exception [5] server [localhost:27017]
I have also printed out error code strings, both of them are "Unknown error"s.
If I restart the process, it resets, therefore I'm assuming the connection is somehow damaged. No one else is accessing the shared ptr at the moment. mongo daemon runs fine and there is nothing unusual in mongodb log.
My big question is: Why does happen?
The snippet:
try
{
// Some initialzation here..
// dbConn is a boost::shared_ptr<mongo::DBClientConnection>
std::auto_ptr<mongo::DBClientCursor> cursor = dbConn->query(collection, queryObj);
if (!cursor->more())
{
throw Exception();
}
}
catch(const Exception&)
{
}
catch(const mongo::SocketException& e)
{
std::cout << ex.what() << "//" << ex.toString() << std::endl;
}
MongoDB C++ driver version is 2.3.2.
I assume that you acquire and initialize the connection else where in your code, expecting to avoid the overhead of acquiring that connection every time you need it. (I did that initially in my code as well).
I think you'll find that moving the connection acquisition closer in using ScopedDbConnection and getting a fresh connection from the driver will help things along; the driver seems to manage the connection well enough.
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!