how to open socket for connecting to VK API, this code works good with other resources, but gives APPCRASH with api.vk.com. In browser it works with http, hence it should work here, and problem is not in 'http`, or am I wrong? Help!
P.S. I'm new to Boost and VK API, so if you can, explain it in details, thank you.
int main()
{
boost::asio::io_service io_service;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query("api.vk.com", "http");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
// Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
socket.connect(*endpoint_iterator, error);
return 0;
}
It looks like APPCRASH might be a thing you see in the Windows event log.
From that, I formed the hypothesis that you might be running this code in a windows service context.
Windows services do not have network access by default.
This means the DNS lookup may fail. You get an exception, e.g. resolve: Host not found (authoritative). This is what happens in a Linux console when I purposefully change the domain name to a nonexisting TLD:
$ ./test
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
what(): resolve: Host not found (authoritative)
Aborted (core dumped)
Because you don't handle the exception or check for errors, the program is abnormally terminated.
Fixed Demo
Note:
I opted to handle errors rather than exceptions.
You failed to loop through the query results (using only the first without even checking whether it was valid)
Coliru, much like a restricted windows service, does not allow network connectivity outside the loopback adaptor either, so it shows a proper error
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
using boost::asio::ip::tcp;
int main()
{
boost::asio::io_service io_service;
boost::system::error_code error = boost::asio::error::host_not_found;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query("api.vk.com", "http");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, error), last;
if (!error) {
// Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service);
for (;endpoint_iterator != last; ++endpoint_iterator) {
socket.connect(*endpoint_iterator, error);
if (!error) {
std::cout << "Successfully connected to " << endpoint_iterator->endpoint() << "\n";
break; // found working endpoint
} else {
std::cout << "Skipped " << endpoint_iterator->endpoint() << " - not connecting\n";
}
}
return 0;
} else {
std::cout << error.message() << "\n";
return 255;
}
}
On my system it prints
Successfully connected to 87.240.131.97:80
I simply changed my DNS server and it works: Successfully connected to 87.240.131.119:80
Related
I have one machine running simultaniously some C++ application and a Node.js server.
Use-case:
I want to be able to trigger my C++ application and make it pass some data (lets say a string) into a socket file. Then my Node.js server shall fetch that data from the socket and print it on some web page via a TCP-port (Code not included here/yet). The same should happen the other way around.
What I've done so far:
I was able to write some strings from my Node.js server into to the socket file with the following code:
server.js
var net = require('net');
var fs = require('fs');
var socketPath = '/tmp/sock';
fs.stat(socketPath, function(err) {
if (!err) fs.unlinkSync(socketPath);
var unixServer = net.createServer(function(localSerialConnection) {
localSerialConnection.on('data', function(data) {
// data is a buffer from the socket
console.log('Something happened!');
});
// write to socket with localSerialConnection.write()
localSerialConnection.write('HELLO\n');
localSerialConnection.write('I\'m\n');
localSerialConnection.write('DOING something!\n');
localSerialConnection.write('with the SOCKS\n');
});
unixServer.listen(socketPath);
});
reading the content with nc -U /tmp/sock and with the following output https://i.stack.imgur.com/ye2Dx.png.
When I run my C++ code:
cpp_socket.cpp
#include <boost/asio.hpp>
#include <iostream>
int main() {
using boost::asio::local::stream_protocol;
boost::system::error_code ec;
::unlink("/tmp/sock"); // Remove previous binding.
boost::asio::io_service service;
stream_protocol::endpoint ep("/tmp/sock");
stream_protocol::socket s(service);
std::cout << "passed setup section" << std::endl;
s.connect(ep);
std::cout << "passed connection" << std::endl;
std::string message = "Hello from C++!";
std::cout << "before sending" << std::endl;
boost::asio::write(s, boost::asio::buffer(message), boost::asio::transfer_all());
/* s.write_some(boost::asio::buffer("hello world!"), ec); */
std::cout << "after sending" << std::endl;
I get the following output:
/cpp_socket
passed setup section
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
what(): connect: No such file or directory
Aborted (core dumped)
Even though the /tmp/sock file still exists.
When I remove ::unlink("/tmp/sock"); // Remove previous binding. with comments it runs through, but my Node.js server stops running and nc -U /tmp/sock looses its connection.
Neither the .write() nor the .write_some() function seems to work.
I assume that I miss something trivial or I'm not following basic concepts of unix socket communication.
Questions:
Is it even possible to listen with one Node.js server application to a TCP-port and a UNIX-socket at the same time?
Am I understanding the concept of unix socket communication correctly, judging from my input?
How can I read or write from C++ from/into a socket, preferably with C++ boost/asio library. But not necessarily necessary :-)
Am I asking the right questions?
As you might see, I'm not too experienced with these subjects. If I haven't addressed my issues accordingly and not precisely enough,it's due to my lack of experience.
Thanks a lot in advance. Lets have a fruitful discussion.
Oh oops. The error was in plain sight:
::unlink("/tmp/sock"); // Remove previous binding.
Removes the socket. That's not good if you wanted to connect to it.
Removing that line made it work:
passed setup section
passed connection: Success
before sending
after sending
And on the listener side:
Which is, I guess, to be expected because the client isn't complete yet.
Disclaimer:
I made it work with TCP sockets, but I would like to see how its possible with unix sockets. One more open port could lead to potential security threats (correct me if I'm wrong). So if you (sehe) or someone knows how to achieve this, please feel free to share. Since I wasn't able to find this in my searches over the internet, it could be helpful for others, too.
What I did now:
Creating a NodeJS server which is listening to two ports. One port for the web-browser and one for the C++ application
Connect the C++ application with one port
Sending strings using telnet
server.js
const net = require('net');
const express = require('express');
const app = express();
const c_port = 6666;
const si_port = 8888;
//------------- From here Browser stream is handled -------------//
app.get('/', (req, res)=>{
res.send('Hello from Node!');
});
app.get('/index.html', (req, res) => {
res.sendFile(__dirname + "/" + "index.html");
});
app.listen(si_port,(req, res)=>{
console.log(`Listening on http://localhost:${si_port}`);
});
//------------- From here C++ stream is handled -------------//
var server = net.createServer(function(c) { //'connection' listener
console.log('client connected');
c.on('end', function() {
console.log('client disconnected');
});
c.write('hello\r\n');
c.on('data', function(data){
var read = data.toString();
console.log(read);
// var message = c.read();
// console.log(message);
})
// c.pipe(c);
c.write('Hello back to C++'); // But only if you shut down the server
});
server.listen(c_port, function() { //'listening' listener
console.log(`Listening for input from C++ application on port:${c_port}`);
});
client.cpp
#include <iostream>
#include <boost/asio.hpp>
int main(int argc, char* argv[])
{
if(argc != 4){
std::cout<<"Wrong parameter\n"<<"Example usage ./client 127.0.0.1 1234 hello"<<std::endl;
return -1;
}
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = std::atoi(argv[2]);
std::string msg = argv[3];
msg = msg + '\n';
boost::asio::io_service io_service;
//socket creation
boost::asio::ip::tcp::socket socket(io_service);
//connection
boost::system::error_code ec;
socket.connect( boost::asio::ip::tcp::endpoint( address, port ),ec);
if(ec){std::cout<<ec.message()<<std::endl; return 1;}
// request/message from client
//const string msg = "Hello from Client!\n";
boost::system::error_code error;
boost::asio::write( socket, boost::asio::buffer(msg), error );
if(error){
std::cout << "send failed: " << error.message() << std::endl;
}
// getting response from server
boost::asio::streambuf receive_buffer;
boost::asio::read(socket, receive_buffer, boost::asio::transfer_all(), error);
if( error && error != boost::asio::error::eof ){
std::cout << "receive failed: " << error.message() << std::endl;
}
else{
const char* data = boost::asio::buffer_cast<const char*>(receive_buffer.data());
std::cout << data << std::endl;
}
return 0;
}
With telnet localhost 6666 I can easily on that port and send random strings.
Executing my binary with additional arguments and a string I was able to send some data from my C++: ./clientcpp 127.0.0.1 6666 "HELLO from C++". And here is the output:
Thanks a lot again.
I'm trying to create a simple proxy server. I want to connect to a remote host_ (could be something like google.com) at port_, and forward a request req_buf_to_send. The following is my code:
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(host_, port_string, boost::asio::ip::resolver_query_base::numeric_service);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
tcp::endpoint connectionEndpoint(endpoint_iterator->endpoint().address(), port_);
boost::system::error_code ec;
socket.connect(connectionEndpoint, ec);
boost::asio::write(socket, req_buf_to_send);
When I run the above and send it a request that it needs to forward, the code fails and an exception is thrown:
Exception: resolve: Host not found (authoritative)
I also have a unit test for the above code and that fails too, saying:
C++ exception with description "resolve: Service not found" thrown in the test body.
So, it seems as though there is a problem in my resolver logic. Can anyone help me out?
Thank you.
Likely the host or service is unknown or empty. Here are a few demonstrations of how the resolver will fail depending on the inputs:
#include <boost/asio.hpp>
#include <iostream>
#include <iomanip>
#include <boost/range/istream_range.hpp>
int main() {
boost::asio::io_context io;
boost::asio::ip::tcp::resolver r(io);
for (auto q : {
boost::asio::ip::tcp::resolver::query
// these are good:
{"google.com", ""}, // port 0
{"google.com", "ftp"}, // port 21
{"google.com", "80"}, // port 80
// these ar bad:
{"google.ggg", ""}, // host not found
{"google.com", "bogus_service"}, // service not found
{"google.com", "-1"}, // service not found
{"", ""}, // host not found
})
{
try
{
for (auto ep : boost::make_iterator_range(r.resolve(q), {}))
std::cout << std::quoted(q.host_name()) << " -> " << ep.endpoint() << "\n";
} catch(std::exception const& e) {
std::cout << std::quoted(q.host_name()) << " " << e.what() << "\n";
}
}
}
Prints:
"google.com" -> 172.217.168.206:0
"google.com" -> [2a00:1450:400e:80c::200e]:0
"google.com" -> 172.217.168.206:21
"google.com" -> [2a00:1450:400e:80c::200e]:21
"google.com" -> 172.217.168.206:80
"google.com" -> [2a00:1450:400e:80c::200e]:80
"google.ggg" resolve: Host not found (authoritative)
"google.com" resolve: Service not found
"google.com" resolve: Service not found
"" resolve: Host not found (authoritative)
Now if your system doesn't know the service names that could be because you run on some stripped-down minimalist install (a docker container or embedded system?). Solutions are to install a standard service database (e.g. put the IANA list in /etc/services.
On a Debian it would be a matter of sudo apt-get install netbase
I'm having problems with the udp broadcast subsection of an application. I am using boost 1.62.0 under windows 10.
void test_udp_broadcast(void)
{
boost::asio::io_service io_service;
boost::asio::ip::udp::socket socket(io_service);
boost::asio::ip::udp::endpoint remote_endpoint;
socket.open(boost::asio::ip::udp::v4());
socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
socket.set_option(boost::asio::socket_base::broadcast(true));
remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4::any(), 4000);
try {
socket.bind(remote_endpoint);
socket.send_to(boost::asio::buffer("abc", 3), remote_endpoint);
} catch (boost::system::system_error e) {
std::cout << e.what() << std::endl;
}
}
I receive:
send_to: The requested address is not valid in its context
From the catch.
I've attempted to change the endpoint from any() to broadcast(), however this only throws the same error on bind().
I normally program under linux, and this code works on my normal target. So I'm scratching my head as to what I'm doing wrong here. Can anyone give me a poke in the right direction?
I believe you want to bind your socket to a local endpoint with any() (if you wish to receive broadcast packets - see this question), and send to a remote endpoint using broadcast() (see this question).
The following compiles for me and does not throw any errors:
void test_udp_broadcast(void)
{
boost::asio::io_service io_service;
boost::asio::ip::udp::socket socket(io_service);
boost::asio::ip::udp::endpoint local_endpoint;
boost::asio::ip::udp::endpoint remote_endpoint;
socket.open(boost::asio::ip::udp::v4());
socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
socket.set_option(boost::asio::socket_base::broadcast(true));
local_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4::any(), 4000);
remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4::broadcast(), 4000);
try {
socket.bind(local_endpoint);
socket.send_to(boost::asio::buffer("abc", 3), remote_endpoint);
} catch (boost::system::system_error e) {
std::cout << e.what() << std::endl;
}
}
I am facing a strange issue while trying to resolve endpoints using boost resolver in c++.
Case:
I am trying to connect to a website http://localhostIpAddress/test/ using boost.
where local address of server is "172.34.22.11"(say).
I am facing the error saying "resolve: No such host is known"
But when I am connecting to say website like google.com its able to resolve and connect successfully.
Also,even when I try to open "http:://localhostIpAddress/test/" in a browser, it opens successfully.
below is my code:
int main()
{
std::cout << "\nWebClient is starting... \n";
boost::asio::io_service IO_Servicehttp;
boost::asio::ip::tcp::resolver Resolverhttp(IO_Servicehttp);
std::string porthttp = "http";
boost::asio::ip::tcp::resolver::query Queryhttp("172.34.22.11/test/", porthttp);
boost::asio::ip::tcp::resolver::iterator EndPointIteratorhttp = Resolverhttp.resolve(Queryhttp);
g_ClientHttp = new HTTPClient(IO_Servicehttp, EndPointIteratorhttp);
}
catch (std::exception& e)
{
std::cerr << e.what();
}
}
In HTTPClient.cpp
HTTPClient::HTTPClient(boost::asio::io_service& IO_Servicehttp, boost::asio::ip::tcp::resolver::iterator EndPointIterhttp)
: m_IOServicehttp(IO_Servicehttp), m_Sockethttp(IO_Servicehttp),m_EndPointhttp(*EndPointIterhttp)
{
std::cout << "\n Entered: HTTPClient ctor \n";
boost::asio::ip::tcp::resolver::iterator endhttp;
boost::system::error_code error= boost::asio::error::host_not_found;
try
{
while (error && EndPointIterhttp != endhttp) //if error go to next endpoint
{
m_Sockethttp.async_connect(m_EndPointhttp,boost::bind(&HTTPClient::OnConnect_http, this, boost::asio::placeholders::error, ++EndPointIterhttp));
}
if(error)
throw boost::system::system_error(error);
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
m_IOServicehttp.run();
}
I have gone through a lot of website directed by google but haven't found anything related to this issue.
Any help or tip will be much appreciated
The hostname being resolved is invalid. Try changing the resolver's query host to "172.34.22.11". In the URL, "http://172.34.22.11/test/":
"http" is the protocol
"172.34.22.11" is the host which needs resolved
"/test/" is the path
At a high level, network communication occurs between the client and the server (host) over TCP. The client will create an HTTP request, include the path as part of the request, and write the complete request to a TCP socket. The server will read the HTTP request from a TCP socket, process the request based on the path, then write an HTTP response to the client over TCP.
Hostnames are concatenated with dots and specified to only allow:
ASCII letters 'a' through 'z'
digits
hyphen
Hence, "172.34.22.11/test/" contains invalid characters, and will likely not resolve. See RFC952 and RFC1123 for more details.
Im following the tutorials at the boost official web site http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/tutorial/tutdaytime1.html.
The program is working perfectly if i connect to "localhost" or "127.0.0.1" on the same machine. But if i run the client on another computer with the same network it fails to connect to the server. Why is this happening? and what would i have to do to get the client to run on another network?
Error: connect: No connection could be made because the target machine actively refused it.
Client:
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main()
{
try
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
char* serverName = "localhost";
tcp::resolver::query query(serverName, "daytime");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
while(true)
{
boost::asio::connect(socket, endpoint_iterator);
for (;;)
{
boost::array<char, 128> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
std::cout.write(buf.data(), len);
std::cout <<"\n";
}
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
Server:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main()
{
try
{
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13));
for (;;)
{
tcp::socket socket(io_service);
acceptor.accept(socket);
std::string message = "This is the Server!";
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
I would guess your problem might be that you return on the first error. Resolving gives you an iterator on a number of endpoints. You try the first of those and if it does not work out you give up instead of letting the iterator go on.
Again, i am by no means an expert in boost::asio and far less in its TCP world but resolve may return more than one endpoint (for example IPv4 and IPv6) and possibly only one of them does not work out here.
For testing you could create the endpoint yourself by first creating a ip::address object, using its from_string() method to give it the address of the server (works only on your local network of course) and then using it for your endpoint:
boost::asio::ip::address address;
address.from_string("the.servers.ip.here");
boost::asio::ip::tcp::endpoint endpoint(address, 13);
boost::asio::connect(socket, endpoint);
And see if that works. If not, it probably is a problem on the server side.
To run the server and client on separate networks, Make the client connect to the servers external ip address. This is obvious but external ip addresses constantly change so to solve this problem you can go to www.noip.com and create a name that links to your ip address. This way in the client all you have to do is specify a name instead of an ip address.
most likely firewall issue, if you are using windows for server check windows firewall, if you are using linux, check the iptables.