[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [libmicrohttpd] upgrading and life cycle of sockets, issue when used
From: |
Christian Grothoff |
Subject: |
Re: [libmicrohttpd] upgrading and life cycle of sockets, issue when used with epoll |
Date: |
Wed, 6 Jan 2021 20:45:21 +0100 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.12.0 |
Hi Jose,
Yes, we should indeed return a timeout of 0 in this case. I've
implemented that in df6124f7..b1691240.
However, please note that I would still strongly advise the use of a
signalling channel, as your
approach only works in limited cases where your
closing of the connection is done within the scope of the MHD_run()
operation. The moment you actually do such operations later based on
other things in your external event loop, you will need some kind of
signalling.
Happy hacking!
Christian
On 1/5/21 10:17 AM, José Bollo wrote:
> On Sun, 3 Jan 2021 14:22:25 +0100
> Christian Grothoff <grothoff@gnunet.org> wrote:
>
>> Hi Jose,
>>
>> I've figured out the issue. The bug is actually in your code.
>
> Hi Christian,
>
> Thank you for having checked that issue.
>
>> The problem is that you are using an _external_ event loop, and if you
>> do so, you are responsible for re-triggering MHD_run() if you do
>> anything that might change the state of an MHD connection.
>> This (mostly) applies to MHD_resume_connection() -- but also to
>> closing an upgraded connection.
>>
>> Without this modification, MHD does close the connection on the _next_
>> request, so if you would connect with another client, MHD will then
>> close the connection.
>
> Yes, the next request closes the connection and unlocks the first
> client. But this is not a solution, obviously.
>
>> This is the only way to fix this, as when MHD is not 'run', it cannot
>> act. And if you are controlling the external event loop, you are
>> responsible for triggering MHD 'when necessary'.
>>
>> I've attached a modified version of your code that adds the necessary
>> signalling logic to your poll()-loop. (Using eventfd(); non-portable.
>> Use a pipe() to do this in a more portable way.)
>
> I have checked your rewrite. (A side note, reformatting code is not fair
> when using tools for a quick search of differences.)
>
> Before accepting your conclusion, I'd like to argument a little the
> reason why I'm still thinking that something can be done in your code.
>
> The main loop i submitted is:
>
> while (poll(pfd, 1, -1) == 1) {
> do {
> MHD_run(d);
> }
> while(
> MHD_get_timeout(d, &to) == MHD_YES
> && to == 0);
> }
>
> The close is done in a user callback invoked within MHD_run. Then in my
> opinion, the function MHD_get_timeout should return a timeout of zero
> because there is no time to wait before the next action: closing
> something.
>
> If you accept that idea, it simplifies my code and probably avoid
> further questions if someone also integrates an external polling
> mechanism.
>
> Otherwise, lets go for handling specifically the squared corner case of
> the wheel.
>
> Hopefully I convinced you.
> Best regards
> José
>
>>
>>
>> Happy hacking!
>>
>> Christian
>>
>> On 12/10/20 4:08 PM, José Bollo wrote:
>>> Hello,
>>>
>>> My code uses LMHD embedded with its EPOLL mechanism. Part of that
>>> code deals with upgrading to websocket. It then call somewhere:
>>>
>>> response = MHD_create_response_for_upgrade(
>>> upgrade_to_websocket, memo);
>>>
>>> and the callback function upgrade_to_websocket looks as here below:
>>>
>>> void upgrade_to_websocket(
>>> void *cls,
>>> struct MHD_Connection *connection,
>>> void *con_cls,
>>> const char *extra_in,
>>> size_t extra_in_size,
>>> MHD_socket sock,
>>> struct MHD_UpgradeResponseHandle *urh
>>> ) {
>>> struct memo *memo = cls;
>>> struct ws *ws = ws_create(sock, memo, close_websocket, urh);
>>> if (ws == NULL) close_websocket(urh);
>>> }
>>>
>>> void close_websocket(struct MHD_UpgradeResponseHandle *urh) {
>>> MHD_upgrade_action (urh, MHD_UPGRADE_ACTION_CLOSE);
>>> }
>>>
>>> Thank you for your attention until here. So far, so good.
>>>
>>> The issue now: when the functiuon ws_create returns NULL, the
>>> program returns to some polling and wait for an events BUT DOES NOT
>>> CLOSE THE SOCKET, leading to starvation of the client.
>>>
>>> I guess that calling some function after calling MHD_upgrade_action
>>> (urh, MHD_UPGRADE_ACTION_CLOSE) could unlock the situation by
>>> performing correct close. Though the called function should not be
>>> MHD_run because it dispatch events, what is not expected here.
>>>
>>> I join a sample demo. When I connect on websocket on it, the client
>>> starves. I recorded and joined the output of strace.
>>>
>>> Best regards
>>> José Bollo
>>>
>>>
>
signature.asc
Description: OpenPGP digital signature