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

Pranjali Chumbhale pranjalic at safeai.ai
Wed Mar 25 20:23:55 CET 2020


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*

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.

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/e48682ac/attachment.htm>


More information about the Libwebsockets mailing list