How to use OpenSSL in POCO C++ library correctly - c++

According to the Specification in POCO assistant:
Initialize the NetSSL library, as well as the underlying OpenSSL
libraries, by calling Poco::Crypto::OpenSSLInitializer::initialize().
Should be called before using any class from the NetSSL library.
The NetSSL will be initialized automatically, through
Poco::Crypto::OpenSSLInitializer instances or similar mechanisms
when creating Context or SSLManager instances.
However, it is recommended to call initializeSSL()
in any case at application startup.
When I want to use HTTPSClientSession,do I have to construct an Application object first?
How can I use it in Client? Any guy can tell me ?Thank you very much!

Let's take Net/samples/httpget as an example, let's copy httpget/ as a new httpsget directory:
open Makefile, add "PocoNetSSL" to target_libs
replace 'HTTPClientSession' with 'HTTPSClientSession'
you need to create Poco::Net::Context for SSL use
replace 'HTTPClientSession session(uri.getHost(), uri.getPort());' with following two lines:
const Context::Ptr context = new Context(Context::CLIENT_USE, "", "", "", Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:#STRENGTH");
HTTPSClientSession session(uri.getHost(), uri.getPort(), context);
Summary:
add PocoNetSSL as a lib_depends
use Poco::Net::Context with HTTPSClientSession

No, you do not need the Application object. Here's a fully functional example:
$ httpsget https://httpbin.org/user-agent
{
"user-agent": "Poco HTTPSClientSession"
}
Code:
#include "Poco/StreamCopier.h"
#include "Poco/URI.h"
#include "Poco/Exception.h"
#include "Poco/SharedPtr.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/KeyConsoleHandler.h"
#include "Poco/Net/ConsoleCertificateHandler.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include <memory>
#include <iostream>
using namespace Poco;
using namespace Poco::Net;
class SSLInitializer {
public:
SSLInitializer() { Poco::Net::initializeSSL(); }
~SSLInitializer() { Poco::Net::uninitializeSSL(); }
};
int main(int argc, char** argv)
{
SSLInitializer sslInitializer;
SharedPtr<InvalidCertificateHandler> ptrCert = new ConsoleCertificateHandler(false);
Context::Ptr ptrContext = new Context(Context::CLIENT_USE, "", "", "rootcert.pem", Context::VERIFY_STRICT, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:#STRENGTH");
SSLManager::instance().initializeClient(0, ptrCert, ptrContext);
try
{
if (argc > 1)
{
URI uri(argv[1]);
HTTPSClientSession s(uri.getHost(), uri.getPort());
HTTPRequest request(HTTPRequest::HTTP_GET, uri.getPath());
request.set("user-agent", "Poco HTTPSClientSession");
s.sendRequest(request);
HTTPResponse response;
std::istream& rs = s.receiveResponse(response);
StreamCopier::copyStream(rs, std::cout);
}
}
catch (Exception& ex)
{
std::cout << ex.displayText() << std::endl;
return 1;
}
return 0;
}

Related

Poco failing to send mail

I have installed the Poco C++ library (Release 1.12.4) with vcpkg on my computer and I'm trying to send a simple Mail by using the sample delivered on the Github Page.`The script is compile with Visual Studio 17.
The full code:
#include "Poco/Net/MailMessage.h"
#include "Poco/Net/MailRecipient.h"
#include "Poco/Net/SecureSMTPClientSession.h"
#include "Poco/Net/StringPartSource.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/ConsoleCertificateHandler.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
#include "Poco/SharedPtr.h"
#include "Poco/Path.h"
#include "Poco/Exception.h"
#include <iostream>
using Poco::Net::MailMessage;
using Poco::Net::MailRecipient;
using Poco::Net::SMTPClientSession;
using Poco::Net::SecureSMTPClientSession;
using Poco::Net::StringPartSource;
using Poco::Net::SSLManager;
using Poco::Net::Context;
using Poco::Net::InvalidCertificateHandler;
using Poco::Net::ConsoleCertificateHandler;
using Poco::SharedPtr;
using Poco::Path;
using Poco::Exception;
using Poco::UInt16;
using namespace std;
class SSLInitializer
{
public:
SSLInitializer()
{
Poco::Net::initializeSSL();
}
~SSLInitializer()
{
Poco::Net::uninitializeSSL();
}
};
int main()
{
SSLInitializer sslInitializer;
std::string mailhost("smtp.office365.com");
std::string recipient("recipient#gmail.com");
std::string username("MyMail#gmail.com");
std::string password("MyPassword");
Poco:UInt16 port = 587;
try
{
// Note: we must create the passphrase handler prior Context
SharedPtr<InvalidCertificateHandler> pCert = new ConsoleCertificateHandler(false); // ask the user via console
Context::Ptr pContext = new Context(Context::CLIENT_USE, "");
SSLManager::instance().initializeClient(0, pCert, pContext);
MailMessage message;
message.addRecipient(MailRecipient(MailRecipient::PRIMARY_RECIPIENT, recipient));
message.setSubject("Hello from the POCO C++ Libraries");
std::string content;
content += "Hello ";
content += recipient;
content += ",\r\n\r\n";
content += "This is a greeting from the POCO C++ Libraries.\r\n\r\n";
message.addContent(new StringPartSource(content));
SecureSMTPClientSession session(mailhost, port);
session.login();
session.startTLS(pContext);
if (!username.empty())
{
session.login(SMTPClientSession::AUTH_LOGIN, username, password);
}
session.sendMessage(message);
session.close();
}
catch (Exception& exc)
{
std::cerr << exc.displayText() << std::endl;
return 1;
}
return 0;
}
I already tried the code on my first computer and it works. I wanted to try it on my laptop but it raises following error:
Poco::Net::NoCertificateException
and after a while:
SSL Exception: Error during handshake: failed to read data
I located the error and it comes from this line:
session.startTLS(pContext);
Thank you for helping me!
P.S: I don't use OpenSSL but NetSSL_Win, an implementation of the POCO NetSSL library based on Windows Schannel.

How to play with spdlog?

I downloaded and followed the example 1.
Moved to example 2 (Create stdout/stderr logger object) and got stuck. Actually I can run it as it is but if I change
spdlog::get("console") to spdlog::get("err_logger") it crashes.
Am I supposed to change it like that?
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example()
{
// create color multi threaded logger
auto console = spdlog::stdout_color_mt("console");
auto err_logger = spdlog::stderr_color_mt("stderr");
spdlog::get("err_logger")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}
int main()
{
stdout_example();
return 0;
}
I also tried Basic file logger example:
#include <iostream>
#include "spdlog/sinks/basic_file_sink.h"
void basic_logfile_example()
{
try
{
auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
}
catch (const spdlog::spdlog_ex &ex)
{
std::cout << "Log init failed: " << ex.what() << std::endl;
}
}
int main()
{
basic_logfile_example();
return 0;
}
And I see it creates basic-log.txt file but there is nothing on it.
Because you need to register err_logger logger first. There is no default err_logger as far as I know. spdlog::get() returns logger based on its registered name, not variable.
You need a code like this. Code is complex and you may not need all of it though:
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"
void multi_sink_example2()
{
spdlog::init_thread_pool(8192, 1);
auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >();
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3);
std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink};
auto logger = std::make_shared<spdlog::async_logger>("err_logger", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
spdlog::register_logger(logger); //<-- this line registers logger for spdlog::get
}
and after this code, you can use spdlog::get("err_logger").
You can read about creating and registering loggers here.
I think spdlog::stderr_color_mt("stderr"); registers logger with name stderr so spdlog::get("stderr") may work, but have not tested myself.

Json output into single line

Question:
With below sample code, able to create a json string and print as below, my requirements is to print into a single line(below as well) with no space or tab, can i do it using boost or need to explicitly remove from string.
#include "boost/property_tree/json_parser.hpp"
#include <boost/property_tree/ptree.hpp>
#include <sstream>
#include <iostream>
int main()
{
boost::property_tree::ptree root;
root.put("sessionId", "123456");
root.put("applicationName", "Sample_Appliation");
root.put("applicationId", "null");
root.put("logMessage", "Sample Message");
root.put("loggingTime", "2020-03-17T13:26:45.013");
std::stringstream ss;
boost::property_tree::write_json(ss, root);
std::cout << ss.str() << std::endl;
return 0;
}
Output:
{
"sessionId": "123456",
"applicationName": "Sample_Appliation",
"applicationId": "null",
"logMessage": "Sample Message",
"loggingTime": "2020-03-17T13:26:45.013"
}
Expected:
{"sessionId": "123456","applicationName": "Sample_Appliation","applicationId": "null","logMessage": "Sample Message","loggingTime": "2020-03-17T13:26:45.013"}
There is a third parameter to boost::property_tree::write_json named pretty with default value true, just pass false as a third parameter to disable pretty printing.
Big caution: Boost PropertyTree Is Not A JSON Library. However, as luck would have it, Boost has recently adopted the new JSON library, which actually does the job:
Live On Compiler Explorer
#include <boost/json.hpp>
#include <iostream>
int main() {
auto json = boost::json::parse(R"(
{
"sessionId": "123456",
"applicationName": "Sample_Appliation",
"applicationId": "null",
"logMessage": "Sample Message",
"loggingTime": "2020-03-17T13:26:45.013"
})");
std::cout << json;
}
Prints
{"sessionId":"123456","applicationName":"Sample_Appliation","applicationId":"null","logMessage":"Sample Message","loggingTime":"2020-03-17T13:26:45.013"}

Is this code correct to send logs to remote syslog server using log4cplus?

Can someone please tell me if this is correct way of using SysLogAppender of log4cplus ? I did not find a proper example for log4cplus. I need to send numerous logs to remote syslog server.
main.cpp
int main()
{
SysLogHelper syslogHelper;
int errCode = syslogHelper.initialize("172.16.72.239");
errCode = syslogHelper.sendLogstoSyslog("send testing log");
// I need to send numerous logs to syslog
}
syslog.cpp
#include <log4cplus/syslogappender.h>
#include <log4cplus/spi/loggingevent.h>
#include <log4cplus/logger.h>
class SysLogHelper
{
string hostname;
log4cplus::SysLogAppender *syslogAppender;
// is it necessary to create a pointer? I am not able to use log4cplus in a class without creating a pointer? Is there any other way?
log4cplus::spi::InternalLoggingEvent syslogLoggingEvent;
public:
SysLogHelper();
int initialize(string hostname);
int sendLogstoSyslog(string message);
};
SysLogHelper::SysLogHelper()
{
hostname = "";
syslogAppender = NULL;
}
int SysLogHelper::initialize(string hostname)
{
syslogAppender = new log4cplus::SysLogAppender("ident", hostname);
//I am not getting what is "ident" here? what input is expected?
return 0;
}
int SysLogHelper::sendLogstoSyslog(string message)
{
syslogLoggingEvent.setLoggingEvent(
log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("test")).getName(),
log4cplus::FATAL_LOG_LEVEL, LOG4CPLUS_TEXT(message),__FILE__,
__LINE__, "main");
syslogAppender->doAppend(syslogLoggingEvent);
//Is this correct method of sending logs to syslog?
return 0;
}
questions:
I am able to send logs to remote syslog using above code. But is this correct way to use log4cplus APIs? Questions are given in the form of comments in above code example.
Why do we need to use log4cplus::initializer? I am not able to import log4cplus/initializer.h in my code.
In my opinion the phylosophy at the base of Log4cplus library is that you can have in your application one or more logger and for each logger you can have one or more output, called "appender". Inside your application you have to manage with logger and you don't have care which appender are linked to the logger. This is clear, for example, if you use a property file to config and to tune your logger.
By the way here in the following I show what I have done to configure syslog inside my application in both cases:
configuring syslog appender inside the code:
#include <log4cplus/logger.h>
#include <log4cplus/fileappender.h>
#include <log4cplus/syslogappender.h>
#include <log4cplus/layout.h>
#include <log4cplus/ndc.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/configurator.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/fileinfo.h>
#include <TCHAR.h>
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
using namespace log4cplus;
int main()
{
log4cplus::initialize ();
Logger root = Logger::getRoot();
// log level INFO: you don't see TRACE and DEBUG on your syslogserver
root.setLogLevel(log4cplus::INFO_LOG_LEVEL);
SharedObjectPtr<Appender> ptrSys(
new SysLogAppender(
_T("mysyslog"),
_T("localhost"),
514,
_T("user"))) ;
root.addAppender(ptrSys);
for(int i=0; i<100; ++i)
{
LOG4CPLUS_TRACE(root, LOG4CPLUS_TEXT("Error log test")); //not visible
LOG4CPLUS_DEBUG(root, LOG4CPLUS_TEXT("Debug log test")); //not visible
LOG4CPLUS_INFO(root, LOG4CPLUS_TEXT("Info log test"));
LOG4CPLUS_WARN(root, LOG4CPLUS_TEXT("Warning log test"));
LOG4CPLUS_ERROR(root, LOG4CPLUS_TEXT("Error log test"));
}
log4cplus::Logger::shutdown();
return 0;
}
As I said the way, that I prefer, is by configuration file, called here configlog.properties
#include <log4cplus/logger.h>
#include <log4cplus/fileappender.h>
#include <log4cplus/syslogappender.h>
#include <log4cplus/layout.h>
#include <log4cplus/ndc.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/configurator.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/fileinfo.h>
#include <TCHAR.h>
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
using namespace log4cplus;
log4cplus::tstring getPropertiesFileArgument (std::wstring argv)
{
log4cplus::tstring file = LOG4CPLUS_C_STR_TO_TSTRING (argv);
log4cplus::helpers::FileInfo fi;
if (getFileInfo (&fi, file) == 0)
return file;
return LOG4CPLUS_TEXT ("log4cplus.properties");
}
int main()
{
log4cplus::initialize ();
PropertyConfigurator::doConfigure( getPropertiesFileArgument(_T("c:\\ConfigLog.properties")));
Logger root = Logger::getRoot();
for(int i=0; i<100; ++i) {
LOG4CPLUS_TRACE(root, LOG4CPLUS_TEXT("Error log test"));
LOG4CPLUS_DEBUG(root, LOG4CPLUS_TEXT("Debug log test"));
LOG4CPLUS_INFO(root, LOG4CPLUS_TEXT("Info log test"));
LOG4CPLUS_WARN(root, LOG4CPLUS_TEXT("Warning log test"));
LOG4CPLUS_ERROR(root, LOG4CPLUS_TEXT("Error log test"));
}
log4cplus::Logger::shutdown();
return 0;
}
the configlog.properties file is something like this
log4cplus.rootLogger=INFO, syslog
log4cplus.appender.syslog=log4cplus::SysLogAppender
log4cplus.appender.syslog.ident=syslog
log4cplus.appender.syslog.layout=log4cplus::PatternLayout
log4cplus.appender.syslog.layout.ConversionPattern=[%T] %-5p %b %x - %m%n
log4cplus.appender.syslog.host=localhost
log4cplus.appender.syslog.udp=true
log4cplus.appender.syslog.port=514
log4cplus.appender.syslog.facility=user
I hope to be not too in late and I hope this can be helpful for you

