Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread Evgeny Grin
Hi Nicolas,

On 04.05.2017 3:18, Nicolas Mora wrote:
> I'm currently working on an implementation of a websocket manager with
> MHD and it's getting pretty good so far.
>
> The problem I have is when the daemon is shut down and there are open
> connections. The documentation on MHD_quiesce_daemon says that "Note
> that the caller is responsible for closing the returned socket;" which
> is close to what I have, but since a websocket can be left open
> indefinitely, I need to know if the daemon needs to stop.
MHD_quiesce_daemon() prevent MHD from accepting new connections but
allow to continue processing with current connections.
The returned socket is listening socket.
> Is there a signal or an event or any other way for the upgrade_handler
> function to know that a MHD_quiesce_daemon or a MHD_stop_daemon has
> been sent ?

You can track quiesced state of MHD in some global variable (if you are
using single MHD instance) or in local variable associated with MHD
instance. You will need to update this variable when you quiesced MHD.
In upgrade_handler you can check current state of MHD by checking variable.
Keep in mind that MHD will not accept new connection after
MHD_quiesce_daemon(), so upgrade_handler will be called after
MHD_quiesce_daemon() if connection was accepted before
MHD_quiesce_daemon() but not yet "upgraded".

MHD_stop_daemon() will close all connections including "upgraded"
connections. So you can't use "upgraded" connections after
MHD_stop_daemon().

Could you explain a bit more situation that you need to solve?
Do you want to implement graceful MHD shutdown after closing all
upgraded connections?

-- 
Best Wishes,
Evgeny Grin




Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread Nicolas Mora

Hi,

Thanks Evgeny and Silvio for your help

Le 2017-05-04 à 03:02, Evgeny Grin a écrit :

MHD_quiesce_daemon() prevent MHD from accepting new connections but
allow to continue processing with current connections.
The returned socket is listening socket.


Actually, I'm not using MHD_quiesce_daemon() at all, just 
MHD_stop_daemon(). I talked about MHD_quiesce_daemon() because in the 
online documentation, the phrase I quote is below MHD_quiesce_daemon().



You can track quiesced state of MHD in some global variable (if you are
using single MHD instance) or in local variable associated with MHD
instance. You will need to update this variable when you quiesced MHD.
In upgrade_handler you can check current state of MHD by checking variable.
Keep in mind that MHD will not accept new connection after
MHD_quiesce_daemon(), so upgrade_handler will be called after
MHD_quiesce_daemon() if connection was accepted before
MHD_quiesce_daemon() but not yet "upgraded".

MHD_stop_daemon() will close all connections including "upgraded"
connections. So you can't use "upgraded" connections after
MHD_stop_daemon().

The problem I have is that MHD_stop_daemon() doesn't close all the 
connections. Instead, it looks like it waits for the active connections 
to close by themselves and I have the following log message:

Initiated daemon shutdown while "upgraded" connection was not closed.


Could you explain a bit more situation that you need to solve?
Do you want to implement graceful MHD shutdown after closing all
upgraded connections?

I guess what I'd rather have is for the upgraded connections to be 
closed by MHD when MHD_stop_daemon() is called, so the upgrade callback 
could interpret it easily.
Silvio's suggestion might work too, some signal like a 
"MHD_DAEMON_INFO_WAS_QUIESCED" or, in my case "MHD_DAEMON_INFO_WAS_STOPPED".


My current implementation is the following.
When a websocket upgrade is called by the client, the websocket callback 
is executed:

https://github.com/babelouest/ulfius/blob/2.0/src/ulfius.c#L432
Then the program loops on listening to the socket
https://github.com/babelouest/ulfius/blob/2.0/src/u_websocket.c#L115

But in my example program, when the user stops the program by pressing 
the  key while connections are active, the program doesn't stop 
and waits for the open websockets to close.

https://github.com/babelouest/ulfius/blob/2.0/example_programs/websocket_example/websocket_example.c



Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread Evgeny Grin
>> MHD_stop_daemon() will close all connections including "upgraded"
>> connections. So you can't use "upgraded" connections after
>> MHD_stop_daemon().
>>
> The problem I have is that MHD_stop_daemon() doesn't close all the
> connections. Instead, it looks like it waits for the active connections
> to close by themselves and I have the following log message:
> Initiated daemon shutdown while "upgraded" connection was not closed.
> 

Do you use HTTP or HTTPS?
You must not call MHD_stop_daemon() while you still have some not closed
"upgraded" connections.
May be we should add more alarming message in case of such API violation.

