[Libwebsockets] libwebsocket problem

Andy Green andy at warmcat.com
Mon May 27 07:24:44 CEST 2019



On 5/27/19 4:52 AM, Wei, Catherine wrote:
> Yes, I think we have what you said.
> 
> The server instance call
> 
> int TServer::Initialize(int serverPort, bool allowRemoteClients,  const 
> std::set<std::string>& supportedProtocols),  when it receives a callback 
> (reason: LWS_CALLBACK_ADD_POLL_FD), it will call 
> "EventLoop->AddDescriptor() like below:
> 
> 
> int TServer::LwsCallback(lws* wsi, lws_callback_reasons reason, void* 
> user,  void* in,   size_t len)
> {
>    auto context = lws_get_context(wsi);
>    auto self = static_cast<TLwsBase*>(lws_context_user(context));
>    auto pollArgs = static_cast<const lws_pollargs*>(in);
> 
>    if (!self->ShuttingDown) {
>      int result = 0;
>      if (self->HandleLwsCallback(wsi, reason, user, in, len, result)) {
>        return result;
>      }
>    }
> 
>    switch (reason) {
>    case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
>      self->EventLoop.RemoveDescriptor(pollArgs->fd);
>      // Fall through
>    case LWS_CALLBACK_ADD_POLL_FD:
>      self->EventLoop.AddDescriptor(pollArgs->fd,
>                                    FromLwsEventMask(pollArgs->events),
>                                    IIOEventLoop::PRIORITY_NORMAL,
>                                    self);
>      break;
> ......
> 
> }
> 
> 
> After adding the descriptor, we will handle the socket coming to the 
> file descirptor
> 
> void TServer::HandleEvent(int fd, uint32_t event)
> {
>    lws_pollfd pollFdStruct = {
>      .fd = fd,
>      .events = ToLwsEventMask(event),
>      .revents = ToLwsEventMask(event)
>    };
>    lws_service_fd(LwsContext, &pollFdStruct);
> }
> 
> 
> The lws_service_fd() is what you called lws_service(), right?

You've basically hotwired your fd events up to lws_service_fd(), which 
is good if that's what you want.  But it's not enough.

Some things, eg, timeout handling, do not happen because of fd events... 
in fact you want timeouts to fire precisely when you have not been 
getting any fd events.

If you used the lws event loop, with the poll() backend each time around 
lws_service() it will do the timeout processing... by default it waits 
for up to 1000ms before exiting and coming around again.

With the other lws event loop backends like libuv etc, lws sets up a 1Hz 
timer to do the timeout checking for you.

But with what you have here, where you participate in someone else's 
event loop, you must also manually ask for the timeout / periodic check 
stuff to be handled... look at the last part of the comment for 
lws_service_fd()

/**
  * lws_service_fd() - Service polled socket with something waiting
  * \param context:	Websocket context
  * \param pollfd:	The pollfd entry describing the socket fd and which 
events
  *		happened, or NULL to tell lws to do only timeout servicing.
  *
  * This function takes a pollfd that has POLLIN or POLLOUT activity and
  * services it according to the state of the associated
  * struct lws.
  *
  * The one call deals with all "service" that might happen on a socket
  * including listen accepts, http files as well as websocket protocol.
  *
  * If a pollfd says it has something, you can just pass it to
  * lws_service_fd() whether it is a socket handled by lws or not.
  * If it sees it is a lws socket, the traffic will be handled and
  * pollfd->revents will be zeroed now.
  *
  * If the socket is foreign to lws, it leaves revents alone.  So you can
  * see if you should service yourself by checking the pollfd revents
  * after letting lws try to service it.
  *
  * You should also call this with pollfd = NULL to just allow the
  * once-per-second global timeout checks; if less than a second since 
the last
  * check it returns immediately then.
  */

If you also take care of that, you will find timeouts and ASYNC close 
start to magically work.

-Andy


More information about the Libwebsockets mailing list