diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | src/microhttpd/connection.c | 7 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 120 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 31 | ||||
-rw-r--r-- | src/microhttpd/response.c | 8 |
5 files changed, 149 insertions, 26 deletions
@@ -1,4 +1,11 @@ | |||
1 | Thu Mar 17 10:45:31 MSK 2017 | 1 | Sun Mar 19 13:57:30 MSK 2017 |
2 | Rewritten logic of handling "upgraded" TLS connections in epoll mode: | ||
3 | used edge trigger instead of level trigger, | ||
4 | upgraded "ready" connection are stored in DL-list, | ||
5 | fixed handling of more than 128 ready connections, | ||
6 | fixed busy-waiting for idle "upgraded" TLS connections. -EG | ||
7 | |||
8 | Fri Mar 17 10:45:31 MSK 2017 | ||
2 | If read buffer is full, MHD need to receive remote data and application | 9 | If read buffer is full, MHD need to receive remote data and application |
3 | suspended connection, do not fail while connection is suspended and give | 10 | suspended connection, do not fail while connection is suspended and give |
4 | application one more chance to read data from buffer once connection is | 11 | application one more chance to read data from buffer once connection is |
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index 5c1a8611..36c05716 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -593,6 +593,13 @@ MHD_connection_finish_forward_ (struct MHD_Connection *connection) | |||
593 | { | 593 | { |
594 | MHD_PANIC (_("Failed to remove FD from epoll set\n")); | 594 | MHD_PANIC (_("Failed to remove FD from epoll set\n")); |
595 | } | 595 | } |
596 | if (urh->in_eready_list) | ||
597 | { | ||
598 | EDLL_remove (daemon->eready_urh_head, | ||
599 | daemon->eready_urh_tail, | ||
600 | urh); | ||
601 | urh->in_eready_list = false; | ||
602 | } | ||
596 | #endif /* EPOLL_SUPPORT */ | 603 | #endif /* EPOLL_SUPPORT */ |
597 | if (MHD_INVALID_SOCKET != urh->mhd.socket) | 604 | if (MHD_INVALID_SOCKET != urh->mhd.socket) |
598 | { | 605 | { |
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 03266204..991577b1 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -3252,7 +3252,11 @@ MHD_get_timeout (struct MHD_Daemon *daemon, | |||
3252 | 3252 | ||
3253 | #ifdef EPOLL_SUPPORT | 3253 | #ifdef EPOLL_SUPPORT |
3254 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | 3254 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && |
3255 | (NULL != daemon->eready_head) ) | 3255 | ((NULL != daemon->eready_head) |
3256 | #if defined(UPGRADE_SUPPORT) && defined(HTTPS_SUPPORT) | ||
3257 | || (NULL != daemon->eready_urh_head) | ||
3258 | #endif /* UPGRADE_SUPPORT && HTTPS_SUPPORT */ | ||
3259 | ) ) | ||
3256 | { | 3260 | { |
3257 | /* Some connection(s) already have some data pending. */ | 3261 | /* Some connection(s) already have some data pending. */ |
3258 | *timeout = 0; | 3262 | *timeout = 0; |
@@ -3972,6 +3976,47 @@ MHD_poll (struct MHD_Daemon *daemon, | |||
3972 | #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) | 3976 | #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) |
3973 | 3977 | ||
3974 | /** | 3978 | /** |
3979 | * Checks whether @a urh has some data to process. | ||
3980 | * | ||
3981 | * @param urh upgrade handler to analyse | ||
3982 | * @return 'true' if @a urh has some data to process, | ||
3983 | * 'false' otherwise | ||
3984 | */ | ||
3985 | static bool | ||
3986 | is_urh_ready(struct MHD_UpgradeResponseHandle * const urh) | ||
3987 | { | ||
3988 | const struct MHD_Connection * const connection = urh->connection; | ||
3989 | |||
3990 | if ( (0 == urh->in_buffer_size) && | ||
3991 | (0 == urh->out_buffer_size) && | ||
3992 | (0 == urh->in_buffer_used) && | ||
3993 | (0 == urh->out_buffer_used) ) | ||
3994 | return false; | ||
3995 | |||
3996 | if (connection->daemon->shutdown) | ||
3997 | return true; | ||
3998 | |||
3999 | if ( ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) || | ||
4000 | (connection->tls_read_ready) ) && | ||
4001 | (urh->in_buffer_used < urh->in_buffer_size) ) | ||
4002 | return true; | ||
4003 | |||
4004 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && | ||
4005 | (urh->out_buffer_used < urh->out_buffer_size) ) | ||
4006 | return true; | ||
4007 | |||
4008 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | ||
4009 | (urh->out_buffer_used > 0) ) | ||
4010 | return true; | ||
4011 | |||
4012 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | ||
4013 | (urh->in_buffer_used > 0) ) | ||
4014 | return true; | ||
4015 | |||
4016 | return false; | ||
4017 | } | ||
4018 | |||
4019 | /** | ||
3975 | * Do epoll()-based processing for TLS connections that have been | 4020 | * Do epoll()-based processing for TLS connections that have been |
3976 | * upgraded. This requires a separate epoll() invocation as we | 4021 | * upgraded. This requires a separate epoll() invocation as we |
3977 | * cannot use the `struct MHD_Connection` data structures for | 4022 | * cannot use the `struct MHD_Connection` data structures for |
@@ -3984,6 +4029,8 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
3984 | { | 4029 | { |
3985 | struct epoll_event events[MAX_EVENTS]; | 4030 | struct epoll_event events[MAX_EVENTS]; |
3986 | int num_events; | 4031 | int num_events; |
4032 | struct MHD_UpgradeResponseHandle * pos; | ||
4033 | struct MHD_UpgradeResponseHandle * prev; | ||
3987 | 4034 | ||
3988 | num_events = MAX_EVENTS; | 4035 | num_events = MAX_EVENTS; |
3989 | while (MAX_EVENTS == num_events) | 4036 | while (MAX_EVENTS == num_events) |
@@ -4006,45 +4053,74 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
4006 | #endif | 4053 | #endif |
4007 | return MHD_NO; | 4054 | return MHD_NO; |
4008 | } | 4055 | } |
4009 | for (i=0;i<(unsigned int) num_events;i++) | 4056 | for (i = 0; i < (unsigned int) num_events; i++) |
4010 | { | 4057 | { |
4011 | struct UpgradeEpollHandle * const ueh = events[i].data.ptr; | 4058 | struct UpgradeEpollHandle * const ueh = events[i].data.ptr; |
4012 | struct MHD_UpgradeResponseHandle * const urh = ueh->urh; | 4059 | struct MHD_UpgradeResponseHandle * const urh = ueh->urh; |
4060 | bool new_err_state = false; | ||
4013 | 4061 | ||
4014 | /* Each MHD_UpgradeResponseHandle can be processed two times: | ||
4015 | * one time for TLS data and one time for socketpair data. | ||
4016 | * If forwarding was finished on first time, second time must | ||
4017 | * be skipped as urh must not be used anymore. */ | ||
4018 | if (urh->clean_ready) | 4062 | if (urh->clean_ready) |
4019 | continue; | 4063 | continue; |
4020 | 4064 | ||
4021 | /* Update our state based on what is ready according to epoll() */ | 4065 | /* Update ueh state based on what is ready according to epoll() */ |
4022 | if (0 != (events[i].events & EPOLLIN)) | 4066 | if (0 != (events[i].events & EPOLLIN)) |
4023 | ueh->celi |= MHD_EPOLL_STATE_READ_READY; | 4067 | ueh->celi |= MHD_EPOLL_STATE_READ_READY; |
4024 | if (0 != (events[i].events & EPOLLOUT)) | 4068 | if (0 != (events[i].events & EPOLLOUT)) |
4025 | ueh->celi |= MHD_EPOLL_STATE_WRITE_READY; | 4069 | ueh->celi |= MHD_EPOLL_STATE_WRITE_READY; |
4026 | if (0 != (events[i].events & EPOLLHUP)) | 4070 | if (0 != (events[i].events & EPOLLHUP)) |
4027 | ueh->celi |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY; | 4071 | ueh->celi |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY; |
4028 | if (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) | ||
4029 | ueh->celi |= MHD_EPOLL_STATE_ERROR; | ||
4030 | 4072 | ||
4031 | process_urh (urh); | 4073 | if ( (0 == (ueh->celi & MHD_EPOLL_STATE_ERROR)) && |
4032 | /* Finished forwarding? */ | 4074 | (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) ) |
4033 | if ( (0 == urh->in_buffer_size) && | 4075 | { |
4034 | (0 == urh->out_buffer_size) && | 4076 | /* Process new error state only one time |
4035 | (0 == urh->in_buffer_used) && | 4077 | * and avoid continuously marking this connection |
4036 | (0 == urh->out_buffer_used) ) | 4078 | * as 'ready'. */ |
4079 | ueh->celi |= MHD_EPOLL_STATE_ERROR; | ||
4080 | new_err_state = true; | ||
4081 | } | ||
4082 | |||
4083 | if (! urh->in_eready_list) | ||
4037 | { | 4084 | { |
4038 | MHD_connection_finish_forward_ (urh->connection); | 4085 | if (new_err_state || |
4039 | urh->clean_ready = true; | 4086 | is_urh_ready(urh)) |
4040 | /* If 'urh->was_closed' set to true, connection will be | 4087 | { |
4041 | * moved immediately to cleanup list. Otherwise connection | 4088 | EDLL_insert (daemon->eready_urh_head, |
4042 | * will stay in suspended list until 'urh' will be marked | 4089 | daemon->eready_urh_tail, |
4043 | * with 'was_closed' by application. */ | 4090 | urh); |
4044 | MHD_resume_connection(urh->connection); | 4091 | urh->in_eready_list = true; |
4092 | } | ||
4045 | } | 4093 | } |
4046 | } | 4094 | } |
4047 | } | 4095 | } |
4096 | prev = daemon->eready_urh_tail; | ||
4097 | while (NULL != (pos = prev)) | ||
4098 | { | ||
4099 | prev = pos->prevE; | ||
4100 | process_urh (pos); | ||
4101 | if (! is_urh_ready(pos)) | ||
4102 | { | ||
4103 | EDLL_remove (daemon->eready_urh_head, | ||
4104 | daemon->eready_urh_tail, | ||
4105 | pos); | ||
4106 | pos->in_eready_list = false; | ||
4107 | } | ||
4108 | /* Finished forwarding? */ | ||
4109 | if ( (0 == pos->in_buffer_size) && | ||
4110 | (0 == pos->out_buffer_size) && | ||
4111 | (0 == pos->in_buffer_used) && | ||
4112 | (0 == pos->out_buffer_used) ) | ||
4113 | { | ||
4114 | MHD_connection_finish_forward_ (pos->connection); | ||
4115 | pos->clean_ready = true; | ||
4116 | /* If 'pos->was_closed' already was set to true, connection | ||
4117 | * will be moved immediately to cleanup list. Otherwise | ||
4118 | * connection will stay in suspended list until 'pos' will | ||
4119 | * be marked with 'was_closed' by application. */ | ||
4120 | MHD_resume_connection(pos->connection); | ||
4121 | } | ||
4122 | } | ||
4123 | |||
4048 | return MHD_YES; | 4124 | return MHD_YES; |
4049 | } | 4125 | } |
4050 | #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ | 4126 | #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 44590878..5350c013 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -1026,6 +1026,23 @@ struct MHD_UpgradeResponseHandle | |||
1026 | */ | 1026 | */ |
1027 | struct MHD_UpgradeResponseHandle *prev; | 1027 | struct MHD_UpgradeResponseHandle *prev; |
1028 | 1028 | ||
1029 | #ifdef EPOLL_SUPPORT | ||
1030 | /** | ||
1031 | * Next pointer for the EDLL listing urhs that are epoll-ready. | ||
1032 | */ | ||
1033 | struct MHD_UpgradeResponseHandle *nextE; | ||
1034 | |||
1035 | /** | ||
1036 | * Previous pointer for the EDLL listing urhs that are epoll-ready. | ||
1037 | */ | ||
1038 | struct MHD_UpgradeResponseHandle *prevE; | ||
1039 | |||
1040 | /** | ||
1041 | * Specifies whether urh already in EDLL list of ready connections. | ||
1042 | */ | ||
1043 | bool in_eready_list; | ||
1044 | #endif | ||
1045 | |||
1029 | /** | 1046 | /** |
1030 | * The buffer for receiving data from TLS to | 1047 | * The buffer for receiving data from TLS to |
1031 | * be passed to the application. Contains @e in_buffer_size | 1048 | * be passed to the application. Contains @e in_buffer_size |
@@ -1217,7 +1234,19 @@ struct MHD_Daemon | |||
1217 | * Tail of EDLL of connections ready for processing (in epoll mode) | 1234 | * Tail of EDLL of connections ready for processing (in epoll mode) |
1218 | */ | 1235 | */ |
1219 | struct MHD_Connection *eready_tail; | 1236 | struct MHD_Connection *eready_tail; |
1220 | #endif | 1237 | |
1238 | #ifdef UPGRADE_SUPPORT | ||
1239 | /** | ||
1240 | * Head of EDLL of upgraded connections ready for processing (in epoll mode). | ||
1241 | */ | ||
1242 | struct MHD_UpgradeResponseHandle *eready_urh_head; | ||
1243 | |||
1244 | /** | ||
1245 | * Tail of EDLL of upgraded connections ready for processing (in epoll mode) | ||
1246 | */ | ||
1247 | struct MHD_UpgradeResponseHandle *eready_urh_tail; | ||
1248 | #endif /* UPGRADE_SUPPORT */ | ||
1249 | #endif /* EPOLL_SUPPORT */ | ||
1221 | 1250 | ||
1222 | /** | 1251 | /** |
1223 | * Head of the XDLL of ALL connections with a default ('normal') | 1252 | * Head of the XDLL of ALL connections with a default ('normal') |
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index 9004013f..e8707480 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c | |||
@@ -851,7 +851,7 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
851 | 851 | ||
852 | EXTRA_CHECK (-1 != daemon->epoll_upgrade_fd); | 852 | EXTRA_CHECK (-1 != daemon->epoll_upgrade_fd); |
853 | /* First, add network socket */ | 853 | /* First, add network socket */ |
854 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; | 854 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; |
855 | event.data.ptr = &urh->app; | 855 | event.data.ptr = &urh->app; |
856 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | 856 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, |
857 | EPOLL_CTL_ADD, | 857 | EPOLL_CTL_ADD, |
@@ -870,7 +870,7 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
870 | } | 870 | } |
871 | 871 | ||
872 | /* Second, add our end of the UNIX socketpair() */ | 872 | /* Second, add our end of the UNIX socketpair() */ |
873 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; | 873 | event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; |
874 | event.data.ptr = &urh->mhd; | 874 | event.data.ptr = &urh->mhd; |
875 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | 875 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, |
876 | EPOLL_CTL_ADD, | 876 | EPOLL_CTL_ADD, |
@@ -894,6 +894,10 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
894 | free (urh); | 894 | free (urh); |
895 | return MHD_NO; | 895 | return MHD_NO; |
896 | } | 896 | } |
897 | EDLL_insert (daemon->eready_urh_head, | ||
898 | daemon->eready_urh_tail, | ||
899 | urh); | ||
900 | urh->in_eready_list = true; | ||
897 | } | 901 | } |
898 | #endif /* EPOLL_SUPPORT */ | 902 | #endif /* EPOLL_SUPPORT */ |
899 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) | 903 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) |