[Libwebsockets] What is the proper way to keep stream connection?

Kun Zhao kunzhao77 at gmail.com
Mon Apr 29 05:19:07 CEST 2019


I see the code is not on 3.1-stable branch. I just cherry-picked the change
into 3.1-stable branch. Thanks.

On Sun, Apr 28, 2019 at 7:37 PM Kun Zhao <kunzhao77 at gmail.com> wrote:

> error C3861: 'lws_http_headers_detach': identifier not found
>
> I am using 3.1-stable branch.
>
> On Sun, Apr 28, 2019 at 7:31 PM Kun Zhao <kunzhao77 at gmail.com> wrote:
>
>> Andy,
>>
>> Thanks for your reply. I'm trying to call the lws_http_headers_detach,
>> but the function is not in the compiled header file (lws-http.h), did I
>> miss something?
>>
>> Thanks,
>> Kun
>>
>> On Sat, Apr 27, 2019 at 11:08 PM Andy Green <andy at warmcat.com> wrote:
>>
>>>
>>>
>>> On April 28, 2019 1:31:31 AM GMT+01:00, Kun Zhao <kunzhao77 at gmail.com>
>>> wrote:
>>> >Hi Andy,
>>> >
>>> >I have a HTTP client which receives data from a server. The connection
>>> >is
>>> >kept alive and the server sends data to the client periodically. The
>>> >client
>>> >receives data for a while then closed the connection. After some
>>> >debugging,
>>> >I found that the problem is here:
>>> >
>>> https://github.com/warmcat/libwebsockets/blob/2d2c0f0f9241fa449018baececdab83289b1e0f9/lib/core-net/service.c#L708
>>> >
>>> >the ah->assigned never updates and the session eventually timed out
>>> >then
>>> >and the client closed the connection.
>>>
>>> ah->assigned should never update... this code represents an lws policy
>>> that user code must not hold onto an ah for a long period, the limit's like
>>> 5 minutes.
>>>
>>> ah are 'detachable' heap-allocated structs that contain parsed http
>>> headers... the're a few KB each but can be set larger at context creation
>>> time; an ah pool can also be defined there based on how scarce memory is in
>>> your system.  On h1, connections acquire an ah or go on a waiting list for
>>> one before the request (server) or response (client) headers can be parsed.
>>>
>>> On h2, all the care about waiting lists and pools was turned on its
>>> head... since h2 muxes control packets and an arbitrary number of http
>>> streams on one connection, dealing with h2 means you cannot just defer
>>> reading from the connection... you will deadlock being unable to send
>>> anything because you deferred reading it to find the necessary tx credit
>>> update control packets.  So if the h2 connection says it wants to open 10 x
>>> http streams concurrently, which is pretty typical, lws must find or
>>> allocate 10 x ah suddenly... we can't tolerate using the ah waiting list.
>>>
>>> For this reason ah are required to be freed ASAP and user code that
>>> keeps them is regarded as a bug by lws.  For connections that upgrade to
>>> ws, this is done by lws for you, the ah is detached just after ESTABLISHED
>>> is called.  This is why if you care about the http headers on a ws
>>> connection, you must query them at ESTABLISHED or keep copies of ones you
>>> care about at that point.
>>>
>>> For long-lived http connections, you can detach the ah manually, again
>>> after querying or copying critical info from it
>>>
>>>
>>> https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-http.h#n700-708
>>>
>>> For h1 that and the wsi timeout is all lws needs you to do...
>>> intermediaries or the remote server that understand h1 might enforce their
>>> own idle timeouts though.  For h2 it's more complicated again... there are
>>> two idle timeouts in play, one for a logical stream wsi, and one for the
>>> 'nwsi' network wsi, the h2 socket connection that carries one or more
>>> streams.  When you write something, both get 30s of life.  So if any stream
>>> writes anything, the underlying nwsi keeps getting life.  If an individual
>>> stream is idle, it will quickly get closed.
>>>
>>> With SSE and ws-over-h2, it introduced a concept of an 'immortal
>>> stream'... an nwsi carrying at least one immortal stream is itself no
>>> longer subject to timeouts.  This is to deliver the necessary ws semantics
>>> over h2, where ws streams can idle forever by default.  This works ok vs
>>> the ah assignation timeout because nwsi don't have an ah themselves, and
>>> the upgraded-to-ws stream dropped their ah.
>>>
>>> Since you're already doing the keepalive stuff, it sounds like you just
>>> need to drop the ah before entering your long wait.
>>>
>>> -Andy
>>>
>>> >What is the proper way to update the ah->assigned time stamp to keep
>>> >the
>>> >connection open?
>>> >
>>> >Following is the response header from the server.
>>> >
>>> >HTTP/1.1 200 OK
>>> >Server: openresty/1.9.15.1
>>> >Date: Sat, 27 Apr 2019 21:11:14 GMT
>>> >Content-Type: application/octet-stream
>>> >Transfer-Encoding: chunked
>>> >Connection: close
>>> >Access-Control-Allow-Headers: Authorization, Content-Type,
>>> >Accept-Datetime-Format, OANDA-Agent, ETag
>>> >Access-Control-Allow-Methods: PUT, PATCH, POST, GET, OPTIONS, DELETE
>>> >Access-Control-Allow-Origin: *
>>> >Access-Control-Expose-Headers: ETag, RequestID
>>> >RequestID: 799161546957200243
>>> >
>>> >Following is the logs:
>>> >[2019/04/27 19:05:01:8002] NOTICE: ah excessive hold: wsi
>>> >00000000122CFC40
>>> >  peer address: 198.105.26.108
>>> >  ah pos 258
>>> >[2019/04/27 19:05:01:8032] NOTICE:    connection: = close
>>> >[2019/04/27 19:05:01:8042] NOTICE:    http/1.1  = 200 OK
>>> >[2019/04/27 19:05:01:8052] NOTICE:    content-type: =
>>> >application/octet-stream
>>> >[2019/04/27 19:05:01:8072] NOTICE:    date: = Sat, 27 Apr 2019 23:56:03
>>> >GMT
>>> >[2019/04/27 19:05:01:8092] NOTICE:    access-control-allow-origin: = *
>>> >[2019/04/27 19:05:01:8102] NOTICE:    server: = openresty/1.9.15.1
>>> >[2019/04/27 19:05:01:8122] NOTICE:    transfer-encoding: = chunked
>>> >[2019/04/27 19:05:01:8132] INFO: __lws_header_table_detach: wsi
>>> >00000000122CFC40: ah 000000001230F9C0 (tsi=0, count = 1)
>>> >[2019/04/27 19:05:01:8152] DEBUG: __lws_header_table_detach: wsi
>>> >00000000122CFC40: ah held 544s, role/state 0x10000000 0x117,
>>> >[2019/04/27 19:05:01:8182] INFO: __lws_header_table_detach: nobody
>>> >usable
>>> >waiting
>>> >[2019/04/27 19:05:01:8202] INFO: _lws_destroy_ah: freed ah
>>> >000000001230F9C0
>>> >: pool length 0
>>> >[2019/04/27 19:05:01:8222] INFO: __lws_header_table_detach: wsi
>>> >00000000122CFC40: ah 000000001230F9C0 (tsi=0, count = 0)
>>> >[2019/04/27 19:05:01:8242] INFO: __lws_close_free_wsi:
>>> >00000000122CFC40:
>>> >caller: excessive ah
>>> >[2019/04/27 19:05:01:8262] DEBUG: __lws_close_free_wsi: real
>>> >just_kill_connection: 00000000122CFC40 (sockfd 260)
>>> >[2019/04/27 19:05:01:8282] DEBUG: __remove_wsi_socket_from_fds:
>>> >wsi=00000000122CFC40, skt=260, fds pos=0, end guy pos=1, endfd=0
>>> >[2019/04/27 19:05:01:8312] DEBUG: lwsi_set_state(00000000122CFC40,
>>> >0x1000001e)
>>> >
>>> >Thanks,
>>> >Kun Zhao
>>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://libwebsockets.org/pipermail/libwebsockets/attachments/20190428/6f2da508/attachment.htm>


More information about the Libwebsockets mailing list