>> Could you explain a bit more situation that you need to solve?
>> Do you want to implement graceful MHD shutdown after closing all
>> upgraded connections?
>>
> I guess what I'd rather have is for the upgraded connections to be
> closed by MHD when MHD_stop_daemon() is called, so the upgrade callback
> could interpret it easily.
> Silvio's suggestion might work too, some signal like a
> "MHD_DAEMON_INFO_WAS_QUIESCED" or, in my case
> "MHD_DAEMON_INFO_WAS_STOPPED".
> 
> My current implementation is the following.
> When a websocket upgrade is called by the client, the websocket callback
> is executed:
> https://github.com/babelouest/ulfius/blob/2.0/src/ulfius.c#L432
> Then the program loops on listening to the socket
> https://github.com/babelouest/ulfius/blob/2.0/src/u_websocket.c#L115
> 
> But in my example program, when the user stops the program by pressing
> the  key while connections are active, the program doesn't stop
> and waits for the open websockets to close.
> https://github.com/babelouest/ulfius/blob/2.0/example_programs/websocket_example/websocket_example.c

Could you provide a minimal example?

-- 
Wishes,
Evgeny



Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread Nicolas Mora


Do you use HTTP or HTTPS?
Eventually, since it's a framework for both http and https, I will use 
both protocols.



You must not call MHD_stop_daemon() while you still have some not closed
"upgraded" connections.
May be we should add more alarming message in case of such API violation.

I understand.
What I have thought of is to store a signature of all opened upgraded 
connections in an array, then before calling MHD_stop_daemon(), going 
through each connection, and close them. I guess that's the most clean 
way to do it.



Could you provide a minimal example?

The file 
https://github.com/babelouest/ulfius/blob/2.0/example_programs/websocket_example/websocket_example.c 
provides a minimal example of what I intend to do, although it's still 
in progress.




Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread silvioprog
On Thu, May 4, 2017 at 8:47 AM, Nicolas Mora  wrote:
[...]

> Silvio's suggestion might work too, some signal like a
> "MHD_DAEMON_INFO_WAS_QUIESCED" or, in my case "MHD_DAEMON_INFO_WAS_STOPPED".


I'm going to send a patch to Evgeny ...

-- 
Silvio Clécio


Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread Evgeny Grin
On 04.05.2017 16:41, Nicolas Mora wrote:
>>
>> Do you use HTTP or HTTPS?
> Eventually, since it's a framework for both http and https, I will use
> both protocols.
Behavior in undefined situation can differ in HTTP and HTTPS modes.
MHD_stop_daemon() should close all upgraded connections in HTTPS mode.


>> You must not call MHD_stop_daemon() while you still have some not closed
>> "upgraded" connections.
>> May be we should add more alarming message in case of such API violation.
> I understand.
> What I have thought of is to store a signature of all opened upgraded
> connections in an array, then before calling MHD_stop_daemon(), going
> through each connection, and close them. I guess that's the most clean
> way to do it.

Yes, it's most correct way.


>> Could you provide a minimal example?
>>
> The file
> https://github.com/babelouest/ulfius/blob/2.0/example_programs/websocket_example/websocket_example.c
> provides a minimal example of what I intend to do, although it's still
> in progress.

>From MHD point of view it's not minimal - a lot of functions and
variables that not required to trigger this behavior.

-- 
Wishes,
Evgeny




Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread silvioprog
Done. So dudes, what do you think about this attached patch?

On Thu, May 4, 2017 at 10:45 AM, silvioprog  wrote:

> On Thu, May 4, 2017 at 8:47 AM, Nicolas Mora 
> wrote:
> [...]
>
>> Silvio's suggestion might work too, some signal like a
>> "MHD_DAEMON_INFO_WAS_QUIESCED" or, in my case "MHD_DAEMON_INFO_WAS_STOPPED".
>
>
> I'm going to send a patch to Evgeny ...
>

-- 
Silvio Clécio
From 91cec1d7e2a1c69dcf3978e70c4ee12cd9a21513 Mon Sep 17 00:00:00 2001
From: silvioprog 
Date: Thu, 4 May 2017 10:58:26 -0300
Subject: [PATCH] Allows to check the server shutdown statuses.

---
 src/include/microhttpd.h | 20 +++-
 src/microhttpd/daemon.c  |  6 ++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index ca0059f..fa0b820 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -1841,7 +1841,25 @@ enum MHD_DaemonInfoType
* Note: flags may differ from original 'flags' specified for
* daemon, especially if #MHD_USE_AUTO was set.
*/
-  MHD_DAEMON_INFO_FLAGS
+  MHD_DAEMON_INFO_FLAGS,
+
+  /**
+   * Check if the daemon was shut down.
+   * No extra arguments should be passed.
+   */
+  MHD_DAEMON_INFO_SHUTDOWN,
+
+  /**
+   * Check if the daemon was quiesced.
+   * No extra arguments should be passed.
+   */
+  MHD_DAEMON_INFO_QUIESCED,
+
+  /**
+   * Check if the daemon has data waiting to be processed.
+   * No extra arguments should be passed.
+   */
+  MHD_DAEMON_INFO_PENDING_DATA
 };
 
 
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index a91d268..dba818f 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -6470,6 +6470,12 @@ MHD_get_daemon_info (struct MHD_Daemon *daemon,
   return (const union MHD_DaemonInfo *) &daemon->connections;
 case MHD_DAEMON_INFO_FLAGS:
   return (const union MHD_DaemonInfo *) &daemon->options;
+case MHD_DAEMON_INFO_SHUTDOWN:
+  return (const union MHD_DaemonInfo *) &daemon->shutdown;
+case MHD_DAEMON_INFO_QUIESCED:
+  return (const union MHD_DaemonInfo *) &daemon->was_quiesced;
+case MHD_DAEMON_INFO_PENDING_DATA:
+  return (const union MHD_DaemonInfo *) &daemon->data_already_pending;
 default:
   return NULL;
 };
