[Libwebsockets] libwebsocket problem

Andy Green andy at warmcat.com
Fri May 24 14:15:21 CEST 2019



On May 23, 2019 8:47:57 PM PDT, "Wei, Catherine" <catherine.wei at commscope.com> wrote:
>>That's not an option... have a read of the documentation I pasted for
>...SYNC.
>LWS_TO_KILL_SYNC is an option in lws_set_timeout and its value is -2

:-)  yes, it's listed in the header as a flag.

But as it describes in the comment there, it may delete the wsi immediately.  Because the stuff in lws who called the callback may still expect to do housekeeping on the wsi after the callback returns, that code will blow up if the callback actually freed it.

For that reason, using the SYNC close is "not an option" for you if the wsi you are closing is the one that was the subject of the callback.  It explains this restriction in the comment I pasted.

>>- something happens on a wsi
> >- lws calls the callback
> >-    user code deletes the wsi
> >- user code returns to lws
> >- lws uses the now-deleted wsi
>
>If this is the sequence, it explains my segment fault.

Right.

It means something else is wrong that ASYNC doesn't just work fine instead.

>My eventLoop is like this:
>
>1. Initialize the websocket server
>int TServer::Initialize(int serverPort,
>                         bool allowRemoteClients,
>                       const std::set<std::string>& supportedProtocols)
>{
>   const auto protocolStructEntries = 2 + supportedProtocols.size();
>  LwsProtocolStructs.reset(new lws_protocols[protocolStructEntries]);
>
>  InitLwsProtocolStruct(NO_PROTOCOL, 0);
>
>  size_t protocolCounter = 1;
>  for (const auto& protocol : supportedProtocols) {
>    assert(protocol != NO_PROTOCOL);
>    InitLwsProtocolStruct(protocol.c_str(), protocolCounter);
>    ++protocolCounter;
>  }
>InitLwsProtocolStruct(nullptr, protocolCounter); // "No more protocols"
>
>  if (KDEBUG_LEVEL < 2) {
>    lws_set_log_level(0, nullptr);
>  }
>
>  lws_context_creation_info creationInfo;
>  memset(&creationInfo, 0, sizeof(creationInfo));
>  creationInfo.port = serverPort; // 0 -> allocate any port
>  creationInfo.iface = allowRemoteClients ? nullptr : "lo";
>  creationInfo.protocols = LwsProtocolStructs.get();
>  creationInfo.gid = -1; // Don't change GID after socket listen
>  creationInfo.uid = -1; // Don't change UID after socket listen
>  creationInfo.options =
>    LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME
>    | LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
>  creationInfo.user = this;
>
>  LwsContext = lws_create_context(&creationInfo);
>  assert(LwsContext);
>
>  auto vhost = lws_create_vhost(LwsContext, &creationInfo);
>  return lws_get_vhost_listen_port(vhost);
>}
>
>2. Monitored client class:
>Class Client {
>  bool ReceivedClosedConnectionCallback = false;
>  bool ReceivedFailedConnectionInitiationCallback = false;
>
>  void SendAndReceive(
>    const std::string& message,
>IConnection::TMessageType messageType =
>IConnection::TMessageType::TEXT)
>  {
>    MessageToSend = message;
>    MessageTypeToSend = messageType;
>    ReceivedMessage.clear();
>    while (ReceivedMessage.empty()
>           && !ReceivedClosedConnectionCallback
>           && !ReceivedFailedConnectionInitiationCallback) {
>      EventLoop.RunOnce();
>    }
>  }
>  void HandleFailedConnectionInitiation() override
>  {
>    ReceivedFailedConnectionInitiationCallback = true;
>  }
>  void HandleClosedConnection(IConnection& /*connection*/) override
>  {
>    ReceivedClosedConnectionCallback = true;
>  }
>}
>
>In my code:
>1.Initialize my server
>2.Create a client instance: Client c;
>3.connect to the server which started in step1. The server accepted the
>connection
>4.client call SendAndReceive("") to send an empty message
>4.server call "lws_set_timeout(&LwsConnection, NO_PENDING_TIMEOUT,
>LWS_TO_KILL_ASYNC);" to disconnect the client connection
>5.The client doesn't receive any close callback, so it doesn't set
>ReceivedClosedConnectionCallback or
>ReceivedFailedConnectionInitiationCallback to false, the while loop in
>SendAndReceive() never exits.

