crossbario/autobahn-cpp

Support MSVC/Windows

oberstet opened this issue · 34 comments

Support MSVC/Windows

Hi

I like the autobahn websocket very much and use the autobahn.js in a tiny project. But unfortunalety I need it in a MSVC project.
So, despite my slight knowledge in c++ and boost, I make a try in helping to solve this issue.

First step, the examples need the #define WIN32_LEAN_AND_MEAN makro.

In autobahn_impl.hpp

#ifdef WIN32
#include <WinSock2.h>
#include <io.h>
#else
#include <arpa/inet.h>
#include <unistd.h>
#endif

will help.

But now i stuck on this:
error C2280: 'boost::promise<boost::any> &boost::promise<boost::any>::operator =(const boost::promise<boost::any> &)' : attempting to reference a deleted function

Maybe someone can help out.

Greets

@solarisx What environment are you using? Compiler version, Boost version, etc

Visual C++ 2013 with 18.00.30723 Compiler on Win7 x64.
I get the boost error with boost versions 1_56 and 1_57. With boost 1_55 there are some more.

I am having the exact same error with the same setup as solarisx.

@DominickT sorry, I don't use Windows/VC++ nowerdays and won't have time to do so soon.

You might have a look at

http://stackoverflow.com/questions/24921149/error-c2280-attempting-to-reference-a-deleted-function-trying-to-call-vector-e

and/or ask on Boost mailing lists. Probabyl boost::promise lacks something or needs something defined on Windows to work ...

I managed to port it to Visual C++ 2012 (vc110) and boost 1.56.0. I did not try Visual C++ 2013 (vc120).

It wasn't that bad - mostly took some configuration (boost defines) and converting boost::future to boost:shared_future, and adding .share() to future<>.then(...) in a few places. There seems to be an issue when copying/moving a boost::future with msvc ...

As I only need it for a prototype for now, I haven't run tests but the basics seem to work: binding rpc methods, calling them via html+js through a crossbar instance.

I don't plan to maintain this port - but may be able to make it available on request.

After a big battle, I managed to get it to compile and run (Windows 7 / VS 2013 / VC120).

Apart from following the advice above, a patch was needed inside Boost future.hpp:
BOOST_THREAD_COPYABLE_AND_MOVABLE(promise) instead of
BOOST_THREAD_MOVABLE_ONLY(promise).

If the above change is not made, autobahn_impl.hpp doesn't compile due to this operation:
m_register_requests[m_request_id] = register_request_t(endpoint);

Unfortunately running it doesn't produce the expected results. The socket connection succeeds but the client never enters the specified realm.

This is the whole output with debug mode enabled, when running the call1.cpp example:


Running on 105700
Starting ASIO I/O loop ..
Connected to server
RX preparing to receive message ..
TX message (56 octets) ...
TX message sent (60 / 60 octets)


...and the client remains stuck at this point.

Any advice on how to proceed?
@codeandroid , I would be grateful if you list your exact changes or upload the modified source code somewhere.
Regards

See my comment at #27

@IvaKom , thanks for the tip!
Your addition seems to make perfect sense and I guess a PR would be nice.
I am now able to compile:
https://raw.githubusercontent.com/tavendo/AutobahnCpp/master/examples/register2.cpp
But the call 1 example is still failing: https://github.com/tavendo/AutobahnCpp/blob/master/examples/call1.cpp


Anyhow, more importantly, my C++ client never joins the realm ("realm1" in my case).
Basically the body of the closure below is never executed:


session_future = session.join("realm1").then([&](shared_future<uint64_t> s) {
cerr << "Session joined to realm with session ID " << s.get() << endl;
// ....
});


OTOH, the nodejs and browser based clients successfully manage to connect and perform RPC calls, etc.


I have followed the other advice on this thread:

  1. Adding #define WIN32_LEAN_AND_MEAN (although I don't think that it makes much of a difference in this case)
  2. Renamed the ERROR = 8, of enum class msg_code to something else.
  3. Added surrounding defines around case msgpack::type::DOUBLE:, as it's not defined in the VS 2013 case
  4. Replaced all future to shared_future and appended .share() to .then(...)
  5. Reordered the #include <boost/asio.hpp> & #include <boost/version.hpp> includes, due to a WinSock check.