-- 
2.7.4



Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread Christian Grothoff
You forgot to update doc/libmicrohttpd.texi, otherwise looks OK even
though I'm not convinced SHUTDOWN/QUESTCED are useful: an application
can trivially track those itself, so these two are definitively just API
bloat.

On 05/04/2017 03:59 PM, silvioprog wrote:
> Done. So dudes, what do you think about this attached patch?
> 


0xE29FC3CC.asc
Description: application/pgp-keys


signature.asc
Description: OpenPGP digital signature


Re: [libmicrohttpd] How to close all upgraded connections when shutting down MHD_Daemon?

2017-05-04 Thread Evgeny Grin
Same for "pending data".
Moreover MHD_DAEMON_INFO_PENDING_DATA is confusing and not correct.
Zero in data_already_pending doesn't mean that no data is pending. Zero
only means that "no data for immediately process". May be socket is not
ready for sending more data, but more data is pending.

And mapping "bool" to not bool is not correct. union MHD_DaemonInfo
doesn't have "bool" member and currently we do not want to expose "bool"
in public header.
On some platforms "bool" can be implemented as "char".

-- 
Best Wishes,
Evgeny Grin

On 04.05.2017 17:20, Christian Grothoff wrote:
> You forgot to update doc/libmicrohttpd.texi, otherwise looks OK even
> though I'm not convinced SHUTDOWN/QUESTCED are useful: an application
> can trivially track those itself, so these two are definitively just API
> bloat.
> 
> On 05/04/2017 03:59 PM, silvioprog wrote:
>> Done. So dudes, what do you think about this attached patch?
>>



signature.asc
Description: OpenPGP digital signature


[libmicrohttpd] [PATCH] Check response existence on upgrade

2017-05-04 Thread José Bollo
When a connection upgrade is requested and when the
request sent an error reply, the response is most of
the time already sent when the test on
connection->response->upgrade_handler is made, leading
to dereferencing NULL.

Two possibilities exist:

  NULL == connection->response || NULL == connection->response->upgrade_handler

or

  NULL != connection->response && NULL == connection->response->upgrade_handler

The first is prefered because it is probably safer to close the
connection in that case.

Change-Id: Ie6e7fc165f7fe3635ade0952bb34a0b937d38716
Signed-off-by: José Bollo 
---
 src/microhttpd/connection.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 4753d6e..91a4492 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -882,7 +882,7 @@ keepalive_possible (struct MHD_Connection
*connection) #ifdef UPGRADE_SUPPORT
 if ( (MHD_str_equal_caseless_ (end,
"upgrade")) &&
- (NULL == connection->response->upgrade_handler) )
+ (NULL == connection->response || NULL == 
connection->response->upgrade_handler) )
   return MHD_NO;
 #endif /* UPGRADE_SUPPORT */
 
-- 
2.9.3




Re: [libmicrohttpd] [PATCH] Check response existence on upgrade

2017-05-04 Thread Evgeny Grin
Thanks! Applied.

-- 
Best Wishes,
Evgeny Grin

On 04.05.2017 22:58, José Bollo wrote:
> When a connection upgrade is requested and when the
> request sent an error reply, the response is most of
> the time already sent when the test on
> connection->response->upgrade_handler is made, leading
> to dereferencing NULL.
> 
> Two possibilities exist:
> 
>   NULL == connection->response || NULL == 
> connection->response->upgrade_handler
> 
> or
> 
>   NULL != connection->response && NULL == 
> connection->response->upgrade_handler
> 
> The first is prefered because it is probably safer to close the
> connection in that case.
> 
> Change-Id: Ie6e7fc165f7fe3635ade0952bb34a0b937d38716
> Signed-off-by: José Bollo 
> ---
>  src/microhttpd/connection.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
> index 4753d6e..91a4492 100644
> --- a/src/microhttpd/connection.c
> +++ b/src/microhttpd/connection.c
> @@ -882,7 +882,7 @@ keepalive_possible (struct MHD_Connection
> *connection) #ifdef UPGRADE_SUPPORT
>  if ( (MHD_str_equal_caseless_ (end,
> "upgrade")) &&
> - (NULL == connection->response->upgrade_handler) )
> + (NULL == connection->response || NULL == 
> connection->response->upgrade_handler) )
>return MHD_NO;
>  #endif /* UPGRADE_SUPPORT */
>  
>