I have a Xilinx ZCU106 with a Petalinux build I created that includes an application using SignalR-Client-Cpp. Despite trying a number of things, I'm continually getting an "Error in SSL handshake" exception after calling start() on my signalr::hub_connection.
This application runs fine on other Linux systems like Ubuntu. I think the problem is it's having trouble finding the ca-certificates.crt file which is usually in /usr/local/ssl on more normal Linux distro's like Ubuntu. In the Petalinux build it's located here: /etc/ssl/certs/ca-certificates.crt.
The best I can tell, I need to do something like this to configure the signalr::hub_connection to use the certificate file:
web::http::client::http_client_config httpConfig;
httpConfig.set_ssl_context_callback([](boost::asio::ssl::context& ctx) {
ctx.load_verify_file("/etc/ssl/certs/ca-certificates.crt"); });
web::websockets::client::websocket_client_config wsConfig;
wsConfig.set_ssl_context_callback([](boost::asio::ssl::context& ctx) {
ctx.load_verify_file("/etc/ssl/certs/ca-certificates.crt"); });
signalr::signalr_client_config signalrConfig;
signalrConfig.set_http_client_config(httpConfig);
signalrConfig.set_websocket_client_config(wsConfig);
auto hubConn = signalr::hub_connection_builder::create(signalrURI).build();
hubConn.set_client_config(signalrConfig);
std::promise<void> task;
hubConn.start([&task](std::exception_ptr exception) {
// Code that checks the exception, etc
Yet, even when doing this, the exception that is passed into start() is populated, stating "Error in SSL handshake".
I've tried some other things like using web::credentials and setting those on the signalr_client_config before giving it to the hub_connection but I get the same results.
I'm out of ideas as to how to get this to work and I'm hoping someone else might have some ideas?
Related
I am using the example from boost with three minor differences:
I use threads to process io_service
I have limited the protocol to > TLS v1.1
There is no password callback, because the cert key has no password
The threads simply process various connections in parallel
void server::start()
{
for (std::size_t i = 0; i < thread_pool_size_; i++) {
threads_.push_back(std::thread([&]() {
io_service_.run();
}));
}
for (auto & t : threads_) {
t.join();
}
}
The context arguments are:
ctx.set_options(boost::asio::ssl::context::default_workarounds
|boost::asio::ssl::context::no_sslv2
|boost::asio::ssl::context::no_sslv3
|boost::asio::ssl::context::no_tlsv1
|boost::asio::ssl::context::no_tlsv1_1
|boost::asio::ssl::context::single_dh_use);
Apart from that, a connection class controls internally a ssl_socket,
which follows the following callback chain:
ctor
-> start
-> async_handshake
-> read_header
-> async_read_until
-> process_header
...
If I replace the SSL socket with a plaintext socket ip::tcp::socket then everything works fine.
When using the SSL socket, I keep getting called a function you should not call.
GDB shows that this originates from async_handshake. After reading this SO post I managed to obtain the error code:
(20,197,66) error:140C5042:SSL routines:ssl_undefined_function:called a function you should not call.
I'm using Boost 1.58 on Ubuntu 16.04.
Any help as to why this is happening, what might be causing it, or what I could possibly have done wrong?
If it matters, I am testing with curl using the -insecure flag.
EDIT
Did try without the restrictive protocol flags, and by setting a password callback - problem still persists.
Seems that the following line triggers the problem:
context_(io_service, boost::asio::ssl::context::tlsv12_client)
I should have paid more attention to my code (copy-paste is the root of all evil):
The offending line was in the context constructor:
ctx_(io_service, boost::asio::ssl::context::tlsv12_client)
I've replaced with the server version:
context_(io_service, boost::asio::ssl::context::tlsv12_server)
The full list is hidden in the implementation header of boost.
Insert big facepalm here :-)
I have a small C++ project and need to access a mySQL DB from it, so i have setup mySQL Connector for C++.
This is done on OS X 10.10, and i got no problems with the compilation/linking.
I have written a class for all the mysql stuff, and in the constructor i want to setup the connection to the db. However, this seems to be kinda hard.
Here is the relevant part from the class:
class mysql{
public:
mysql(std::string server, std::string user, std::string password);
private:
sql::mysql::MySQL_Driver *driver;
sql::Connection *con;
std::string last_error = "";
};
And here the implementation:
mysql::mysql(std::string server, std::string user, std::string password){
driver = sql::mysql::get_mysql_driver_instance();
try{
con = driver->connect(server, user, password);
last_error = "";
}
catch(sql::SQLException &e){
last_error = e.what();
}
}
However, when i create an object of that class like this:
mysql db("tcp://127.0.0.1:3306", "root", "secretsecret");
I then have this in my last_error string:
Unknown MySQL server host '???' (0)
The "host" sometimes differs even tho i dont change it in code. This seems like internally a different memory location is read out as it should be.
But even if i pass the connect() variables directly when i call it, i get this error. Same when saving those three variables internally in the mysql class and use those to call connect().
Anyone has an idea what could cause this? I have a similar implementation in a different project where this does work fine so im kinda confused :/
Here is a post that matches to your circumstances (The C++ connector works on linux and fails on OSX).
With using mysql logging/tracing or running it in debugger, you may be able to gather more information to report to mysql developers. You may have better luck.
After a long time of googeling i found this the most useful link: https://apple.stackexchange.com/questions/251290/weird-behaviour-of-mysql-connector-c-in-osx
Following the hints there, i recompiled the myscl c connector and then the mysql c++ connector (version 1.1.6 cause 1.1.7 caused a json error while compiling).
I also saw in the cmake logs of the c++ connector that Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ was used to compile the library.
So i used that one too for my compilation. It could be that this would work, tho im also including wxwisgeds in my project resulting in this error:
/usr/local/include/wx-3.0/wx/strvararg.h:30:18: fatal error: 'tr1/type_traits' file not found
#include <tr1/type_traits>
I found some hints for that one but they all just produced a massiv amount of new errors, so i stopped digging deeper here.
My best options would be to create two seperate programs, on to communicate with mysql and one to provide the gui and let them both communicate with each other either via sockets or files providing a very inefficient access to a mysql db.
Good luck to anyone who runs into the same thing..
I'm starting to use Boost, so may be I'm messing something up.
I'm trying to set up http server with boost (ASIO). I've taken the code from docs: http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/examples/cpp03_examples.html (HTTP Server, the first one)
The only difference from the example is I'm running server by my own method "run" and starting io_service in background thread, like in the docs: http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/io_service.html
boost::asio::io_service::work work(io_service_);
(Also I'm stopping io_service from my run method too.)
When I'm starting this modified server everything seems to be OK, run method is working fine. But then I'm trying to get a doc from the server the request hangs and control flow never comes to "request_handle" method.
Am I missing something?
UPD. Here is my code of run method:
void NetstreamServer::run()
{
LOG4CPLUS_DEBUG(logger, "NetstreamServer is running");
boost::asio::io_service::work work(io_service_);
try
{
while (true)
{
if (condition)
{
io_service_.stop();
break;
}
}
}
catch (std::exception const& e)
{
LOG4CPLUS_ERROR(logger, "NetstreamServer" << " caught exception: " << e.what());
}
}
You should call io_service_::run() - otherwise no one will dispatch the completion handlers of Asio objects serviced by io_service_.
Without including the code you changed, everyone here can only guess. Unfortunately you also do not include the compiler and the OS you are using. Even with boost claiming it is platform independent, you should always include this information, as it reality, platforms are different even with boost.
Let me do a guess. You use Microsoft Windows? How do you prevent the "main" function to exit? You moved the blocking "run" function out of it in another thread, the main function has no wait point anymore. Let me guess again, you used something like "getchar". With that, you can exit your server with only hitting the keyboard return key. If yes, the problem is the getchar, with unfortunately blocks every io of the asio socket implementation, but only on Windows based systems.
I would not need to guess if you would include the informations mentioned in your post. In particular all(!) changes you made to the code sample.
Using custom C++ OCI wrappers, I can successful register a CQN C++ callback-based registration, but it appears that somehow the subscription is dropped right away, behind my back. I get no call back on simple DMLs. If I try to unregister that subscription, for which register() worked just fine, I get ORA-29970: Specified registration id does not exist.
I'm running this test on a Win7 (64-bit) box, running a local 11.2.0.1.0 Oracle Server, and I connect with a C++ client app built against instantclient-11.2.0.2.0 that runs on that same machine.
I tried setting OCI_ATTR_SUBSCR_TIMEOUT explicitly to 0, to no avail.
I checked the job_queue_processes instance param to make sure it's not 0 (it's 1000).
Of course, the user/schema I'm connecting with has been granted CHANGE NOTIFICATION
I'm running out of ideas on this issue, and I would appreciate some insights on what else I could try or check.
I'm starting to wonder if CQN needs to be activated somehow. My DBA skills are close to nonexistent, this is a stock install of 11gR1 on Windows using the installer, with no special configurations or customization done at all.
Thanks, --DD
Update #1
A colleague successfully ran that same test, and he ran it using the server-provided oci.dll. I tried that (I build using instantclient, but forced the PATH at runtime: Path=D:\oracle\product\11.2.0\dbhome_1\BIN;$(Path) in VS Property Page> Debugging> Environment), and indeed the CQN test works! We still haven't figured out whether the slight version difference between client and server, or using instantclient (the Light variant by the way) vs a full client vs a server install is the real culprit.
But it is bad news that a newer instantclient does not support CQN...
Update #2
I've tried all 6 combinations of instantclient Light (65 MB) or Normal (150 MB) in versions 12.2.0.(1|2|3).0 on Win64, and none of them worked. Haven't tested the Full Client yet, nor have we tested on Linux just yet.
Environment_var cqn_env = Environment::create(OCI_EVENTS + OCI_OBJECT);
Connection_var cqn_conn = Connection::logon2(...);
Subscription sub(cqn_conn, "cqn_test", OCI_SUBSCR_NAMESPACE_DBCHANGE);
sub.set<attr::SUBSCR_CALLBACK>( &cqn_callback_func );
sub.set<attr::SUBSCR_CQ_QOSFLAGS>( OCI_SUBSCR_CQ_QOS_QUERY );
try {
sub.register_self();
} catch (const OracleException& ex) {
BOOST_REQUIRE(ex.error_code && *ex.error_code == 29972);
cerr << "\nSKIPPED: test requires CHANGE NOTIFICATION privilege" << endl;
return;
}
I have a server application which I am debugging which basically parses scripts (VBscript, Python, Jscript and SQl) for the application that requests it.
This is a very critical application which, if it crashes causes havoc for a lot of users. The problem I am facing is how to handle exceptions so that the application can continue and the users know if something is wrong in their scripts.
An example: In the SQL scripts the application normally returns a set of values (Date, Number, String and Number). So the scripts have to have a statement at the end as such:
into dtDate, Number, Number, sString. These are values that are built into the application and the server application knows how to interpret these. These fields are treated in the server app as part of an array. The return values should normally be in a specific order as the indexes for these fields into the array are hardcoded inside the server application.
Now when a user writing a script forgets one of these fields, then the last field (normally string) throws an IndexOutofBoundsException.
The question is how does one recover from exceptions of this nature without taking down the application?
Another example is an error in a script for which no error parsing message can be generated. These errors just disappear in the background in the application and eventually cause the server app to crash. The scripts on which it fails don't necessarily fail to execute entirely, but part of it doesn't execute and the other parts do, which makes it look fairly odd to a user.
This server app is a native C++ application and uses COM technologies.
I was wondering if anyone has any ideas on what the best way is to handle exceptions such as the ones described above without crashing the application??
You can't handle problems like this with exceptions. You could have a top-level catch block that catches the exception and hope that not too much state of the program got irrecoverably munched to try to keep the program alive. Still doesn't make the user happy, that query she is waiting for still doesn't run.
Ensuring that changes don't destabilize a critical business app requires organization. People that sign-off on the changes and verify that they work as intended before it is allowed into production. QA.
since you talk about parsing different languages, you probably have something like
class IParser //parser interface
{
virtual bool Parse( File& fileToParse, String& errMessage ) = 0;
};
class VBParser : public Parser
class SQLParser : public Parser
Suppose the Parse() method throws an exception that is not handled, your entire app crashes. Here's a simplified example how this could be fixed at the application level:
//somewhere main server code
void ParseFileForClient( File& fileToParse )
{
try
{
String err;
if( !currentParser->Parse( fileToParse, err ) )
ReportErrorToUser( err );
else
//process parser result
}
catch( std::exception& e )
{
ReportErrorToUser( FormatExceptionMessage( err ) );
}
catch( ... )
{
ReportErrorToUser( "parser X threw unknown exception; parsing aborted" );
}
}
If you know an operation can throw an exception, then you need to add exception handling to this area.
Basically, you need to write the code in an exception safe manner which usually uses the following guidelines
Work on temporary values that can throw exceptions
Commit the changes using the temp values after (usually this will not throw an exception)
If an exception is thrown while working on the temp values, nothing gets corrupted and in the exception handling you can manage the situation and recover.
http://www.gotw.ca/gotw/056.htm
http://www.gotw.ca/gotw/082.htm
It really depends on how long it takes to start up your server application. It may be safer to let the application crash and then reload it. Or taking a cue from Chrome browser run different parts of your application in different processes that can crash. If you can safely recover an exception and trust that your application state is ok then fine do it. However catching std::exception and continuing can be risky.
There are simple to complex ways to baby sit processes to make sure if they crash they can be restarted. A couple of tools I use.
bluepill http://asemanfar.com/Bluepill:-a-new-process-monitoring-tool
pacemaker http://www.clusterlabs.org/
For simple exceptions that can happen inside your program due to user errors,
simply save the state that can be changed, and restore it like this:
SaveStateThatCanBeAlteredByScript();
try {
LoadScript();
} catch(std::exception& e){
RestoreSavedState();
ReportErrorToUser(e);
}
FreeSavedState();
If you want to prevent external code from crashing (possible untrustable code like plugins), you need an IPC scheme. On Windows, I think you can memory map files with OpenFile(). On POSIX-systems you can use sem_open() together with mmap().
If you have a server. You basically have a main loop that waits for a signal to start up a job. The signal could be nothing and your server just goes through a list of files on the file system or it could be more like a web server where it waits for a connection and executes the script provided on the connection (or any thing like that).
MainLoop()
{
while(job = jobList.getJob())
{
job.execute();
}
}
To stop the server from crashing because of the scripts you need to encapsulate the external jobs in a protected region.
MainLoop()
{
// Don't bother to catch exceptions from here.
// This probably means you have a programming error in the server.
while(job = jobList.getJob())
{
// Catch exception from job.execute()
// as these exceptions are generally caused by the script.
try
{
job.execute();
}
catch(MyServerException const& e)
{
// Something went wrong with the server not the script.
// You need to stop. So let the exception propagate.
throw;
}
catch(std::exception const& e)
{
log(job, e.what());
}
catch(...)
{
log(job, "Unknown exception!");
}
}
}
If the server is critical to your operation then just detecting the problem and logging it is not always enough. A badly written server will crash so you want to automate the recovery. So you should write some form of heartbeat processes that checks at regular intervals if the processes has crashed and if it has automatically restart it.