autobahn-cpp icon indicating copy to clipboard operation
autobahn-cpp copied to clipboard

Add secure RawSocket example

Open Bobface opened this issue 8 years ago • 15 comments

Hello,

can I somehow connect to Secure WebSocket Servers (wss://)? I can't find a solution in the documentation.

Bobface avatar Dec 26 '15 00:12 Bobface

Not as of now.

@davidchappelle has patches that might be merged into autobahn-cpp which generalize the transport interface. Theoretically this means that after these get merged, you could add a WebSocket transport yourself.

I'm not aware of any code that actually implements WebSockets from autobahn-cpp yet, though. (It might pop up in the future, or it might not.)

jpetso avatar Jan 15 '16 01:01 jpetso

If you mean: WAMP-RawSocket over TLS .. that should work already. We need an example though.

If you specifically mean WAMP-WebSocket over TLS, as @jpetso notes, there has to be a proper transport abstraction first.

Second is adding WebSocket transport as one option - and that based on https://github.com/zaphoyd/websocketpp

Once that is done, secure WebSocket comes free, as websocketpp supports that.

oberstet avatar Jan 28 '16 18:01 oberstet

If anyone is looking to add websocket support to autobahn-cpp, please connect with me as all of the transport abstraction work is already done. It just needs to be broken up into smaller commits and merged back to the master branch.

On Thu, Jan 28, 2016 at 1:06 PM, Tobias Oberstein [email protected] wrote:

If you mean: WAMP-RawSocket over TLS .. that should work already. We need an example though.

If you specifically mean WAMP-WebSocket over TLS, as @jpetso https://github.com/jpetso notes, there has to be a proper transport abstraction first.

Second is adding WebSocket transport as one option - and that based on https://github.com/zaphoyd/websocketpp

Once that is done, secure WebSocket comes free, as websocketpp supports that.

— Reply to this email directly or view it on GitHub https://github.com/crossbario/autobahn-cpp/issues/72#issuecomment-176309592 .

davidchappelle avatar Jan 28 '16 18:01 davidchappelle

With the way that the abstraction was done, I would expect it to be fairly trivial to add websocket support.

On Thu, Jan 28, 2016 at 1:08 PM, David Chappelle [email protected] wrote:

If anyone is looking to add websocket support to autobahn-cpp, please connect with me as all of the transport abstraction work is already done. It just needs to be broken up into smaller commits and merged back to the master branch.

On Thu, Jan 28, 2016 at 1:06 PM, Tobias Oberstein < [email protected]> wrote:

If you mean: WAMP-RawSocket over TLS .. that should work already. We need an example though.

If you specifically mean WAMP-WebSocket over TLS, as @jpetso https://github.com/jpetso notes, there has to be a proper transport abstraction first.

Second is adding WebSocket transport as one option - and that based on https://github.com/zaphoyd/websocketpp

Once that is done, secure WebSocket comes free, as websocketpp supports that.

— Reply to this email directly or view it on GitHub https://github.com/crossbario/autobahn-cpp/issues/72#issuecomment-176309592 .

davidchappelle avatar Jan 28 '16 18:01 davidchappelle

Tested wss:// with websocket transport, works as expected.

Tested with the following setup:

Crossbar.io router behind AWS ELB (SSL 443 -> TCP PVT Port)

#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>

typedef websocketpp::client<websocketpp::config::asio_tls_client> websocket_client;
typedef autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> websocket_transport;

Configure TLS init handler for Websocket client

    websocket_client client;
    client.set_tls_init_handler([this](websocketpp::connection_hdl) {
        return websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
    });
    transport = std::make_shared < autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> >(
        client, "wss://host.domain.com");

DZabavchik avatar Mar 09 '16 22:03 DZabavchik

@DZabavchik Nice. Thanks for leaving code/comments for WS example here!

oberstet avatar Mar 11 '16 14:03 oberstet

Hi,

Does current autobahn-cpp code works with wss:// ? Or some patches still be needed. I've tried something like this:

` #include <websocketpp/config/asio_client.hpp> #include <websocketpp/client.hpp>

typedef websocketpp::clientwebsocketpp::config::asio_tls_client client; typedef autobahn::wamp_websocketpp_websocket_transportwebsocketpp::config::asio_tls_clientwebsocket_transport;

    client ws_clinet;
    ws_clinet.set_tls_init_handler([&](websocketpp::connection_hdl) {
            return websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
    });
    ws_clinet.init_asio(&io);

    auto transport = std::make_shared < autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> >(
        ws_clinet, "wss://127.0.0.1:8443/ws", debug);

`

, but without success (however it works with autobahn-python). The error is:

Connecting to realm: realm1 starting io service [2016-07-16 18:39:21] [info] Error getting remote endpoint: system:107 (Transport endpoint is not connected) [2016-07-16 18:39:21] [fail] WebSocket Connection Unknown - "" /ws 0 websocketpp.transport:9 Timer Expired [2016-07-16 18:39:21] [error] handle_connect error: Timer Expired [2016-07-16 18:39:21] [info] asio async_shutdown error: asio.ssl:336462100 (uninitialized) stopped io service failed to connect

Any suggestions? Could you probably to show full example?

Thanks!

sashakh avatar Jul 16 '16 15:07 sashakh

Autobahn-cpp does work with wss://

Since you are connecting to wss://localhost I assume you are using self-signed certificate.

You may need to add your CA cert to trusted root CA file.

Regards,

Denis

On Jul 16, 2016, at 20:59, Sasha Khapyorsky [email protected] wrote:

Hi,

Does current autobahn-cpp code works with wss:// ? Or some patches still be needed. I've tried something like this:

` #include #include

typedef websocketpp::clientwebsocketpp::config::asio_tls_client client; typedef autobahn::wamp_websocketpp_websocket_transportwebsocketpp::config::asio_tls_clientwebsocket_transport;

client ws_clinet;
ws_clinet.set_tls_init_handler([&](websocketpp::connection_hdl) {
        return websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
});
ws_clinet.init_asio(&io);

auto transport = std::make_shared < autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> >(
    ws_clinet, "wss://127.0.0.1:8443/ws", debug);

`

, but without success (however it works with autobahn-python). The error is:

Connecting to realm: realm1 starting io service [2016-07-16 18:39:21] [info] Error getting remote endpoint: system:107 (Transport endpoint is not connected) [2016-07-16 18:39:21] [fail] WebSocket Connection Unknown - "" /ws 0 websocketpp.transport:9 Timer Expired [2016-07-16 18:39:21] [error] handle_connect error: Timer Expired [2016-07-16 18:39:21] [info] asio async_shutdown error: asio.ssl:336462100 (uninitialized) stopped io service failed to connect

Any suggestions? Could you probably to show full example?

Thanks!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

DZabavchik avatar Jul 16 '16 17:07 DZabavchik

Thanks for the quick replay Denis,

Actually I'm not using localhost (just placed this name in the example). Also it works without any problem with autobahn-python, but doesn't with autobahn-cpp.

Probably it is some mess with types. For instance I cannot see where:

typedef autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> websocket_transport;

is used.

Maybe you have some simple example (like wss_publish.cpp or so?

Many Thanks, Sasha

sashakh avatar Jul 16 '16 17:07 sashakh

Typedef is just not used. You could do:

auto transport = std::make_shared < websocket_transport >(ws_client, "wss://host/ws");

Any chance TLSv1 is disabled on the server? Can you run Crossbar with debug logging and see what server says when you try to connect? How do you initialize OpenSSL library (ciphers, algos and CA file).

Some related issues:
https://github.com/zaphoyd/websocketpp/issues/263 https://github.com/zaphoyd/websocketpp/issues/360

DZabavchik avatar Jul 16 '16 18:07 DZabavchik

I will try to verify the server, however it may take some time (it is not mine). Many Thanks!

sashakh avatar Jul 17 '16 17:07 sashakh

Hi, There are logs... Not so clear for me (

From autobahn-cpp side:

starting io service [2016-07-19 18:15:43] [connect] Successful connection [2016-07-19 18:15:43] [error] handle_transport_init received error: TLS handshake failed [2016-07-19 18:15:43] [fail] WebSocket Connection 52.29.34.99:8443 - "" /ws 0 websocketpp.transport.asio.socket:8 TLS handshake failed [2016-07-19 18:15:43] [info] asio async_shutdown error: asio.ssl:336462231 (shutdown while in init) stopped io service failed to connect

From server side:

2016-07-19T15:13:39+0000 [Router 5017 crossbar.router.protocol.WampWebSocketServerProtocol] dropping connection: None 2016-07-19T15:13:39+0000 [Router 5017 crossbar.router.protocol.WampWebSocketServerProtocol] Connection to/from tcp4:80.235.34.78:51424 was lost in a non-clean fashion: Connection lost 2016-07-19T15:13:39+0000 [Router 5017 crossbar.router.protocol.WampWebSocketServerProtocol] _connectionLost: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionLost'>: Connection to the other side was lost in a non-clean fashion: Connection lost. ] 2016-07-19T15:13:39+0000 [Router 5017 crossbar.router.protocol.WampWebSocketServerProtocol] WAMP-over-WebSocket transport lost: wasClean=True, code=1001, reason="None" 2016-07-19T15:13:39+0000 [Controller 5012 crossbar.controller.processtypes.RouterWorkerProcess] Worker worker-001 -> Controller traffic: {2: {'count': 301, 'bytes': 171683}, 3: {'count': 8, 'bytes': 3923}}

-----------AND ---------------

2016-07-19T15:15:08+0000 [Router 5017 crossbar.router.protocol.WampWebSocketServerProtocol] Unable to format event {'log_logger': <Logger 'crossbar.router.protocol.WampWebSocketServerProtocol'>, 'log_source': None, 'log_format': "parsed WebSocket extension 'permessage-deflate' with params '{'client_max_window_bits': [True]}'", 'log_time': 1468941308.227039}: u"'client_max_window_bits'" 2016-07-19T15:15:08+0000 [Router 5017 crossbar.router.protocol.WampWebSocketServerProtocol] client request permessage-compress extension, but we did not accept any offer [[PerMessageDeflateOffer(acceptNoContextTakeover = True, acceptMaxWindowBits = True, requestNoContextTakeover = False, requestMaxWindowBits = 0)]]

sashakh avatar Jul 19 '16 15:07 sashakh

I've found the problem finally. crossbario supports only TLS v1.2 clients. So using:

ws_clinet.set_tls_init_handler([&](websocketpp::connection_hdl) {
        return websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv12_client);
});

makes it to work.

Thanks for the help!

sashakh avatar Nov 28 '16 16:11 sashakh

I'm having an issue implementing the utilization of wss/wamp with a combination of websocketpp and autobahn|cpp libraries.

Ultimately, my issue is that calling connect_future = transport->connect() results in a segmentation fault of sorts.

The fault is happening in boost::asio::detail::strand_service& boost::asio::use_serviceboost::asio::detail::strand_service(boost::asio::io)service&) io_service.hpp (line 33). Here is a screenshot of the call stack (http://imgur.com/bWV25WB). As the error (at the end of this post) suggests, I have tried adding -fno-limit-debug-info while compiling with no difference in results. This error happens when compiled using clang or g++ (aka it makes no difference). It's an odd error output that seems like something that should be a compilation error rather than a runtime error. Very strange (to me).

The web socket feed I'm attempting to utilize is found here (https://poloniex.com/support/api/).

Any thoughts, ideas, or advice on what I'm doing wrong in my code (below) would be extremely appreciated. If there's any other information I can provide to help investigate this, please don't hesitate to let me know!

Includes I'm using:

#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
#include <string>
#include <stdio.h>
#include <exception>
#include <autobahn/autobahn.hpp>
#include <autobahn/wamp_websocketpp_websocket_transport.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <tuple>

Code With An Issue

try {
        boost::asio::io_service io;

        typedef websocketpp::client<websocketpp::config::asio_tls_client> websocket_client;
        typedef autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> websocket_transport;

        websocket_client client;
        client.set_tls_init_handler([&](websocketpp::connection_hdl) {
            return websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv12_client);
        });
        auto transport = std::make_shared < autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> >(
                client, "wss://api.poloniex.com");

        //auto transport = std::make_shared<autobahn::wamp_tcp_transport>(
        //        io, parameters->rawsocket_endpoint(),true);

        // create a WAMP session that talks WAMP-RawSocket over TCP
        auto session = std::make_shared<autobahn::wamp_session>(io, true);

        transport->attach(std::static_pointer_cast<autobahn::wamp_transport_handler>(session));

        // Make sure the continuation futures we use do not run out of scope prematurely.
        // Since we are only using one thread here this can cause the io service to block
        // as a future generated by a continuation will block waiting for its promise to be
        // fulfilled when it goes out of scope. This would prevent the session from receiving
        // responses from the router.
        boost::future<void> connect_future;
        boost::future<void> start_future;
        boost::future<void> join_future;
        boost::future<void> subscribe_future;
        connect_future = transport->connect().then([&](boost::future<void> connected) {
            try {
                connected.get();
            } catch (const std::exception& e) {
                std::cerr << e.what() << std::endl;
                io.stop();
                return;
            }

            std::cerr << "transport connected" << std::endl;

            start_future = session->start().then([&](boost::future<void> started) {
                try {
                    started.get();
                } catch (const std::exception& e) {
                    std::cerr << e.what() << std::endl;
                    io.stop();
                    return;
                }

                std::cerr << "session started" << std::endl;

                join_future = session->join("realm1").then([&](boost::future<uint64_t> joined) {
                    try {
                        std::cerr << "joined realm: " << joined.get() << std::endl;
                    } catch (const std::exception& e) {
                        std::cerr << e.what() << std::endl;
                        io.stop();
                        return;
                    }

                    subscribe_future = session->subscribe("ticker", &on_topic1).then([&] (boost::future<autobahn::wamp_subscription> subscribed)
                    {
                        try {
                            std::cerr << "subscribed to topic: " << subscribed.get().id() << std::endl;
                        }
                        catch (const std::exception& e) {
                            std::cerr << e.what() << std::endl;
                            io.stop();
                            return;
                        }

                    });
                });
            });
        });

        std::cerr << "starting io service" << std::endl;
        io.run();
        std::cerr << "stopped io service" << std::endl;
    }
    catch (std::exception& e) {
        std::cerr << "exception: " << e.what() << std::endl;
        return 1;
    }

Results/Errors Output:

Boost: 106300
Connecting to realm: realm1
Exception: EXC_BAD_ACCESS (code=1, address=0x0)
error: bitbot_tests.cpp.o DWARF DIE at 0x0015aea5 (class connection<websocketpp::config::asio_tls_client::transport_config>) has a member variable 0x0015b017 (m_tcp_pre_init_handler) whose type is a forward declaration, not a complete definition.
Try compiling the source file with -fno-limit-debug-info
error: bitbot_tests.cpp.o :: Class 'endpoint<websocketpp::connection<websocketpp::config::asio_tls_client>, websocketpp::config::asio_tls_client>' has a base class 'websocketpp::config::asio_tls_client::transport_type' which does not have a complete definition.
error: bitbot_tests.cpp.o :: Try compiling the source file with -fno-limit-debug-info.

xandrrix avatar Mar 01 '17 03:03 xandrrix

Hi again all. I actually fixed my issue and in so doing, I think I've created an example of using secure RawSocket/WebSocket.

Includes:

#include <autobahn/autobahn.hpp>
#include <autobahn/wamp_websocketpp_websocket_transport.hpp>
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>
#include <boost/version.hpp>
#include <iostream>
#include <memory>
#include <string>
#include <tuple>

Solution:

typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
    typedef autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> websocket_transport;

    try {
        //std::cerr << "Connecting to realm: " << parameters->realm() << std::endl;

        boost::asio::io_service io;
        //bool debug = parameters->debug();

        client ws_client;
        ws_client.init_asio(&io);
        ws_client.set_tls_init_handler([&](websocketpp::connection_hdl) {
            return websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv12_client);
        });
        auto transport = std::make_shared < autobahn::wamp_websocketpp_websocket_transport<websocketpp::config::asio_tls_client> >(
                ws_client, "wss://api.poloniex.com:443", true);

        //auto transport = std::make_shared<autobahn::wamp_tcp_transport>(
        //        io, parameters->rawsocket_endpoint(),true);

        // create a WAMP session that talks WAMP-RawSocket over TCP
        auto session = std::make_shared<autobahn::wamp_session>(io, true);

        transport->attach(std::static_pointer_cast<autobahn::wamp_transport_handler>(session));

        // Make sure the continuation futures we use do not run out of scope prematurely.
        // Since we are only using one thread here this can cause the io service to block
        // as a future generated by a continuation will block waiting for its promise to be
        // fulfilled when it goes out of scope. This would prevent the session from receiving
        // responses from the router.
        boost::future<void> connect_future;
        boost::future<void> start_future;
        boost::future<void> join_future;
        boost::future<void> subscribe_future;
        connect_future = transport->connect().then([&](boost::future<void> connected) {
            try {
                connected.get();
            } catch (const std::exception& e) {
                std::cerr << e.what() << std::endl;
                io.stop();
                return;
            }

            std::cerr << "transport connected" << std::endl;

            start_future = session->start().then([&](boost::future<void> started) {
                try {
                    started.get();
                } catch (const std::exception& e) {
                    std::cerr << e.what() << std::endl;
                    io.stop();
                    return;
                }

                std::cerr << "session started" << std::endl;

                join_future = session->join("realm1").then([&](boost::future<uint64_t> joined) {
                    try {
                        std::cerr << "joined realm: " << joined.get() << std::endl;
                    } catch (const std::exception& e) {
                        std::cerr << e.what() << std::endl;
                        io.stop();
                        return;
                    }

                    subscribe_future = session->subscribe("BTC_ETH", &on_topic1).then([&] (boost::future<autobahn::wamp_subscription> subscribed)
                    {
                        try {
                            std::cerr << "subscribed to topic: " << subscribed.get().id() << std::endl;
                        }
                        catch (const std::exception& e) {
                            std::cerr << e.what() << std::endl;
                            io.stop();
                            return;
                        }

                    });
                });
            });
        });

        std::cerr << "starting io service" << std::endl;
        io.run();
        while(1){
            cout<<"looping..."<<endl;
            sleep(1);
        }
        std::cerr << "stopped io service" << std::endl;
    }
    catch (std::exception& e) {
        std::cerr << "exception: " << e.what() << std::endl;
        ret_var.successfully_ran = false;
		return ret_var;
    }
    return ret_var;

xandrrix avatar Mar 01 '17 04:03 xandrrix