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

andy at warmcat.com andy at warmcat.com
Wed Mar 25 20:39:00 CET 2020



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