libmicrohttpd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libmicrohttpd] upgrading and life cycle of sockets, issue when used


From: José Bollo
Subject: Re: [libmicrohttpd] upgrading and life cycle of sockets, issue when used with epoll
Date: Thu, 7 Jan 2021 09:16:44 +0100

Hello Christian,

Thank you for the advise. I had not thought about that before but there
is surely a need for a side channel notification in my case. I have
to check...

The dream for me that it could be blindly integrated in LMHD translates
perhaps to a nightmare for you... I let you mind about that, extend or
not the TODO list, and return to my code.

Thank you again for your work.

Best regards
José

On Wed, 6 Jan 2021 20:45:21 +0100
Christian Grothoff <grothoff@gnunet.org> wrote:

> 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
> >>>
> >>>  
> >   
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]