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

andy at warmcat.com andy at warmcat.com
Wed Mar 25 03:46:35 CET 2020



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