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

andy at warmcat.com andy at warmcat.com
Thu Mar 26 02:18:14 CET 2020



On March 25, 2020 9:38:40 PM UTC, Pranjali Chumbhale <pranjalic at safeai.ai> wrote:
>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?

Right way is if I bother to reply with a url highlighting the member and docs for it as I did earlier, prpperly read it.

-Andy

>-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
>> >> >> >> >>>
>> >> >> >> >>
>> >> >> >>
>> >> >>
>> >>
>>


More information about the Libwebsockets mailing list