Oops, I meant: static int dh(void *cls, struct MHD_Connection *con, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) { const char *page = "<html><body>I love MHD!</body></html>"; struct MHD_Daemon *d; struct MHD_Response *response; int ret; unsigned char i; bool quiesced; if (NULL != *con_cls) { *con_cls = (void *) 1; return MHD_YES; } /* simulating a long processing, like hard query in a database ... */ i = 1; while (i < 100) { MHD_get_connection_info(con, MHD_CONNECTION_INFO_DAEMON, &d); if (d) { MHD_get_daemon_info(d, *MHD_DAEMON_INFO_<some option informing that daemon was quiesced>*, &quiesced); if (quiesced) break; } sleep(1); i++; } response = MHD_create_response_from_buffer(strlen(page), (void *) page, MHD_RESPMEM_PERSISTENT); ret = MHD_queue_response(con, MHD_HTTP_OK, response); MHD_destroy_response(response); return ret; }
On Tue, Mar 28, 2017 at 1:32 PM, silvioprog <silviop...@gmail.com> wrote: > Done. The entire code is: https://pastebin.com/gNY2MwSY . I've used "curl > http://localhost:8080; echo" to test it. > > Commenting the code: the locking happens at line 39 (MHD_stop_daemon(d)). > I don't know it the stop function offer some option to force the server > stopping, but I think we really don't need it. However, it would be nice to > have a "MHD_DAEMON_INFO_<some option informing the daemon was quiesced>", > so the clients could check it in their processing, e.g: > > ... > > static int dh(void *cls, struct MHD_Connection *con, const char *url, const > char *method, const char *version, > const char *upload_data, size_t *upload_data_size, void > **con_cls) { > const char *page = "<html><body>I love MHD!</body></html>"; > struct MHD_Daemon *d; > struct MHD_Response *response; > int ret; > unsigned char i = 1; > bool stoped; > if (NULL != *con_cls) { > *con_cls = (void *) 1; > return MHD_YES; > } > /* simulating a long processing, like hard query in a database ... */ > i = 1; > while (i < 100) { > MHD_get_connection_info(con, MHD_CONNECTION_INFO_DAEMON, &d); > if (d && MHD_get_daemon_info(d, *MHD_DAEMON_INFO_<some option > informing that daemon was quiesced>*)) > break; > sleep(1); > i++; > } > response = MHD_create_response_from_buffer(strlen(page), (void *) page, > MHD_RESPMEM_PERSISTENT); > ret = MHD_queue_response(con, MHD_HTTP_OK, response); > MHD_destroy_response(response); > return ret; > } > > ... > > It is just a idea, but I'm totally open to get new ideas. :-) > > Anyway, if you see that *MHD_DAEMON_INFO_<some option informing that > daemon was quiesced>* could be an useful feature, I can try to send a > patch implementing it, something like *MHD_DAEMON_INFO_**WAS_QUIESCED*. > > On Tue, Mar 28, 2017 at 12:51 PM, silvioprog <silviop...@gmail.com> wrote: > >> Dude, thanks for fixing it, I'm going to study the changes and apply it >> here. :-) >> >> I've got a situation that locks the shutdown even using this fix, but I >> need to create a small project simulating the problem, I'm going to do it >> now ... >> >> On Tue, Mar 28, 2017 at 12:08 PM, Evgeny Grin <k...@yandex.ru> wrote: >> >>> Fixed version of you code: >>> >>> bool bf_httpsrv_shutdown(struct bf_httpsrv *srv) { MHD_socket fd; >>> uint8_t shutdown_attempts; /* Max 256. */ if (srv && srv->listening) { >>> fd = MHD_quiesce_daemon(srv->mhd); if (fd != MHD_INVALID_SOCKET) { >>> srv->listening = false; close(fd); if (! srv->forced_shutdown) { >>> shutdown_attempts = 1; while (MHD_get_daemon_info(srv->mhd, >>> MHD_DAEMON_INFO_CURRENT_CONNECTIONS)->num_connections > 0) { if >>> (shutdown_attempts >= srv->shutdown_attempts) { /* Default >>> srv->shutdown_attempts is 10. */ _BF_LOG("Forced server shutdown.\n"); >>> break; } shutdown_attempts++; sleep(1); } } } else _BF_LOG("Server >>> quiesce failed.\n"); MHD_stop_daemon(srv->mhd); return true; } return >>> false; } >>> >>> -- >>> Best Wishes, >>> Evgeny Grin >>> >>> On 28.03.2017 4:46, silvioprog wrote: >>> > Thanks for replying Evgeny, you and Christian always saving my day. :-) >>> > I read and re-read your and Christian answer, and finally I found a >>> > possible way to never lock the server at shutdown: adding an option to >>> > exit the server after configurable attempts. It can solve the timeout >>> > problem too, because I can't ensure that the programmer have >>> > configured it (anyway my library will assume 15 seconds by default). >>> > So, the code below applies your tips and implements the attempts >>> approach: >>> > bool bf_httpsrv_shutdown(struct bf_httpsrv *srv) { MHD_socket fd; >>> > uint8_t shutdown_attempts; /* Max 256. */ if (srv && srv->listening) { >>> > fd = MHD_quiesce_daemon(srv->mhd); if (fd != MHD_INVALID_SOCKET) >>> > close(fd); else _BF_LOG("Server quiesce failed.\n"); if >>> > (srv->forced_shutdown) { shutdown_attempts = 1; while >>> > (MHD_get_daemon_info(srv->mhd, >>> > MHD_DAEMON_INFO_CURRENT_CONNECTIONS)->num_connections > 0) { if >>> > (shutdown_attempts >= srv->shutdown_attempts) { /* Default >>> > srv->shutdown_attempts is 10. */ _BF_LOG("Forced server shutdown.\n"); >>> > exit(EINTR); } shutdown_attempts++; sleep(1); } } >>> > MHD_stop_daemon(srv->mhd); srv->listening = false; return true; } >>> > return false; } >>> > Unfortunately if exit was called the MHD_stop_daemon() will be not >>> > called, probably raising some memory leak, but current I have no idea >>> > how it could be solved. >>> > Feel totally free to point improvements about this new version. :-) >>> > On Sun, Mar 26, 2017 at 5:36 PM, Evgeny Grin <k...@yandex.ru >>> > <mailto:k...@yandex.ru>> wrote: >>> > >>> > On 26.03.2017 8:33, silvioprog wrote: > I found the following >>> > related message: > > >>> > https://lists.gnu.org/archive/html/libmicrohttpd/2014-09/ms >>> g00012.html >>> > <https://lists.gnu.org/archive/html/libmicrohttpd/2014-09/m >>> sg00012.html> >>> > > > I've used a similar logic, but with item X below, because I >>> > need to wait > the client processing: > > 1) MHD_quiesce_daemon() >>> > > *X) while (info.num_connections > 0) sleep(0.5s) # pseudo code* >>> > > 2) MHD_stop_daemon() > 3) close() > > Real implementation: > > >>> > bool bf_httpsrv_shutdown(struct bf_httpsrv *srv, bool force) { > >>> > MHD_socket fd; > if (srv && srv->listening) { > fd >>> > = MHD_quiesce_daemon(srv->mhd); > if (!force) > >>> > while (MHD_get_daemon_info(srv->mhd, >>> > MHD_DAEMON_INFO_CURRENT_CONNECTIONS)->num_connections > 0) > >>> > usleep(1000 * 500); //TODO: allow to use external >>> > callback > MHD_stop_daemon(srv->mhd); > if (fd != >>> > MHD_INVALID_SOCKET) > close(fd); > >>> > srv->listening = false; > return true; > } > >>> > return false; > } > > > Calling it with bf_httpsrv_shutdown(srv, >>> > false) the server stops waiting > for clients processing. > > So, >>> > what do you think about the logic above? Should it be improved?! > >>> > > Thanks in advance for any suggestions! If you don't check >>> > returned value from MHD_quiesce_daemon(), you may later found that >>> > you didn't quiesced daemon, so move check right after >>> > MHD_quiesce_daemon() and added error handling. If you didn't set >>> > connection timeout, connection may live indefinitely. Moreover, >>> > even with connection timeout, clients may continue processing on >>> > same HTTP 1.1 connections with new requests indefinitely. >>> > Furthermore, even with HTTP 1.0 and connection timeout >>> > hypothetical client may read answer very slow with results in very >>> > long unpredictable closure of connection. So: yes, you code will >>> > work but may result in very long (hours, for example) or even >>> > indefinitely long daemon shutdown. -- Best Wishes, Evgeny Grin >>> > >>> > >>> > -- >>> > Silvio Clécio >>> >> >> -- >> Silvio Clécio >> > > > > -- > Silvio Clécio > -- Silvio Clécio