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

andy at warmcat.com andy at warmcat.com
Wed Mar 25 21:05:21 CET 2020



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