Still, the C++ client never enters the specified realm. What am I still missing?

Thanks in advance!

I'll try to come up with a clean PR.
On Feb 21, 2015 3:04 AM, "krasi0" notifications@github.com wrote:

@IvaKom https://github.com/IvaKom , thanks for the tip!
Your addition seems to make perfect sense and I guess a PR would be nice.
I am now able to compile:

https://raw.githubusercontent.com/tavendo/AutobahnCpp/master/examples/register2.cpp
But the call 1 example is still failing:

https://github.com/tavendo/AutobahnCpp/blob/master/examples/call1.cpp

Anyhow, more importantly, my C++ client never joins the realm ("realm1" in
my case).

Basically the body of the closure below is never executed:

session_future = session.join("realm1").then(& {
cerr << "Session joined to realm with session ID " << s.get() << endl;
// ....

});

OTOH, the nodejs and browser based clients successfully manage to connect

and perform RPC calls, etc.

I have followed the other advice on this thread:

  1. Adding #define WIN32_LEAN_AND_MEAN (although I don't think that it
    makes much of a difference in this case)
  2. Renamed the ERROR = 8, of enum class msg_code to something else.
  3. Added surrounding defines around case msgpack::type::DOUBLE:, as it's
    not defined in the VS 2013 case
  4. Replaced all future to shared_future and appended .share() to .then(...)
  5. Reordered the #include & #include includes, due to a WinSock check.

Still, the C++ client never enters the specified realm. What am I still
missing?

Thanks in advance!


Reply to this email directly or view it on GitHub
#2 (comment).

I've created a pull request, see #28.

Thanks!
With the changes from your PR, the aforementioned "Register 2" example compiles and runs (never enters the realm, so no improvement there). "Call 1" still doesn't compile.

After you compile and run it, are you able to join the realm of a crossbar server? I have tried with an instance running over the network, as well as against demo.crossbar.io, but to no avail.

@IvaKom Thanks for your patch, everything compiles fine here too. However, I can confirm @krasi0 's problem of being unable to enter the realm. At least my callback lambda function in the then-clause never executes.

Exactly. That is the most profound issue - not being able to join the
realm...
I wonder if it has something to do with the lack of specifying /ws as a
part of the URL. In all other languages, the full URL is specified. In C++,
only the IP and port. What do you guys think?
On Feb 22, 2015 5:57 PM, "mananatee" notifications@github.com wrote:

@IvaKom https://github.com/IvaKom Thanks for your patch, everything
compiles fine here too. However, I can confirm @krasi0
https://github.com/krasi0 's problem of being unable to enter the
realm. At least my callback lambda function in the then-clause never
executes.


Reply to this email directly or view it on GitHub
#2 (comment).

FWIW, AutobahnCpp does not take a WebSocket URL, since it currently does not support WebSocket as a WAMP transport, but only RawSocket. The latter only needs IP and port.

Alright, but in that case, if the whole URL is ws://192.168.1.1:8080/ws,
there should be a way to specify the trailing "/ws" to the session after the socket connection has been opened. Or is "/ws" not necessary?

No. There is no path with RawSocket. ws://192.168.1.1:8080/ws is a WebSocket URL.

So the bottom line is that with AutobahnCpp, the only supported Crossbar URLs are of the form ws://192.168.1.1:8080 , i.e. nothing else could be in the path?

@krasi0 I got it working by starting the crossbar server using a raw socket instead of websocket. For the example to run, I fixed the file AutobahnCpp\examples\server.py and started the crossbar router using this script. To fix it, just import the RouterFactory and RouterSessionFactory classes from crossbar instead of autobahn, i.e.:

from crossbar.router.router import RouterFactory
from crossbar.router.router import RouterSessionFactory

Also i needed to install the package msgpack-python via pip package manager. I hope this helps.

This sounds like a plan, but in that case are the nodejs and Web browser
clients still able to connect and issue RPC requests?

On Sun, Feb 22, 2015 at 7:34 PM, mananatee notifications@github.com wrote:

