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

Pranjali Chumbhale pranjalic at safeai.ai
Thu Mar 26 18:49:53 CET 2020


I will check it out.
Thank you for the responses and all the information.

Regards,
Pranjali


On Wed, Mar 25, 2020 at 6:18 PM <andy at warmcat.com> wrote:

>
>
> 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
> >> >> >> >> >>>
> >> >> >> >> >>
> >> >> >> >>
> >> >> >>
> >> >>
> >>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://libwebsockets.org/pipermail/libwebsockets/attachments/20200326/788ce43f/attachment-0001.htm>


More information about the Libwebsockets mailing list