diff options
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r-- | src/microhttpd/daemon.c | 145 |
1 files changed, 111 insertions, 34 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 487575e0..929a76ba 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -653,25 +653,29 @@ urh_to_fdset (struct MHD_UpgradeResponseHandle *urh, | |||
653 | MHD_socket *max_fd, | 653 | MHD_socket *max_fd, |
654 | unsigned int fd_setsize) | 654 | unsigned int fd_setsize) |
655 | { | 655 | { |
656 | if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && | 656 | if ( (urh->out_buffer_off < urh->out_buffer_size) && |
657 | (MHD_INVALID_SOCKET != urh->mhd.socket) && | ||
657 | (! MHD_add_to_fd_set_ (urh->mhd.socket, | 658 | (! MHD_add_to_fd_set_ (urh->mhd.socket, |
658 | rs, | 659 | rs, |
659 | max_fd, | 660 | max_fd, |
660 | fd_setsize)) ) | 661 | fd_setsize)) ) |
661 | return MHD_NO; | 662 | return MHD_NO; |
662 | if ( (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | 663 | if ( (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && |
664 | (MHD_INVALID_SOCKET != urh->mhd.socket) && | ||
663 | (! MHD_add_to_fd_set_ (urh->mhd.socket, | 665 | (! MHD_add_to_fd_set_ (urh->mhd.socket, |
664 | ws, | 666 | ws, |
665 | max_fd, | 667 | max_fd, |
666 | fd_setsize)) ) | 668 | fd_setsize)) ) |
667 | return MHD_NO; | 669 | return MHD_NO; |
668 | if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) && | 670 | if ( (urh->in_buffer_off < urh->in_buffer_size) && |
671 | (MHD_INVALID_SOCKET != urh->connection->socket_fd) && | ||
669 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, | 672 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, |
670 | rs, | 673 | rs, |
671 | max_fd, | 674 | max_fd, |
672 | fd_setsize)) ) | 675 | fd_setsize)) ) |
673 | return MHD_NO; | 676 | return MHD_NO; |
674 | if ( (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | 677 | if ( (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && |
678 | (MHD_INVALID_SOCKET != urh->connection->socket_fd) && | ||
675 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, | 679 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, |
676 | ws, | 680 | ws, |
677 | max_fd, | 681 | max_fd, |
@@ -966,6 +970,12 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
966 | { | 970 | { |
967 | urh->in_buffer_off += res; | 971 | urh->in_buffer_off += res; |
968 | } | 972 | } |
973 | if (0 == res) | ||
974 | { | ||
975 | /* connection was shut down, signal by shrinking buffer, | ||
976 | which will eventually ensure this FD is no longer listed. */ | ||
977 | urh->in_buffer_size = urh->in_buffer_off; | ||
978 | } | ||
969 | } | 979 | } |
970 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | 980 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && |
971 | (urh->in_buffer_off > 0) ) | 981 | (urh->in_buffer_off > 0) ) |
@@ -977,8 +987,18 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
977 | urh->in_buffer_off); | 987 | urh->in_buffer_off); |
978 | if (-1 == res) | 988 | if (-1 == res) |
979 | { | 989 | { |
980 | /* FIXME: differenciate by errno? */ | 990 | int err = MHD_socket_get_error_ (); |
981 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | 991 | |
992 | if ( (MHD_SCKT_ERR_IS_EINTR_ (err)) || | ||
993 | (MHD_SCKT_ERR_IS_EAGAIN_ (err)) ) | ||
994 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
995 | else | ||
996 | { | ||
997 | /* persistent / unrecoverable error, treat as | ||
998 | if connection was shut down */ | ||
999 | urh->in_buffer_size = 0; | ||
1000 | urh->in_buffer_off = 0; | ||
1001 | } | ||
982 | } | 1002 | } |
983 | else | 1003 | else |
984 | { | 1004 | { |
@@ -1014,6 +1034,12 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1014 | { | 1034 | { |
1015 | urh->out_buffer_off += res; | 1035 | urh->out_buffer_off += res; |
1016 | } | 1036 | } |
1037 | if (0 == res) | ||
1038 | { | ||
1039 | /* connection was shut down, signal by shrinking buffer, | ||
1040 | which will eventually ensure this FD is no longer listed. */ | ||
1041 | urh->out_buffer_size = urh->out_buffer_off; | ||
1042 | } | ||
1017 | fin_read = (0 == res); | 1043 | fin_read = (0 == res); |
1018 | } | 1044 | } |
1019 | else | 1045 | else |
@@ -1045,6 +1071,13 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1045 | urh->out_buffer_off = 0; | 1071 | urh->out_buffer_off = 0; |
1046 | } | 1072 | } |
1047 | } | 1073 | } |
1074 | else | ||
1075 | { | ||
1076 | /* persistent / unrecoverable error, treat as | ||
1077 | if connection was shut down */ | ||
1078 | urh->out_buffer_size = 0; | ||
1079 | urh->out_buffer_off = 0; | ||
1080 | } | ||
1048 | } | 1081 | } |
1049 | if ( (fin_read) && | 1082 | if ( (fin_read) && |
1050 | (0 == urh->out_buffer_off) && | 1083 | (0 == urh->out_buffer_off) && |
@@ -1064,20 +1097,10 @@ static void | |||
1064 | thread_main_connection_upgrade (struct MHD_Connection *con) | 1097 | thread_main_connection_upgrade (struct MHD_Connection *con) |
1065 | { | 1098 | { |
1066 | struct MHD_Daemon *daemon = con->daemon; | 1099 | struct MHD_Daemon *daemon = con->daemon; |
1100 | struct MHD_UpgradeResponseHandle *urh = con->urh; | ||
1067 | 1101 | ||
1068 | if (0 == (daemon->options & MHD_USE_SSL)) | ||
1069 | { | ||
1070 | /* Here, we need to block until the application | ||
1071 | signals us that it is done with the socket */ | ||
1072 | MHD_semaphore_down (con->upgrade_sem); | ||
1073 | MHD_semaphore_destroy (con->upgrade_sem); | ||
1074 | con->upgrade_sem = NULL; | ||
1075 | return; | ||
1076 | } | ||
1077 | #if HTTPS_SUPPORT | 1102 | #if HTTPS_SUPPORT |
1078 | { | 1103 | { |
1079 | struct MHD_UpgradeResponseHandle *urh = con->urh; | ||
1080 | |||
1081 | /* Here, we need to bi-directionally forward | 1104 | /* Here, we need to bi-directionally forward |
1082 | until the application tells us that it is done | 1105 | until the application tells us that it is done |
1083 | with the socket; */ | 1106 | with the socket; */ |
@@ -1108,11 +1131,14 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1108 | #endif | 1131 | #endif |
1109 | break; | 1132 | break; |
1110 | } | 1133 | } |
1111 | num_ready = MHD_SYS_select_ (max_fd + 1, | 1134 | if (MHD_INVALID_SOCKET != max_fd) |
1112 | &rs, | 1135 | num_ready = MHD_SYS_select_ (max_fd + 1, |
1113 | &ws, | 1136 | &rs, |
1114 | NULL, | 1137 | &ws, |
1115 | NULL); | 1138 | NULL, |
1139 | NULL); | ||
1140 | else | ||
1141 | num_ready = 0; | ||
1116 | if (num_ready < 0) | 1142 | if (num_ready < 0) |
1117 | { | 1143 | { |
1118 | const int err = MHD_socket_get_error_(); | 1144 | const int err = MHD_socket_get_error_(); |
@@ -1131,31 +1157,37 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1131 | &rs, | 1157 | &rs, |
1132 | &ws); | 1158 | &ws); |
1133 | process_urh (urh); | 1159 | process_urh (urh); |
1160 | if ( (0 == urh->out_buffer_size) && | ||
1161 | (0 == urh->in_buffer_size) ) | ||
1162 | break; /* connections died, we have no more purpose here */ | ||
1134 | } | 1163 | } |
1135 | } | 1164 | } |
1136 | #ifdef HAVE_POLL | 1165 | #ifdef HAVE_POLL |
1137 | else | 1166 | else |
1138 | { | 1167 | { |
1139 | /* use poll() */ | 1168 | /* use poll() */ |
1140 | struct pollfd p[2]; | ||
1141 | const unsigned int timeout = UINT_MAX; | 1169 | const unsigned int timeout = UINT_MAX; |
1142 | 1170 | ||
1143 | p[0].fd = urh->connection->socket_fd; | ||
1144 | p[1].fd = urh->mhd.socket; | ||
1145 | while (MHD_CONNECTION_UPGRADE == con->state) | 1171 | while (MHD_CONNECTION_UPGRADE == con->state) |
1146 | { | 1172 | { |
1147 | if (0 == (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) | 1173 | struct pollfd p[2]; |
1174 | |||
1175 | memset (p, 0, sizeof (struct pollfd) * 2); | ||
1176 | p[0].fd = urh->connection->socket_fd; | ||
1177 | p[1].fd = urh->mhd.socket; | ||
1178 | if (urh->in_buffer_off < urh->in_buffer_size) | ||
1148 | p[0].events |= POLLIN; | 1179 | p[0].events |= POLLIN; |
1149 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) | 1180 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) |
1150 | p[0].events |= POLLOUT; | 1181 | p[0].events |= POLLOUT; |
1151 | if (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) | 1182 | if (urh->out_buffer_off < urh->out_buffer_size) |
1152 | p[1].events |= POLLIN; | 1183 | p[1].events |= POLLIN; |
1153 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) | 1184 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) |
1154 | p[1].events |= POLLOUT; | 1185 | p[1].events |= POLLOUT; |
1155 | 1186 | ||
1156 | if (MHD_sys_poll_ (p, | 1187 | if ( (0 != (p[0].events | p[1].events)) && |
1157 | 2, | 1188 | (MHD_sys_poll_ (p, |
1158 | timeout) < 0) | 1189 | 2, |
1190 | timeout) < 0) ) | ||
1159 | { | 1191 | { |
1160 | const int err = MHD_socket_get_error_ (); | 1192 | const int err = MHD_socket_get_error_ (); |
1161 | 1193 | ||
@@ -1177,6 +1209,9 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1177 | if (0 != (p[1].revents & POLLOUT)) | 1209 | if (0 != (p[1].revents & POLLOUT)) |
1178 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; | 1210 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; |
1179 | process_urh (urh); | 1211 | process_urh (urh); |
1212 | if ( (0 == urh->out_buffer_size) && | ||
1213 | (0 == urh->in_buffer_size) ) | ||
1214 | break; /* connections died, we have no more purpose here */ | ||
1180 | } | 1215 | } |
1181 | } | 1216 | } |
1182 | /* end POLL */ | 1217 | /* end POLL */ |
@@ -1187,6 +1222,13 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1187 | MHD_PANIC ("This should not be possible\n"); | 1222 | MHD_PANIC ("This should not be possible\n"); |
1188 | #endif | 1223 | #endif |
1189 | } | 1224 | } |
1225 | |||
1226 | /* Here, we need to block until the application | ||
1227 | signals us that it is done with the socket */ | ||
1228 | MHD_semaphore_down (con->upgrade_sem); | ||
1229 | MHD_semaphore_destroy (con->upgrade_sem); | ||
1230 | con->upgrade_sem = NULL; | ||
1231 | free (urh); | ||
1190 | } | 1232 | } |
1191 | 1233 | ||
1192 | 1234 | ||
@@ -2598,6 +2640,7 @@ MHD_run_from_select (struct MHD_Daemon *daemon, | |||
2598 | struct MHD_Connection *next; | 2640 | struct MHD_Connection *next; |
2599 | #if HTTPS_SUPPORT | 2641 | #if HTTPS_SUPPORT |
2600 | struct MHD_UpgradeResponseHandle *urh; | 2642 | struct MHD_UpgradeResponseHandle *urh; |
2643 | struct MHD_UpgradeResponseHandle *urhn; | ||
2601 | #endif | 2644 | #endif |
2602 | unsigned int mask = MHD_USE_SUSPEND_RESUME | MHD_USE_EPOLL_INTERNALLY | | 2645 | unsigned int mask = MHD_USE_SUSPEND_RESUME | MHD_USE_EPOLL_INTERNALLY | |
2603 | MHD_USE_SELECT_INTERNALLY | MHD_USE_POLL_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION; | 2646 | MHD_USE_SELECT_INTERNALLY | MHD_USE_POLL_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION; |
@@ -2650,8 +2693,9 @@ MHD_run_from_select (struct MHD_Daemon *daemon, | |||
2650 | 2693 | ||
2651 | /* handle upgraded HTTPS connections */ | 2694 | /* handle upgraded HTTPS connections */ |
2652 | #if HTTPS_SUPPORT | 2695 | #if HTTPS_SUPPORT |
2653 | for (urh = daemon->urh_head; NULL != urh; urh = urh->next) | 2696 | for (urh = daemon->urh_head; NULL != urh; urh = urhn) |
2654 | { | 2697 | { |
2698 | urhn = urh->next; | ||
2655 | /* update urh state based on select() output */ | 2699 | /* update urh state based on select() output */ |
2656 | urh_from_fdset (urh, | 2700 | urh_from_fdset (urh, |
2657 | read_fd_set, | 2701 | read_fd_set, |
@@ -2934,13 +2978,13 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
2934 | for (urh = daemon->urh_head; NULL != urh; urh = urh->next) | 2978 | for (urh = daemon->urh_head; NULL != urh; urh = urh->next) |
2935 | { | 2979 | { |
2936 | p[poll_server+i].fd = urh->connection->socket_fd; | 2980 | p[poll_server+i].fd = urh->connection->socket_fd; |
2937 | if (0 == (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) | 2981 | if (urh->in_buffer_off < urh->in_buffer_size) |
2938 | p[poll_server+i].events |= POLLIN; | 2982 | p[poll_server+i].events |= POLLIN; |
2939 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) | 2983 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) |
2940 | p[poll_server+i].events |= POLLOUT; | 2984 | p[poll_server+i].events |= POLLOUT; |
2941 | i++; | 2985 | i++; |
2942 | p[poll_server+i].fd = urh->mhd.socket; | 2986 | p[poll_server+i].fd = urh->mhd.socket; |
2943 | if (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) | 2987 | if (urh->out_buffer_off < urh->out_buffer_size) |
2944 | p[poll_server+i].events |= POLLIN; | 2988 | p[poll_server+i].events |= POLLIN; |
2945 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) | 2989 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) |
2946 | p[poll_server+i].events |= POLLOUT; | 2990 | p[poll_server+i].events |= POLLOUT; |
@@ -2952,7 +2996,9 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
2952 | free(p); | 2996 | free(p); |
2953 | return MHD_YES; | 2997 | return MHD_YES; |
2954 | } | 2998 | } |
2955 | if (MHD_sys_poll_(p, poll_server + num_connections, timeout) < 0) | 2999 | if (MHD_sys_poll_(p, |
3000 | poll_server + num_connections, | ||
3001 | timeout) < 0) | ||
2956 | { | 3002 | { |
2957 | const int err = MHD_socket_get_error_ (); | 3003 | const int err = MHD_socket_get_error_ (); |
2958 | if (MHD_SCKT_ERR_IS_EINTR_ (err)) | 3004 | if (MHD_SCKT_ERR_IS_EINTR_ (err)) |
@@ -2988,17 +3034,20 @@ MHD_poll_all (struct MHD_Daemon *daemon, | |||
2988 | next = pos->next; | 3034 | next = pos->next; |
2989 | /* first, sanity checks */ | 3035 | /* first, sanity checks */ |
2990 | if (i >= num_connections) | 3036 | if (i >= num_connections) |
2991 | continue; /* connection list changed somehow, retry later ... */ | 3037 | break; /* connection list changed somehow, retry later ... */ |
2992 | if (p[poll_server+i].fd != pos->socket_fd) | 3038 | if (p[poll_server+i].fd != pos->socket_fd) |
2993 | continue; /* fd mismatch, something else happened, retry later ... */ | 3039 | continue; /* fd mismatch, something else happened, retry later ... */ |
2994 | call_handlers (pos, | 3040 | call_handlers (pos, |
2995 | 0 != (p[poll_server+i].revents & POLLIN), | 3041 | 0 != (p[poll_server+i].revents & POLLIN), |
2996 | 0 != (p[poll_server+i].revents & POLLOUT), | 3042 | 0 != (p[poll_server+i].revents & POLLOUT), |
2997 | MHD_NO); | 3043 | MHD_NO); |
3044 | i++; | ||
2998 | } | 3045 | } |
2999 | #if HTTPS_SUPPORT | 3046 | #if HTTPS_SUPPORT |
3000 | for (urh = daemon->urh_head; NULL != urh; urh = urhn) | 3047 | for (urh = daemon->urh_head; NULL != urh; urh = urhn) |
3001 | { | 3048 | { |
3049 | if (i >= num_connections) | ||
3050 | break; /* connection list changed somehow, retry later ... */ | ||
3002 | urhn = urh->next; | 3051 | urhn = urh->next; |
3003 | if (p[poll_server+i].fd != urh->connection->socket_fd) | 3052 | if (p[poll_server+i].fd != urh->connection->socket_fd) |
3004 | continue; /* fd mismatch, something else happened, retry later ... */ | 3053 | continue; /* fd mismatch, something else happened, retry later ... */ |
@@ -3148,6 +3197,7 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
3148 | struct epoll_event events[MAX_EVENTS]; | 3197 | struct epoll_event events[MAX_EVENTS]; |
3149 | int num_events; | 3198 | int num_events; |
3150 | unsigned int i; | 3199 | unsigned int i; |
3200 | unsigned int j; | ||
3151 | 3201 | ||
3152 | num_events = MAX_EVENTS; | 3202 | num_events = MAX_EVENTS; |
3153 | while (MAX_EVENTS == num_events) | 3203 | while (MAX_EVENTS == num_events) |
@@ -3172,7 +3222,34 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
3172 | for (i=0;i<(unsigned int) num_events;i++) | 3222 | for (i=0;i<(unsigned int) num_events;i++) |
3173 | { | 3223 | { |
3174 | struct UpgradeEpollHandle *ueh = events[i].data.ptr; | 3224 | struct UpgradeEpollHandle *ueh = events[i].data.ptr; |
3175 | struct MHD_UpgradeResponseHandle *urh = ueh->urh; | 3225 | struct MHD_UpgradeResponseHandle *urh; |
3226 | |||
3227 | if (NULL == ueh) | ||
3228 | continue; /* was killed, see below */ | ||
3229 | urh = ueh->urh; | ||
3230 | |||
3231 | /* In case we get two events for the same upgrade handle, | ||
3232 | squash them together (otherwise the first one may | ||
3233 | cause us to free the 'urh', and the second one then | ||
3234 | causes a use-after-free). */ | ||
3235 | for (j=i+1;j< (unsigned int) num_events;j++) | ||
3236 | { | ||
3237 | struct UpgradeEpollHandle *uehj = events[j].data.ptr; | ||
3238 | struct MHD_UpgradeResponseHandle *urhj; | ||
3239 | |||
3240 | if (NULL == uehj) | ||
3241 | continue; /* was killed, see below */ | ||
3242 | urhj = uehj->urh; | ||
3243 | |||
3244 | if (urh == urhj) /* yep, indeed the same! */ | ||
3245 | { | ||
3246 | if (0 != (events[j].events & EPOLLIN)) | ||
3247 | uehj->celi |= MHD_EPOLL_STATE_READ_READY; | ||
3248 | if (0 != (events[j].events & EPOLLOUT)) | ||
3249 | uehj->celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
3250 | } | ||
3251 | events[j].data.ptr = NULL; /* kill this one */ | ||
3252 | } | ||
3176 | 3253 | ||
3177 | /* Update our state based on what is ready according to epoll() */ | 3254 | /* Update our state based on what is ready according to epoll() */ |
3178 | if (0 != (events[i].events & EPOLLIN)) | 3255 | if (0 != (events[i].events & EPOLLIN)) |