At some point in your code, you must have the 'event loop' or 'message pump' where you loop calling lws_service() or similar api, as in the examples.  If it's an event loop like libuv, libev or libevent, lws creates a 1Hz timer internally so it can do the timeout processing.  If you're using the default poll() event loop, you need to time out the poll wait once per second to allow lws to check timeouts and do other long-term processing before resuming the poll wait... this is the meaning of 1000 (ms) in the loop I linked to before.

But I didn't see this kind of thing in the code you pasted (maybe I missed it).

-Andy

>Catherine
>
>-----Original Message-----
>From: Andy Green <andy at warmcat.com> 
>Sent: 2019年5月24日 10:05
>To: Wei, Catherine <catherine.wei at commscope.com>;
>libwebsockets at ml.libwebsockets.org
>Subject: RE: [Libwebsockets] libwebsocket problem
>
>Message received from external source. Exercise caution when opening
>attachments, clicking links, or exchanging information.
>
> 
>
>
>On May 23, 2019 6:54:57 PM PDT, "Wei, Catherine"
><catherine.wei at commscope.com> wrote:
>>I'm using the LWS_TO_KILL_SYNC in lws_set_timeout, since I want to 
>>close it immediately.
>
>That's not an option... have a read of the documentation I pasted for
>...SYNC.
>
>What you're doing is a sequence like this
>
> - something happens on a wsi
> - lws calls the callback
> -    user code deletes the wsi
> - user code returns to lws
> - lws uses the now-deleted wsi
>
>>I tried LWS_TO_KILL_ASYNC in my code and it doesn't work, do I need to
>
>Hmmm what does it mean, 'doesn't work'?
>
>>use LWS_TO_KILL_ASYNC and set a real timeout at the same time. I found
>
>>the libwebsocket doesn't close it at all.
>
>Let's have a look at the logs for that, then.
>
>>The callback reason is LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, my
>>code:
>>
>>  case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
>>    { 
>>   auto requestPathSize = lws_hdr_total_length(wsi,
>WSI_TOKEN_GET_URI);
>>      if (requestPathSize == 0) {
>>        KTRACE1("Rejected non-GET request");
>>        result = -1; // Disconnect
>>      }
>>      else {
>>        std::string requestPath = lws_get_complete_url(wsi);
>>        auto protocol = static_cast<const char*>(in);
>>        if (!protocol) {
>>          protocol = NO_PROTOCOL;
>>        }
>>        KERROR("New connection for protocol \"%s\", path \"%s\"",
>>                protocol, requestPath.c_str());
>>        auto connection = static_cast<TConnection**>(user);
>>        assert(ConnectionHandler);
>>  *connection = new TConnection(*wsi, *ConnectionHandler,
>requestPath);
>>        if (ConnectionHandler->HandleNewConnection(**connection)) {
>>          (*connection)->SetRequestAcceptedFlag(true);
>>        }
>>      } 
>>    }
>>    return true;
>>
>>After the above code is executed, I want to close the client
>connection 
>>later, using lws_set_timeout(LWS_TO_KILL_SYNC) can disconnect the 
>>client connection, using lws_set_timeout(LWS_TO_KILL_ASYNC), the 
>>libwebsocket does nothing and client is not disconnected.
>>
>>This is the log after executing lws_set_timeout(LWS_TO_KILL_ASYNC)
>>2093 09:53:30.564 hbbtv(373) Debug: Connection::Disconnect: Disconnect
>>2
>>2094 09:53:30.564 hbbtv(373) None: <1B>[0m<1B>[34;1m[2019/05/24 
>>01:53:30:3568] DEBUG: __lws_set_timeout: 0x1d2861e0: 0 secs
>>2095 09:53:30.564 hbbtv(373) None: <1B>[0m<1B>[34;1m[2019/05/24 
>>01:53:30:3568] DEBUG: __lws_free_wsi: 0x1d2866e0, remaining wsi 3
>
>What does your event loop type code look like?
>
>I mean like this kind of thing
>
>https://secure-web.cisco.com/1kK0i7d1rwxP_JJAJxGZGRordv4PZCetS68ALhhizS4jLkrFksO04Omh0A1OMSD16c2AGMVZJZdMyb45OPWOJKhsyzYsDAWMv7pGH9fBpxeSCLstQDpaqV10gAwfEHreAYnGM8Yi6GOMGK3Ng6KnvfYCujElU9M2SuC4QXEZWpDfVPkJtfxI2T1KUx_WBr3yMB0nKYYiSLAlrkPsxlRORqJVjJOniN-oqLOvpzE3I9J17I9rCvWeDV3kqhP-3eYRAnxsQifngeGOl5QJslHknBkcgjy0tt4HfdvDh9D4uQmfbBxQK5zD_C8CiRWcnJCaK/https%3A%2F%2Flibwebsockets.org%2Fgit%2Flibwebsockets%2Ftree%2Fminimal-examples%2Fhttp-server%2Fminimal-http-server%2Fminimal-http-server.c#n81-82
>
>-Andy
>
>>
>>Best regards,
>>Catherine
>>
>>-----Original Message-----
>>From: Andy Green <andy at warmcat.com>
>>Sent: 2019年5月23日 19:31
>>To: Wei, Catherine <catherine.wei at commscope.com>; 
>>libwebsockets at ml.libwebsockets.org
>>Subject: Re: [Libwebsockets] libwebsocket problem
>>
>>Message received from external source. Exercise caution when opening 
>>attachments, clicking links, or exchanging information.
>>
>> 
>>
>>
>>On 5/23/19 7:32 AM, Wei, Catherine wrote:
>>
>>> Thanks, the api that you offered works in my case mentioned in my 
>>> early email. Calling it when I disconnect the connection from server
>
>>> side will disconnect the connection and also send callback to the 
>>> server in my case.
>>
>>Great.
>>
>>> However, in another case, I found that when a client request a 
>>> connection, the websocket server will receive a callback to handle
>>the
>>> new connection. When the server handles the new connection, it
>>rejects
>>> the connection directly by the api lws_set_timeout(). At this time, 
>>> when I disconnect the connection from the server side using api
>>> lws_set_timeout() when the client request a connection will lead to 
>>> libwebsocket crash. The process in detail: 1,Client request a
>>> connection   ->libwebsocket 2.Server HandleNewConnection callback,
>>> and call "lws_set_timeout()", then the process of websocket server 
>>> will report segment fault error like follow:
>>
>>You don't mention the callback reason nor show the code.
>>
>>You're using LWS_TO_KILL_ASYNC, right?
>>
>>#define LWS_TO_KILL_ASYNC -1
>>/**< If LWS_TO_KILL_ASYNC is given as the timeout sec in a
>>lws_set_timeout()
>> * call, then the connection is marked to be killed at the next
>timeout
>> * check.  This is how you should force-close the wsi being serviced
>if
>>* you are doing it outside the callback (where you should close by 
>>nonzero
>>  * return).
>>  */
>>#define LWS_TO_KILL_SYNC -2
>>/**< If LWS_TO_KILL_SYNC is given as the timeout sec in a
>>lws_set_timeout()
>>* call, then the connection is closed before returning (which may 
>>delete
>>* the wsi).  This should only be used where the wsi being closed is
>not 
>>the
>>  * wsi currently being serviced.
>>  */
>>
>>-Andy


More information about the Libwebsockets mailing list