Sending commands to server using Poco library - c++

I'm new to socket programming. I'm working with the Poco library. I found this example online. (https://pocoproject.org/slides/200-Network.pdf)
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/StreamCopier.h"
#include <iostream>
int main(int argc, char** argv)
{
Poco::Net::SocketAddress sa("www.appinf.com", 80);
Poco::Net::StreamSocket socket(sa)
Poco::Net::SocketStream str(socket);
str << "GET / HTTP/1.1\r\n"
"Host: www.appinf.com\r\n"
"\r\n";
str.flush();
Poco::StreamCopier::copyStream(str, std::cout);
return 0;
}
I understand that a socket stream is created.
I cannot understand the commands. What does the "/" do after "GET" or what is "1.1". Please do explain what that particular line means.
This code does give me an output. But how do the commands work? And is there a way to give the commands from the console? Thanks.

I'm not sure what you want to do here.
Are you trying to do HTTP or not?
If not, then do your own text, but don't use port 80 as that is the well known http port.
If you want to just send whatever you type over a TCP socket, then you probably could use the StreamCopier to send everything from std::cin to str.

Related

Boost 1.67 - beast::websocket Error: resolve: Host not found (authoritative)

I am trying to use beast::websocket for my Raspberry pi project where Rpi is an IoT websocket client and Microsoft Azure WebPubSub is server-side.
I am new to C++ and Unix system. Sadly, I was unable to find that many useful reference projects using the C++ Websocket.
The first thing I wanted to do was to use the beast::websocket client example to successfully connect to a test websocket server.
Below is the example I used. beast::websocket example 1.67
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
namespace websocket = boost::beast::websocket; // from <boost/beast/websocket.hpp>
// Sends a WebSocket message and prints the response
int main(int argc, char** argv)
{
try
{
// Check command line arguments.
if(argc != 4)
{
std::cerr <<
"Usage: websocket-client-sync <host> <port> <text>\n" <<
"Example:\n" <<
" websocket-client-sync echo.websocket.org 80 \"Hello, world!\"\n";
return EXIT_FAILURE;
}
auto const host = argv[1];
auto const port = argv[2];
auto const text = argv[3];
// The io_context is required for all I/O
boost::asio::io_context ioc;
// These objects perform our I/O
tcp::resolver resolver{ioc};
websocket::stream<tcp::socket> ws{ioc};
// Look up the domain name
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
boost::asio::connect(ws.next_layer(), results.begin(), results.end());
// Perform the websocket handshake
ws.handshake(host, "/");
// Send the message
ws.write(boost::asio::buffer(std::string(text)));
// This buffer will hold the incoming message
boost::beast::multi_buffer buffer;
// Read a message into our buffer
ws.read(buffer);
// Close the WebSocket connection
ws.close(websocket::close_code::normal);
// If we get here then the connection is closed gracefully
// The buffers() function helps print a ConstBufferSequence
std::cout << boost::beast::buffers(buffer.data()) << std::endl;
}
catch(std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Because echo.websocket.org is closed now. I used different test servers.
These are the command line for two different websocket test servers.
sudo websocket-client-sync streamer.finance.yahoo.com 80 "Hello, world!"
Returned with Error: The WebSocket stream was gracefully closed at both endpoints
sudo websocket-client-sync demo.piesocket.com/v3/channel_1?api_key=oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm&notify_self 80 "Hello, world!"
Returned with Error: resolve: Host not found (authoritative)
I was able to connect both URLs with a websocket test client.
But unable to connect or keep connected through this beast example.
Especially, for the second server with an API key and forward slashes, I wasn't even able to find a host.
I thought this could be something to do with those special characters not recognized as literal?
So so far these are what I have tried.
I tried replacing / with /.
I specified the host in the cpp file
(ex. auto const host = "demo.piesocket.com/v3/channel_1?api_key=oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm&notify_self";)
Used encoded URL
(ex. demo.piesocket.com%2Fv3%2Fchannel_1%3Fapi_key%3DoCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm%26notify_self)
used port 443 instead of 80
tried secure beast::websocket example over SSL for wss servers.
Nothing worked...
In the end, I need to use an Azure websocket URL with an access token which looks like this
wss://lupo.webpubsub.azure.com/client/hubs/Hub?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ3c3M6Ly9sdXBvLndlYnB1YnN1Yi5henVyZS5jb20vY2xpZW50L2h1YnMvSHViIiwiaWF0IjoxNjMzNTc3ODA1LCJleHAiOjE2MzM1ODE0MDV9.1xGRvCsyc1QDTBWJ01PcTarx0judpa6ZuQ8
Because this is the secure websocket, I used this example
Successfully compiled with sudo g++ -v websocket_client_sync_ssl.o -o wsstest -lpthread -lboost_system -lcrypto -lssl
But no hope. Same result.. Error: resolve: Host not found (authoritative)
I feel like I am missing something pretty simple here. Could you help me out?!
Thanks!

How can I solve the "empty response" error using nghttp2?

I'm using nghttp2_asio. I compiled it using ./configure --enable-asio-lib. Then, I added /usr/local/lib to /etc/ld.so.conf file. The code is as follows:
#include "bits/stdc++.h"
#include "nghttp2/asio_http2_server.h"
using namespace std;
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
int main(int argc, char **argv) {
http2 srv;
srv.num_threads(4);
srv.handle("/", [](const request &req, const response &res) {
cout << req.uri().path << endl;
header_map headers;
headers.emplace("content-type", header_value{ "text/html", false });
res.write_head(200, headers);
res.end(file_generator("index.html"));
});
boost::system::error_code ec;
if (srv.listen_and_serve(ec, "localhost", "8080")) cerr << ec.message() << endl;
return 0;
}
When I try to open the browser (Chrome or Firefox) on http://localhost:8080, it give me the following error:
This page isn't working
localhost didn't send any data.
ERR_EMPTY_RESPONSE
Even if I try with curl, it gives me the error:
curl: (52) Empty reply from server
The only thing that works is curl http://localhost:8080 --http2-prior-knowledge.
Is there a solution for this?
It looks like your browser refuses to do HTTP/2 over an unencrypted connection. The Wikipedia page has the following to say:
Although the standard itself does not require usage of encryption,[51] all major client implementations (Firefox,[52] Chrome, Safari, Opera, IE, Edge) have stated that they will only support HTTP/2 over TLS, which makes encryption de facto mandatory.[53]
cURL has a different problem: it defaults to HTTP/1 which your HTTP/2 server does not understand. Adding the flag makes it use the HTTP/2 binary protocol directly. Alternatively, connecting to an HTTPS endpoint will automatically turn on HTTP/2.
See the libnghttp2_asio documentation for an example on how to serve with encryption:
int main(int argc, char *argv[]) {
boost::system::error_code ec;
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.use_private_key_file("server.key", boost::asio::ssl::context::pem);
tls.use_certificate_chain_file("server.crt");
configure_tls_context_easy(ec, tls);
http2 server;
// add server handlers here
if (server.listen_and_serve(ec, tls, "localhost", "3000")) {
std::cerr << "error: " << ec.message() << std::endl;
}
}

Socket validation using Poco c++ libraries

I'm working on an application that needs to perform network communication and decided to use the poco c++ libraries. After going through the network tutorial I can't seem to find any forms of validation on establishing a network connection.
In the following example a client tries to connect to a server using a tcp socket stream:
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/StreamCopier.h"
#include <iostream>
int main(int argc, char** argv)
{
Poco::Net::SocketAddress sa("www.appinf.com", 80);
Poco::Net::StreamSocket socket(sa);
Poco::Net::SocketStream str(socket);
str << "GET / HTTP/1.1\r\n"
"Host: www.appinf.com\r\n"
"\r\n";
str.flush();
Poco::StreamCopier::copyStream(str, std::cout);
return 0;
}
However, I couldn't find any information related to:
Error checking(what if www.appinf.com is unavailable or doesn't exist for that matter)
The type of exception these calls may raise
The only mention is that a SocketStream may hang if the receive timeout is not set for the socket when using formated inputs.
How can I check if a host is alive and may set up a tcp connection, implement a method such as:
void TCPClient::connectTo(std::string host, bool& connected, unsigned int port) {
std::string hi = "hi";
Poco::Net::SocketAddress clientSocketAddress(host, port);
Poco::Net::StreamSocket clientStreamSocket;
// try to connect and avoid hang by setting a timeout
clientStreamSocket.connect(clientSocketAddress, timeout);
// check if the connection has failed or not,
// set the connected parameter accordingly
// additionally try to send bytes over this connection
Poco::Net::SocketStream clientSocketStream(clientStreamSocket);
clientSocketStream << hi << std::endl;
clientSocketStream.flush();
// close the socket stream
clientSocketStream.close();
// close stream
clientStreamSocket.shutdown();
}

How to create a cookie with FastCGI (nginx) in C++

I'm creating a website in C++ using FastCGI on nginx. My problem is now to track a user (aka session). I can read the HTTP_COOKIE out, but I have no clue how I can create a new cookie with a name and a value and send this to the client.
Looking up in Google I only found relevant stuff for PHP, Python and other scriptlanguages that try to run with CGI/fCGI.
you can use setcookie syntax.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
int count = 0;
printf("Content-type: text/html\r\n"
"Set-Cookie: name=value\r\n"
"\r\n"
"<title>CGI Hello!</title>"
"<h1>CGI Hello!</h1>"
"Request number %d running on host <i>%s</i>\n",
++count, getenv("SERVER_NAME"));
return 0;
}

Sending an http get request to a website, ignoring the response with c++

I need to send a http get request using c++. My code as of now is:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main ()
{
ifstream llfile;
llfile.open("C:/AdobeRenderServerLog.txt");
if(!llfile.is_open()){
exit(EXIT_FAILURE);
}
char word[50];
llfile >> word;
cout << word;
llfile.close();
return 0;
}
The request would be something sent to:
www.example.com/logger.php?data=word
Possibly the easiest is to use libCurl.
Using the 'easy interface' you just call curl_easy_init(), then curl_easy_setopt() to set the url, then curl_easy_perform() to make it do the getting. If you want the response (or progress, etc) then set the appropriate properties in setopt(). Once you're all done, call curl_easy_cleanup(). Job done!
The documentation is comprehensive - it's not just a simple lib to get http requests, but does practically every network protocol. Realise that the doc therefore looks pretty complicated, but it isn't really.
It might be an idea to go straight to the example code, the simple one looks like this:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
but you might want to check out the 'get a file in memory' sample or the 'replace fopen' one as well.