[Libwebsockets] How to pass a lws_callback_function from a c++ class

Pranjali Chumbhale pranjalic at safeai.ai
Wed Mar 25 22:38:40 CET 2020


Here is the update:

I try to use lws_get_context(wsi) in my code.
However, as it does not see the full definition of type struct lws_contex

If I include just libwebsockets, I get the
error: invalid use of incomplete type ‘struct lws_context’
   my_type * my_type_ptr = (my_type *)(lws_get_context(wsi))->user;

But if I explicitly also include <libwebsockets/lws-misc.h>, I get lots of
compile errors of redeclaration.

I want to avoid any mallocs / new during in my callbacks.

What is the right way to to include the libwebsocket headers to resolve the
incomplete type error for lws_context?

-Pranjali

On Wed, Mar 25, 2020 at 1:05 PM <andy at warmcat.com> wrote:

>
>
> On March 25, 2020 7:58:08 PM UTC, Pranjali Chumbhale <pranjalic at safeai.ai>
> wrote:
> >Thank you for the information.
> >Just trying to understand it further,
> >
> >In my case, I have a single context, single websocket and I am making
> >the
> >call to lws_client_connect_via_info.
> >I am checking for a scenario where my server is not up and running.
> >
> >I am expecting the following sequence of callbacks after few initial
> >ones,
> >LWS_CALLBACK_PROTOCOL_INIT
> >
> >LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL,
> >
> >LWS_CALLBACK_GET_THREAD_ID
> >
> >LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
> >
> >LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
> >
> >
> >I see that LWS_CALLBACK_GET_THREAD_ID has a different wsi address. Does
> >that conclude its a fake wsi?
> >
> >And this fake wsi will not be able to retrieve the object pointer I
> >saved
> >earlier in user field , as it is a fake wsi.
>
> If you use the context user thing I gave the url to, you can recover your
> pointer from any wsi fake or real, since the all have a valid and correct
> context pointer in them either way.  If you use the user pointer in a
> specific lws_protocols struct,you're only going to be able to recover the
> pointer to your lws_protocols from wsi bound to that protocol... your wsi
> will be but not the fakewsi.
>
> -Andy
>
> >
> >Regards,
> >Pranjali
> >
> >
> >On Wed, Mar 25, 2020 at 12:39 PM <andy at warmcat.com> wrote:
> >
> >>
> >>
> >> On March 25, 2020 7:23:55 PM UTC, Pranjali Chumbhale
> ><pranjalic at safeai.ai>
> >> wrote:
> >> >So, the way, I am storing the object pointer *"this"* in
> >protocols.user
> >> >is
> >> >correct for my use case? My use case is to store a pointer to object
> >> >and be
> >> >able to retrieve in the callback, irrespective of the callback.
> >> >and the correct way to retrieve it in callback would be to use*
> >> >lws_get_protocol(wsi)->user*
> >>
> >> If all the wsi that want to recover the pointer are bound to that
> >> protocol, you can do it that way.  There's also a similar user
> >pointer you
> >> can set in the lws context and vhost at context / vhost creation
> >time.
> >>
> >>
> >>
> >
> https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-context-vhost.h#n337-345
> >>
> >> then you don't care about wsi protocol.
> >>
> >> >I observed that every time I get a callback, the wsi has a different
> >> >address.
> >> >I was expecting the wsi in callback to point to the websocket that
> >we
> >> >create so, every time was expecting it to be the same value.
> >>
> >> That's is how it works.  A wsi lives (at the same address) for as
> >long as
> >> the underlying socket connection.
> >>
> >> If your connection fails, you may start another connection and it'll
> >be a
> >> different pointer.
> >>
> >> If you have more than one active wsi, they'll all use the same
> >callback.
> >>
> >> Sometimes there are events reported to the callbacks that aren't
> >related
> >> to a specific wsi, eg cancel service.  A fake wsi is created for that
> >> purpose, with a valid context pointer.
> >>
> >> -Andy
> >>
> >> >Regards,
> >> >Pranjali
> >> >
> >> >
> >> >On Tue, Mar 24, 2020 at 7:46 PM <andy at warmcat.com> wrote:
> >> >
> >> >>
> >> >>
> >> >> On March 24, 2020 9:52:30 PM UTC, Pranjali Chumbhale
> >> ><pranjalic at safeai.ai>
> >> >> wrote:
> >> >> >Hello Andy,
> >> >> >
> >> >> >Following up on this one.
> >> >> >
> >> >> >I decided to make my callback function static and use it.
> >> >>
> >> >> It's not like there was another choice.
> >> >>
> >> >> >Also,
> >> >> >
> >> >> >>Likewise there are .opaque_user_data, .user and some accessors
> >in
> >> >many
> >> >> >lws objects with user-code defined lifetime.  Put your c++ "this"
> >in
> >> >> >there.  You're dealing with a C library, it has to be dealt with
> >as
> >> >C.
> >> >> >
> >> >> >I was using this approach.
> >> >>
> >> >> Right.
> >> >>
> >> >> >I do the assignment in the following way:
> >> >> >m_protocols[0].name = "my-protocol-name";
> >> >> >m_protocols[0].callback = callback_ws;
> >> >> >m_protocols[0].per_session_data_size = 0;
> >> >> >m_protocols[0].rx_buffer_size = m_max_data_size;
> >> >> >m_protocols[0].user = this; // user code can access this in
> >callback
> >> >> >
> >> >> >// terminator - needed by libwebsocket
> >> >> >m_protocols[1].name = NULL;
> >> >> >m_protocols[1].callback = NULL;
> >> >> >m_protocols[1].per_session_data_size = 0;
> >> >> >m_protocols[1].rx_buffer_size = 0;
> >> >>
> >> >> Ok...
> >> >>
> >> >> >I was using gdb to debug:
> >> >> >The value of this is getting assigned to user:
> >> >> >
> >> >> >(gdb)* print(m_protocols[0].user)*
> >> >> >
> >> >> >$5 = (void *) 0x7fffa13f9dc0
> >> >> >
> >> >> >(gdb) *print(this)*
> >> >> >
> >> >> >$6 = (my_class_name * const) 0x7fffa13f9dc0
> >> >> >
> >> >> >But when I get callback, I see that the user field is 0x0.
> >> >> >From gdb:
> >> >>
> >> >> No... lots of structs in lws have a .user / .user_data /
> >> >.opaque_user_data
> >> >> the user code can set in your terms 'reflecting the this of
> >different
> >> >> objects'.  Here, it'd be an object that lives as long as the
> >context
> >> >that's
> >> >> interesting for all users of that protocol to have access to via
> >> >> lws_get_protocol(wsi)->user.  That object scope woule be
> >> >'per-protocol',
> >> >> not 'per-connection'.
> >> >>
> >> >> The 'user' parameter to the protocol callback is unrelated,
> >although
> >> >I can
> >> >> see why it's confusing, that reflects a per-wsi object / struct
> >> >either
> >> >> allocated by lws when the wsi was bound to a particular protocol
> >> >(sized by
> >> >> the protocol's .per_session_data_size) or optionally set by user
> >code
> >> >at
> >> >> creation time for client wsi, with this
> >> >>
> >> >>
> >> >>
> >> >
> >>
> >
> https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-client.h#n85-86
> >> >>
> >> >> -Andy
> >> >>
> >> >> >my_class_name::callback_ws (wsi=0x56297b06f678,
> >> >> >reason=LWS_CALLBACK_EVENT_WAIT_CANCELLED, *user=0x0*, in=0x0,
> >len=0)
> >> >> >
> >> >> >my_class_name::callback_ws (wsi=0x56297aafe2c0,
> >> >> >reason=LWS_CALLBACK_CLIENT_CONNECTION_ERROR,* user=0x0*,
> >> >> >    in=0x7f60636d46eb, len=17)
> >> >> >
> >> >> >Regards,
> >> >> >Pranjali
> >> >> >
> >> >> >
> >> >> >On Tue, Mar 17, 2020 at 5:58 PM <andy at warmcat.com> wrote:
> >> >> >
> >> >> >>
> >> >> >>
> >> >> >> On March 18, 2020 12:35:25 AM UTC, Pranjali Chumbhale
> >> >> ><pranjalic at safeai.ai>
> >> >> >> wrote:
> >> >> >> >I do not have the option of using a static method.
> >> >> >>
> >> >> >> Lws is C, the compiler is telling you C code doesn't know how
> >to
> >> >play
> >> >> >c++
> >> >> >> games with magically passing "this" object context when
> >invoking
> >> >the
> >> >> >> dynamic function ptr.  Static function pointers don't need that
> >> >and
> >> >> >are
> >> >> >> compatible with C.
> >> >> >>
> >> >> >> You "don't have the option" to do what you're doing.  Use a
> >static
> >> >> >> function pointer and explicitly store your dynamic object
> >pointer
> >> >> >> somewhere, where depends on the object scope but there should
> >be
> >> >> >> somewhere.  Eg in lws_protocols in your example
> >> >> >>
> >> >> >>
> >> >> >>
> >> >> >
> >> >>
> >> >
> >>
> >
> https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-protocols-plugins.h#n73-74
> >> >> >>
> >> >> >> Likewise there are .opaque_user_data, .user and some accessors
> >in
> >> >> >many lws
> >> >> >> objects with user-code defined lifetime.  Put your c++ "this"
> >in
> >> >> >there.
> >> >> >> You're dealing with a C library, it has to be dealt with as C.
> >> >> >>
> >> >> >> >I was trying more of
> >> >> >>
> >>https://isocpp.org/wiki/faq/pointers-to-members#memfnptr-vs-fnptr
> >> >> >>
> >> >> >> It doesn't mention C.  If it did, it'd tell you what Brice (and
> >> >eg,
> >> >> >> libcurl docs) say.
> >> >> >>
> >> >> >> -Andy
> >> >> >>
> >> >> >> >Regards,
> >> >> >> >Pranjali
> >> >> >> >
> >> >> >> >
> >> >> >> >On Tue, Mar 17, 2020 at 5:31 PM Brice Hamon <brice at ydotm.com>
> >> >wrote:
> >> >> >> >
> >> >> >> >> Use a static method.
> >> >> >> >>
> >> >> >> >> On Tue, Mar 17, 2020 at 8:25 PM Pranjali Chumbhale
> >> >> >> ><pranjalic at safeai.ai>
> >> >> >> >> wrote:
> >> >> >> >>
> >> >> >> >>> Hello Team,
> >> >> >> >>>
> >> >> >> >>> I am trying to pass  a c++ class member function as a
> >callback
> >> >to
> >> >> >> >>> protocols.
> >> >> >> >>>
> >> >> >> >>> Here is the relevant piece of code.
> >> >> >> >>>
> >> >> >> >>> This is how my callback function is declared.
> >> >> >> >>> int ns::class_name::callback_ws( struct lws *wsi, enum
> >> >> >> >>> lws_callback_reasons reason,
> >> >> >> >>> void *user, void *in, size_t len);
> >> >> >> >>>
> >> >> >> >>>
> >> >> >> >>> This is how I am using it to pass it to protocols:
> >> >> >> >>> std::function<int(struct lws *wsi, enum
> >lws_callback_reasons
> >> >> >reason,
> >> >> >> >void
> >> >> >> >>> *user, void *in, size_t len)> callback_func;
> >> >> >> >>>
> >> >> >> >>> callback_func =
> >std::bind(&ns::class_name::callback_ws,this,
> >> >> >> >>> std::placeholders::_1, std::placeholders::_2,
> >> >> >> >>> std::placeholders::_3, std::placeholders::_4,
> >> >> >> >>> std::placeholders::_5);
> >> >> >> >>>
> >> >> >> >>> m_protocols[0].name = "named_protocol";
> >> >> >> >>> m_protocols[0].callback = callback_func;
> >> >> >> >>> m_protocols[0].per_session_data_size = 0;
> >> >> >> >>> m_protocols[0].rx_buffer_size = m_max_data_size;
> >> >> >> >>>
> >> >> >> >>> // terminator - needed by libwebsocket
> >> >> >> >>> m_protocols[1].name = NULL;
> >> >> >> >>> m_protocols[1].callback = NULL;
> >> >> >> >>> m_protocols[1].per_session_data_size = 0;
> >> >> >> >>> m_protocols[1].rx_buffer_size = 0;
> >> >> >> >>>
> >> >> >> >>> I am getting the following error:
> >> >> >> >>>
> >> >> >> >>> error: cannot convert ‘std::function<int(lws*,
> >> >> >lws_callback_reasons,
> >> >> >> >>> void*, void*, long unsigned int)>’ to ‘int (*)(lws*,
> >> >> >> >lws_callback_reasons,
> >> >> >> >>> void*, void*, size_t) {aka int (*)(lws*,
> >lws_callback_reasons,
> >> >> >> >void*,
> >> >> >> >>> void*, long unsigned int)}’ in assignment
> >> >> >> >>>    m_protocols[0].callback  = callback_func;
> >> >> >> >>>                               ^~~~~~~~~~~~~
> >> >> >> >>> I do not understand when the return data type of callback
> >> >> >function
> >> >> >> >is
> >> >> >> >>> int, why is it throwing error looking for  int(*).
> >> >> >> >>>
> >> >> >> >>> Regards,
> >> >> >> >>> Pranjali
> >> >> >> >>> _______________________________________________
> >> >> >> >>> Libwebsockets mailing list
> >> >> >> >>> Libwebsockets at ml.libwebsockets.org
> >> >> >> >>> https://libwebsockets.org/mailman/listinfo/libwebsockets
> >> >> >> >>>
> >> >> >> >>
> >> >> >>
> >> >>
> >>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://libwebsockets.org/pipermail/libwebsockets/attachments/20200325/80d01be1/attachment-0001.htm>


More information about the Libwebsockets mailing list