Pantheios write to extenal file

I looked around and I couldn't find the answer to how exactly to do this. I am trying to use Pantheios for logging and I want to write to an external file (otherwise whats the point). I am following one of the examples provided but It doesn't seem to be making the log file anywhere. Here is the code:
Edit: Also pantheios_be_file_setFilePath is returning -4 (PANTHEIOS_INIT_RC_UNSPECIFIED_FAILURE) so thats.....not helpful
#include "stdafx.h"
#include <pantheios/pantheios.hpp>
#include <pantheios/implicit_link/core.h>
#include <pantheios/implicit_link/fe.simple.h>
#include <pantheios/implicit_link/be.WindowsConsole.h>
#include <pantheios/implicit_link/be.file.h>
#include <pantheios/frontends/fe.simple.h>
#include <pantheios/backends/bec.file.h>
#include <pantheios/inserters/args.hpp>
PANTHEIOS_EXTERN_C const PAN_CHAR_T PANTHEIOS_FE_PROCESS_IDENTITY[] = PANTHEIOS_LITERAL_STRING("LogTest");
int _tmain(int argc, _TCHAR* argv[])
{
try
{
pantheios_be_file_setFilePath(PANTHEIOS_LITERAL_STRING("testlogforme.log"), PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BEID_ALL);
pantheios::log(pantheios::debug, "Entering main(", pantheios::args(argc,argv, pantheios::args::arg0FileOnly), ")");
pantheios::log_DEBUG("debug yo");
pantheios::log_INFORMATIONAL("informational fyi");
pantheios::log_NOTICE("notice me!");
pantheios::log_WARNING("warning!!");
pantheios::log_ERROR("error omg");
pantheios::log_CRITICAL("critical!!!");
pantheios::log_ALERT("alert mang");
pantheios::log_EMERGENCY("EMERGENCY!!!!!");
pantheios_be_file_setFilePath(NULL, PANTHEIOS_BEID_ALL);
system("pause");
return EXIT_SUCCESS;
}
catch(std::bad_alloc&)
{
pantheios::log_ALERT("out of memory");
}
catch(std::exception& x)
{
pantheios::log_CRITICAL("Exception: ", x);
}
catch(...)
{
pantheios::puts(pantheios::emergency, "Unexpected unknown error");
}
return EXIT_FAILURE;
}
Maybe I'm not calling a method or maybe its not being saved to a good location?
It turns out that some of the examples out there for pantheios are incorrect. You DO need to call pantheios_init() even if you are in C++. Here Is the example I got to work after deleting all my code and implementing an example that works.
// Headers for main()
#include <pantheios/pantheios.hpp>
#include <pantheios/backends/bec.file.h>
// Headers for implicit linking
#include <pantheios/implicit_link/core.h>
#include <pantheios/implicit_link/fe.simple.h>
#include <pantheios/implicit_link/be.file.h>
PANTHEIOS_EXTERN_C const char PANTHEIOS_FE_PROCESS_IDENTITY[] = "testLOL";
int main()
{
if(pantheios::pantheios_init() < 0)
{
return 1;
}
pantheios::log_NOTICE("log-1"); // save until log file set
pantheios_be_file_setFilePath("mylogfile.log"); // sets log file; write "log-1" stmt
pantheios::log_NOTICE("log-2"); // write "log-2" stmt
pantheios_be_file_setFilePath(NULL); // close "mylogfile"
pantheios::log_NOTICE("log-3"); // save until log file set
pantheios_be_file_setFilePath("mylogfile2.log"); // sets log file; write "log-3" stmt
pantheios::log_NOTICE("log-4"); // write "log-4" stmt
//system("pause");
return 0;
} // closes "mylogfile2" during program closedown
I found the example on a different post on stack overflow but like I said, the built in examples do not work.