diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2017-02-26 23:34:20 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2017-02-26 23:46:51 +0300 |
commit | dd2d724c197d6fb5c3d676ae786763190ef278c5 (patch) | |
tree | 6110ca2562bb737820dc21cd29e1910a1674a9e7 /src/microhttpd/daemon.c | |
parent | 3edd4bfa7f87f5970fc701b0772eeadc2f076df9 (diff) | |
download | libmicrohttpd-dd2d724c197d6fb5c3d676ae786763190ef278c5.tar.gz libmicrohttpd-dd2d724c197d6fb5c3d676ae786763190ef278c5.zip |
Reworked handling "already ready" situations:
* busy-waiting for write if TLS connection is in MHD_EVENT_LOOP_INFO_WRITE mode and data is pending in TLS buffers
* removed calculation of number of TLS read-ready connections
* simplified and unified processing if any connection is in MHD_EVENT_LOOP_INFO_BLOCK mode
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r-- | src/microhttpd/daemon.c | 106 |
1 files changed, 56 insertions, 50 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index b52f05e7..b93367b8 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -428,11 +428,6 @@ recv_tls_adapter (struct MHD_Connection *connection, | |||
428 | { | 428 | { |
429 | ssize_t res; | 429 | ssize_t res; |
430 | 430 | ||
431 | if (connection->tls_read_ready) | ||
432 | { | ||
433 | connection->daemon->num_tls_read_ready--; | ||
434 | connection->tls_read_ready = false; | ||
435 | } | ||
436 | res = gnutls_record_recv (connection->tls_session, | 431 | res = gnutls_record_recv (connection->tls_session, |
437 | other, | 432 | other, |
438 | (i > SSIZE_MAX) ? SSIZE_MAX : i); | 433 | (i > SSIZE_MAX) ? SSIZE_MAX : i); |
@@ -451,13 +446,13 @@ recv_tls_adapter (struct MHD_Connection *connection, | |||
451 | disrupted); set errno to something caller will interpret | 446 | disrupted); set errno to something caller will interpret |
452 | correctly as a hard error */ | 447 | correctly as a hard error */ |
453 | MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_); | 448 | MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_); |
449 | connection->tls_read_ready = false; | ||
454 | return res; | 450 | return res; |
455 | } | 451 | } |
456 | if ((size_t)res == i) | 452 | |
457 | { | 453 | /* Check whether TLS buffers still have some unread data. */ |
458 | connection->tls_read_ready = true; | 454 | connection->tls_read_ready = ( ((size_t)res == i) && |
459 | connection->daemon->num_tls_read_ready++; | 455 | (0 != gnutls_record_check_pending (connection->tls_session)) ); |
460 | } | ||
461 | return res; | 456 | return res; |
462 | } | 457 | } |
463 | 458 | ||
@@ -951,6 +946,23 @@ call_handlers (struct MHD_Connection *con, | |||
951 | ret = con->idle_handler (con); | 946 | ret = con->idle_handler (con); |
952 | } | 947 | } |
953 | } | 948 | } |
949 | |||
950 | /* All connection's data and states are processed for this turn. | ||
951 | * If connection already has more data to be processed - use | ||
952 | * zero timeout for next select()/poll(). */ | ||
953 | /* Thread-per-connection do not need global zero timeout as | ||
954 | * connections are processed individually. */ | ||
955 | if ( (!con->daemon->data_already_pending) && | ||
956 | (0 == (con->daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ) | ||
957 | { | ||
958 | if (MHD_EVENT_LOOP_INFO_BLOCK == con->event_loop_info) | ||
959 | con->daemon->data_already_pending = true; | ||
960 | #ifdef HTTPS_SUPPORT | ||
961 | else if ( (con->tls_read_ready) && | ||
962 | (MHD_EVENT_LOOP_INFO_READ == con->event_loop_info) ) | ||
963 | con->daemon->data_already_pending = true; | ||
964 | #endif /* HTTPS_SUPPORT */ | ||
965 | } | ||
954 | return ret; | 966 | return ret; |
955 | } | 967 | } |
956 | 968 | ||
@@ -1061,7 +1073,6 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1061 | if (0 < gnutls_record_check_pending (urh->connection->tls_session)) | 1073 | if (0 < gnutls_record_check_pending (urh->connection->tls_session)) |
1062 | { | 1074 | { |
1063 | urh->connection->tls_read_ready = true; | 1075 | urh->connection->tls_read_ready = true; |
1064 | urh->connection->daemon->has_tls_recv_ready = true; | ||
1065 | } | 1076 | } |
1066 | } | 1077 | } |
1067 | else if (0 >= res) | 1078 | else if (0 >= res) |
@@ -1238,6 +1249,13 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1238 | } | 1249 | } |
1239 | } | 1250 | } |
1240 | 1251 | ||
1252 | /* Check whether data is present in TLS buffers | ||
1253 | * and incoming forward buffer have some space. */ | ||
1254 | if ( (urh->connection->tls_read_ready) && | ||
1255 | (urh->in_buffer_used < urh->in_buffer_size) && | ||
1256 | (0 == (urh->connection->daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ) | ||
1257 | urh->connection->daemon->data_already_pending = true; | ||
1258 | |||
1241 | if ( (urh->connection->daemon->shutdown) && | 1259 | if ( (urh->connection->daemon->shutdown) && |
1242 | ( (0 != urh->out_buffer_size) || | 1260 | ( (0 != urh->out_buffer_size) || |
1243 | (0 != urh->out_buffer_used) ) ) | 1261 | (0 != urh->out_buffer_used) ) ) |
@@ -1312,7 +1330,8 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1312 | { | 1330 | { |
1313 | struct timeval* tvp; | 1331 | struct timeval* tvp; |
1314 | struct timeval tv; | 1332 | struct timeval tv; |
1315 | if (con->tls_read_ready) | 1333 | if ( (con->tls_read_ready) && |
1334 | (urh->in_buffer_used < urh->in_buffer_size)) | ||
1316 | { /* No need to wait if incoming data is already pending in TLS buffers. */ | 1335 | { /* No need to wait if incoming data is already pending in TLS buffers. */ |
1317 | tv.tv_sec = 0; | 1336 | tv.tv_sec = 0; |
1318 | tv.tv_usec = 0; | 1337 | tv.tv_usec = 0; |
@@ -1378,7 +1397,8 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1378 | if (0 != urh->in_buffer_used) | 1397 | if (0 != urh->in_buffer_used) |
1379 | p[1].events |= POLLOUT; | 1398 | p[1].events |= POLLOUT; |
1380 | 1399 | ||
1381 | if (con->tls_read_ready) | 1400 | if ( (con->tls_read_ready) && |
1401 | (urh->in_buffer_used < urh->in_buffer_size)) | ||
1382 | timeout = 0; /* No need to wait if incoming data is already pending in TLS buffers. */ | 1402 | timeout = 0; /* No need to wait if incoming data is already pending in TLS buffers. */ |
1383 | else | 1403 | else |
1384 | timeout = UINT_MAX; | 1404 | timeout = UINT_MAX; |
@@ -1548,15 +1568,20 @@ thread_main_handle_connection (void *data) | |||
1548 | } | 1568 | } |
1549 | 1569 | ||
1550 | tvp = NULL; | 1570 | tvp = NULL; |
1571 | |||
1572 | if ( (MHD_EVENT_LOOP_INFO_BLOCK == con->event_loop_info) | ||
1551 | #ifdef HTTPS_SUPPORT | 1573 | #ifdef HTTPS_SUPPORT |
1552 | if (con->tls_read_ready) | 1574 | || ( (con->tls_read_ready) && |
1575 | (MHD_EVENT_LOOP_INFO_READ == con->event_loop_info) ) | ||
1576 | #endif /* HTTPS_SUPPORT */ | ||
1577 | ) | ||
1553 | { | 1578 | { |
1554 | /* do not block (more data may be inside of TLS buffers waiting for us) */ | 1579 | /* do not block: more data may be inside of TLS buffers waiting or |
1580 | * application must provide response data */ | ||
1555 | tv.tv_sec = 0; | 1581 | tv.tv_sec = 0; |
1556 | tv.tv_usec = 0; | 1582 | tv.tv_usec = 0; |
1557 | tvp = &tv; | 1583 | tvp = &tv; |
1558 | } | 1584 | } |
1559 | #endif /* HTTPS_SUPPORT */ | ||
1560 | if ( (NULL == tvp) && | 1585 | if ( (NULL == tvp) && |
1561 | (timeout > 0) ) | 1586 | (timeout > 0) ) |
1562 | { | 1587 | { |
@@ -1609,9 +1634,6 @@ thread_main_handle_connection (void *data) | |||
1609 | &maxsock, | 1634 | &maxsock, |
1610 | FD_SETSIZE)) | 1635 | FD_SETSIZE)) |
1611 | err_state = true; | 1636 | err_state = true; |
1612 | tv.tv_sec = 0; | ||
1613 | tv.tv_usec = 0; | ||
1614 | tvp = &tv; | ||
1615 | break; | 1637 | break; |
1616 | case MHD_EVENT_LOOP_INFO_CLEANUP: | 1638 | case MHD_EVENT_LOOP_INFO_CLEANUP: |
1617 | /* how did we get here!? */ | 1639 | /* how did we get here!? */ |
@@ -1691,9 +1713,6 @@ thread_main_handle_connection (void *data) | |||
1691 | break; | 1713 | break; |
1692 | case MHD_EVENT_LOOP_INFO_BLOCK: | 1714 | case MHD_EVENT_LOOP_INFO_BLOCK: |
1693 | p[0].events |= MHD_POLL_EVENTS_ERR_DISC; | 1715 | p[0].events |= MHD_POLL_EVENTS_ERR_DISC; |
1694 | tv.tv_sec = 0; | ||
1695 | tv.tv_usec = 0; | ||
1696 | tvp = &tv; | ||
1697 | break; | 1716 | break; |
1698 | case MHD_EVENT_LOOP_INFO_CLEANUP: | 1717 | case MHD_EVENT_LOOP_INFO_CLEANUP: |
1699 | /* how did we get here!? */ | 1718 | /* how did we get here!? */ |
@@ -2905,15 +2924,13 @@ MHD_get_timeout (struct MHD_Daemon *daemon, | |||
2905 | return MHD_NO; | 2924 | return MHD_NO; |
2906 | } | 2925 | } |
2907 | 2926 | ||
2908 | #ifdef HTTPS_SUPPORT | 2927 | if (daemon->data_already_pending) |
2909 | if (0 != daemon->num_tls_read_ready || daemon->has_tls_recv_ready) | ||
2910 | { | 2928 | { |
2911 | /* if there is any TLS connection with data ready for | 2929 | /* Some data already waiting to be processed. */ |
2912 | reading, we must not block in the event loop */ | ||
2913 | *timeout = 0; | 2930 | *timeout = 0; |
2914 | return MHD_YES; | 2931 | return MHD_YES; |
2915 | } | 2932 | } |
2916 | #endif /* HTTPS_SUPPORT */ | 2933 | |
2917 | #ifdef EPOLL_SUPPORT | 2934 | #ifdef EPOLL_SUPPORT |
2918 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | 2935 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && |
2919 | (NULL != daemon->eready_head) ) | 2936 | (NULL != daemon->eready_head) ) |
@@ -3009,6 +3026,10 @@ MHD_run_from_select (struct MHD_Daemon *daemon, | |||
3009 | unsigned int mask = MHD_ALLOW_SUSPEND_RESUME | MHD_USE_EPOLL_INTERNAL_THREAD | | 3026 | unsigned int mask = MHD_ALLOW_SUSPEND_RESUME | MHD_USE_EPOLL_INTERNAL_THREAD | |
3010 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_POLL_INTERNAL_THREAD; | 3027 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_POLL_INTERNAL_THREAD; |
3011 | 3028 | ||
3029 | /* Reset. New value will be set when connections are processed. */ | ||
3030 | /* Note: no-op for thread-per-connection as it is always false in that mode. */ | ||
3031 | daemon->data_already_pending = false; | ||
3032 | |||
3012 | /* Clear ITC to avoid spinning select */ | 3033 | /* Clear ITC to avoid spinning select */ |
3013 | /* Do it before any other processing so new signals | 3034 | /* Do it before any other processing so new signals |
3014 | will trigger select again and will be processed */ | 3035 | will trigger select again and will be processed */ |
@@ -3017,14 +3038,6 @@ MHD_run_from_select (struct MHD_Daemon *daemon, | |||
3017 | read_fd_set)) ) | 3038 | read_fd_set)) ) |
3018 | MHD_itc_clear_ (daemon->itc); | 3039 | MHD_itc_clear_ (daemon->itc); |
3019 | 3040 | ||
3020 | #ifdef HTTPS_SUPPORT | ||
3021 | /* Reset TLS read-ready. | ||
3022 | * New value will be set by read handlers. */ | ||
3023 | if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
3024 | (0 != (daemon->options & MHD_USE_TLS)) ) | ||
3025 | daemon->has_tls_recv_ready = 0; | ||
3026 | #endif /* HTTPS_SUPPORT */ | ||
3027 | |||
3028 | /* Resuming external connections when using an extern mainloop */ | 3041 | /* Resuming external connections when using an extern mainloop */ |
3029 | if (MHD_ALLOW_SUSPEND_RESUME == (daemon->options & mask)) | 3042 | if (MHD_ALLOW_SUSPEND_RESUME == (daemon->options & mask)) |
3030 | resume_suspended_connections (daemon); | 3043 | resume_suspended_connections (daemon); |
@@ -3364,7 +3377,6 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
3364 | break; | 3377 | break; |
3365 | case MHD_EVENT_LOOP_INFO_BLOCK: | 3378 | case MHD_EVENT_LOOP_INFO_BLOCK: |
3366 | p[poll_server+i].events |= MHD_POLL_EVENTS_ERR_DISC; | 3379 | p[poll_server+i].events |= MHD_POLL_EVENTS_ERR_DISC; |
3367 | timeout = 0; | ||
3368 | break; | 3380 | break; |
3369 | case MHD_EVENT_LOOP_INFO_CLEANUP: | 3381 | case MHD_EVENT_LOOP_INFO_CLEANUP: |
3370 | timeout = 0; /* clean up "pos" immediately */ | 3382 | timeout = 0; /* clean up "pos" immediately */ |
@@ -3412,6 +3424,10 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
3412 | free(p); | 3424 | free(p); |
3413 | return MHD_NO; | 3425 | return MHD_NO; |
3414 | } | 3426 | } |
3427 | |||
3428 | /* Reset. New value will be set when connections are processed. */ | ||
3429 | daemon->data_already_pending = false; | ||
3430 | |||
3415 | /* handle ITC FD */ | 3431 | /* handle ITC FD */ |
3416 | /* do it before any other processing so | 3432 | /* do it before any other processing so |
3417 | new signals will be processed in next loop */ | 3433 | new signals will be processed in next loop */ |
@@ -3419,14 +3435,6 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
3419 | (0 != (p[poll_itc_idx].revents & POLLIN)) ) | 3435 | (0 != (p[poll_itc_idx].revents & POLLIN)) ) |
3420 | MHD_itc_clear_ (daemon->itc); | 3436 | MHD_itc_clear_ (daemon->itc); |
3421 | 3437 | ||
3422 | #ifdef HTTPS_SUPPORT | ||
3423 | /* Reset TLS read-ready. | ||
3424 | * New value will be set by read handlers. */ | ||
3425 | if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
3426 | (0 != (daemon->options & MHD_USE_TLS)) ) | ||
3427 | daemon->has_tls_recv_ready = 0; | ||
3428 | #endif /* HTTPS_SUPPORT */ | ||
3429 | |||
3430 | /* handle shutdown */ | 3438 | /* handle shutdown */ |
3431 | if (daemon->shutdown) | 3439 | if (daemon->shutdown) |
3432 | { | 3440 | { |
@@ -3816,12 +3824,10 @@ MHD_epoll (struct MHD_Daemon *daemon, | |||
3816 | else | 3824 | else |
3817 | timeout_ms = 0; | 3825 | timeout_ms = 0; |
3818 | 3826 | ||
3819 | #ifdef HTTPS_SUPPORT | 3827 | /* Reset. New value will be set when connections are processed. */ |
3820 | /* Reset TLS read-ready. | 3828 | /* Note: Used mostly for uniformity here as same situation is |
3821 | * New value will be set by read handlers. */ | 3829 | * signaled in epoll mode by non-empty eready DLL. */ |
3822 | if ( 0 != (daemon->options & MHD_USE_TLS) ) | 3830 | daemon->data_already_pending = false; |
3823 | daemon->has_tls_recv_ready = false; | ||
3824 | #endif /* HTTPS_SUPPORT */ | ||
3825 | 3831 | ||
3826 | /* drain 'epoll' event queue; need to iterate as we get at most | 3832 | /* drain 'epoll' event queue; need to iterate as we get at most |
3827 | MAX_EVENTS in one system call here; in practice this should | 3833 | MAX_EVENTS in one system call here; in practice this should |