@krasi0 https://github.com/krasi0 I got it working by starting the
crossbar server using a raw socket instead of websocket. For the example to
run, I fixed the file AutobahnCpp\examples\server.py and started the
crossbar router using this script. To fix it, just import the
RouterFactory and RouterSessionFactory classes from crossbar instead of
autobahn, i.e.:

from crossbar.router.router import RouterFactoryfrom crossbar.router.router import RouterSessionFactory

Also i needed to install the package msgpack-python via pip package
manager. I hope this helps.


Reply to this email directly or view it on GitHub
#2 (comment).

BR

@krasi0 Yes. If you use Crossbar.io.
@mananatee Using Crossbar.io internal classes is not supported.

@oberstet Ok thanks for heads up. I just made the modification since this is the example script supplied with Autobahn.Python and it is now broken (the classes that are used seem to have moved from autobahn to crossbar). I'm sure the same can be achieved by just setting the right configuration in the .crossbar file.

@oberstet that "Getting started" tutorial definitely answers many of the questions.
One very important detail to note is that Web clients still connect to port 8080 (a Web Socket), while the C++ backend is expected to connect to connect 8090, which is a Raw Socket, so actually crossbar listens on two different ports after starting.
Now, everything seems to work properly. Thanks!

@krasimir-littlepostman great to hear you've got it working! ah, and sorry for costing you time with this - we clearly should update the docs on AutobahnCpp to mention all this. And yes: today, WebSocket and RawSocket transports for WAMP have to run on different ports. There is a slight revision of WAMP-over-RawSocket in the spec that will lift that and allows to run both transports on one port. Not implement yet in any library though ...

Another tip to the poor souls like me, who have to use VS:
In autobahn.hpp:
The call_t struct should look like this:


struct call_t {
call_t() {};
call_t(call_t &&other)
: m_res(std::move(other.m_res))
{};

        boost::promise<boost::any> m_res;
     };

In autobahn_impl.hpp, every
m_calls[m_request_id] = call_t();
must be replaced with:
m_calls.emplace(m_request_id, call_t());

Thanks to @IvaKom suggestion.

There hasn't been activity in this issue for a year now ... can anyone give a quick status update how to run autobahn with MSVC (is possible)? Thanks!

As MSVC apparently IS supported nowadays, I guess this ticket can be closed?

Update: While compilation with VS 2015 works now, VS 2013 raises errors on private member access in msgpack::v1::zone::zone, e.g.:

Error   C2248   'msgpack::v1::zone::zone' : cannot access private member declared in class 'msgpack::v1::zone'   TestProject d:\xxxx\autobahn-cpp\autobahn\wamp_event.ipp   41  

@supermihi this PR #103 was recently merged, where @DZabavchik has added a number of fixes which apparently make VS 2015 work. So yes, closing this one.

I have no clue about the VS 2013 thing, so ..

Yes, I can confirm that 2015 works. I might open another ticket for VS2013 (though I'll probably switch to C#/WampSharp anyway ...)

@supermihi FWIW, we won't spend much effort on working around VS2013 limitations rgd modern C++ support, which likely is the reason (as both GCC, Clang and VS2015 work now). The "fix" is: upgrade VS;) This is by policy: AutobahnCpp requires a modern C++ compiler, due to the use of advanced C++ features, and there is no point in trying to retrofit old compilers.

VS feature support: https://msdn.microsoft.com/en-us/library/hh567368%28v=vs.140%29.aspx

I am not doing Windows these days anymore, so I on longer track developments there, but I am wondering about https://en.wikipedia.org/wiki/C%2B%2B/CX - MS seems to invent new C++ flavors every now and then;) What's C++/CX or what do use it for? Does it work with Boost, ASIO and Autobahn?

@oberstet Thanks for the clarification. I fully understand your reluctance to care about MS' specific interpretation of C++. My original motivation to use VS2013 was that another library I had to use did not run with 2015, however we'll be able to either workaround that or (as I mentioned above) switch to C# in the first place.

In my understanding WinRT is something like .NET but unmanaged. The point is that you can use a WinRT class from other languages like C# and JavaScript directly. I haven't used this so far, but I'm pretty sure that you can use any "normal" C++ library within a C++/CX project...