diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2017-03-02 22:17:11 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2017-03-13 23:48:17 +0300 |
commit | 1855c73cd340ae6273251728e8d6d500b2c1119b (patch) | |
tree | b19ed47f90b98d6313f3859af1d099cfc192c2aa /src/microhttpd/daemon.c | |
parent | 8dadd66ddef2d9320b0a60b9bf7881f42b127c93 (diff) | |
download | libmicrohttpd-1855c73cd340ae6273251728e8d6d500b2c1119b.tar.gz libmicrohttpd-1855c73cd340ae6273251728e8d6d500b2c1119b.zip |
Corrected monitor 'upgraded' sockets for errors, corrected handling of error and
streamlined forwarding processing logic.
Added some comments.
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r-- | src/microhttpd/daemon.c | 309 |
1 files changed, 191 insertions, 118 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index bc10c795..b89c3d57 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -698,6 +698,8 @@ urh_to_fdset (struct MHD_UpgradeResponseHandle *urh, | |||
698 | const MHD_socket mhd_sckt = urh->mhd.socket; | 698 | const MHD_socket mhd_sckt = urh->mhd.socket; |
699 | bool res = true; | 699 | bool res = true; |
700 | 700 | ||
701 | /* Do not add to 'es' only if socket is closed | ||
702 | * or not used anymore. */ | ||
701 | if (MHD_INVALID_SOCKET != conn_sckt) | 703 | if (MHD_INVALID_SOCKET != conn_sckt) |
702 | { | 704 | { |
703 | if ( (urh->in_buffer_used < urh->in_buffer_size) && | 705 | if ( (urh->in_buffer_used < urh->in_buffer_size) && |
@@ -712,7 +714,12 @@ urh_to_fdset (struct MHD_UpgradeResponseHandle *urh, | |||
712 | max_fd, | 714 | max_fd, |
713 | fd_setsize)) ) | 715 | fd_setsize)) ) |
714 | res = false; | 716 | res = false; |
715 | if (0 != urh->in_buffer_size) | 717 | /* Do not monitor again for errors if error was detected before as |
718 | * error state is remembered. */ | ||
719 | if ((0 == urh->app.celi & MHD_EPOLL_STATE_ERROR) && | ||
720 | ((0 != urh->in_buffer_size) || | ||
721 | (0 != urh->out_buffer_size) || | ||
722 | (0 != urh->out_buffer_used))) | ||
716 | MHD_add_to_fd_set_ (conn_sckt, | 723 | MHD_add_to_fd_set_ (conn_sckt, |
717 | es, | 724 | es, |
718 | max_fd, | 725 | max_fd, |
@@ -732,7 +739,12 @@ urh_to_fdset (struct MHD_UpgradeResponseHandle *urh, | |||
732 | max_fd, | 739 | max_fd, |
733 | fd_setsize)) ) | 740 | fd_setsize)) ) |
734 | res = false; | 741 | res = false; |
735 | if (0 != urh->out_buffer_size) | 742 | /* Do not monitor again for errors if error was detected before as |
743 | * error state is remembered. */ | ||
744 | if ((0 == urh->mhd.celi & MHD_EPOLL_STATE_ERROR) && | ||
745 | ((0 != urh->out_buffer_size) || | ||
746 | (0 != urh->in_buffer_size) || | ||
747 | (0 != urh->in_buffer_used))) | ||
736 | MHD_add_to_fd_set_ (mhd_sckt, | 748 | MHD_add_to_fd_set_ (mhd_sckt, |
737 | es, | 749 | es, |
738 | max_fd, | 750 | max_fd, |
@@ -761,8 +773,9 @@ urh_from_fdset (struct MHD_UpgradeResponseHandle *urh, | |||
761 | const MHD_socket conn_sckt = urh->connection->socket_fd; | 773 | const MHD_socket conn_sckt = urh->connection->socket_fd; |
762 | const MHD_socket mhd_sckt = urh->mhd.socket; | 774 | const MHD_socket mhd_sckt = urh->mhd.socket; |
763 | 775 | ||
764 | urh->app.celi = MHD_EPOLL_STATE_UNREADY; | 776 | /* Reset read/write ready, preserve error state. */ |
765 | urh->mhd.celi = MHD_EPOLL_STATE_UNREADY; | 777 | urh->app.celi &= (~MHD_EPOLL_STATE_READ_READY && ~MHD_EPOLL_STATE_WRITE_READY); |
778 | urh->mhd.celi &= (~MHD_EPOLL_STATE_READ_READY && ~MHD_EPOLL_STATE_WRITE_READY); | ||
766 | 779 | ||
767 | if (MHD_INVALID_SOCKET != conn_sckt) | 780 | if (MHD_INVALID_SOCKET != conn_sckt) |
768 | { | 781 | { |
@@ -799,17 +812,31 @@ urh_update_pollfd(struct MHD_UpgradeResponseHandle *urh, | |||
799 | { | 812 | { |
800 | p[0].events = 0; | 813 | p[0].events = 0; |
801 | p[1].events = 0; | 814 | p[1].events = 0; |
815 | |||
802 | if (urh->in_buffer_used < urh->in_buffer_size) | 816 | if (urh->in_buffer_used < urh->in_buffer_size) |
803 | p[0].events |= POLLIN | MHD_POLL_EVENTS_ERR_DISC; | 817 | p[0].events |= POLLIN; |
804 | if (0 != urh->out_buffer_used) | 818 | if (0 != urh->out_buffer_used) |
805 | p[0].events |= POLLOUT | MHD_POLL_EVENTS_ERR_DISC; | 819 | p[0].events |= POLLOUT; |
806 | if (0 != urh->in_buffer_size) | 820 | |
821 | /* Do not monitor again for errors if error was detected before as | ||
822 | * error state is remembered. */ | ||
823 | if ((0 == urh->app.celi & MHD_EPOLL_STATE_ERROR) && | ||
824 | ((0 != urh->in_buffer_size) || | ||
825 | (0 != urh->out_buffer_size) || | ||
826 | (0 != urh->out_buffer_used))) | ||
807 | p[0].events |= MHD_POLL_EVENTS_ERR_DISC; | 827 | p[0].events |= MHD_POLL_EVENTS_ERR_DISC; |
828 | |||
808 | if (urh->out_buffer_used < urh->out_buffer_size) | 829 | if (urh->out_buffer_used < urh->out_buffer_size) |
809 | p[1].events |= POLLIN | MHD_POLL_EVENTS_ERR_DISC; | 830 | p[1].events |= POLLIN; |
810 | if (0 != urh->in_buffer_used) | 831 | if (0 != urh->in_buffer_used) |
811 | p[1].events |= POLLOUT | MHD_POLL_EVENTS_ERR_DISC; | 832 | p[1].events |= POLLOUT; |
812 | if (0 != urh->out_buffer_size) | 833 | |
834 | /* Do not monitor again for errors if error was detected before as | ||
835 | * error state is remembered. */ | ||
836 | if ((0 == urh->mhd.celi & MHD_EPOLL_STATE_ERROR) && | ||
837 | ((0 != urh->out_buffer_size) || | ||
838 | (0 != urh->in_buffer_size) || | ||
839 | (0 != urh->in_buffer_used))) | ||
813 | p[1].events |= MHD_POLL_EVENTS_ERR_DISC; | 840 | p[1].events |= MHD_POLL_EVENTS_ERR_DISC; |
814 | } | 841 | } |
815 | 842 | ||
@@ -839,18 +866,26 @@ static void | |||
839 | urh_from_pollfd(struct MHD_UpgradeResponseHandle *urh, | 866 | urh_from_pollfd(struct MHD_UpgradeResponseHandle *urh, |
840 | struct pollfd p[2]) | 867 | struct pollfd p[2]) |
841 | { | 868 | { |
869 | /* Reset read/write ready, preserve error state. */ | ||
870 | urh->app.celi &= (~MHD_EPOLL_STATE_READ_READY && ~MHD_EPOLL_STATE_WRITE_READY); | ||
871 | urh->mhd.celi &= (~MHD_EPOLL_STATE_READ_READY && ~MHD_EPOLL_STATE_WRITE_READY); | ||
872 | |||
842 | if (0 != (p[0].revents & POLLIN)) | 873 | if (0 != (p[0].revents & POLLIN)) |
843 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; | 874 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; |
844 | if (0 != (p[0].revents & POLLOUT)) | 875 | if (0 != (p[0].revents & POLLOUT)) |
845 | urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; | 876 | urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; |
846 | if (0 != (p[0].revents & MHD_POLL_REVENTS_ERR_DISC)) | 877 | if (0 != (p[0].revents & POLLHUP)) |
878 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY; | ||
879 | if (0 != (p[0].revents & MHD_POLL_REVENTS_ERRROR)) | ||
847 | urh->app.celi |= MHD_EPOLL_STATE_ERROR; | 880 | urh->app.celi |= MHD_EPOLL_STATE_ERROR; |
848 | if (0 != (p[1].revents & POLLIN)) | 881 | if (0 != (p[1].revents & POLLIN)) |
849 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | 882 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; |
850 | if (0 != (p[1].revents & POLLOUT)) | 883 | if (0 != (p[1].revents & POLLOUT)) |
851 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; | 884 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; |
852 | if (0 != (p[1].revents & MHD_POLL_REVENTS_ERR_DISC)) | 885 | if (0 != (p[1].revents & POLLHUP)) |
853 | urh->mhd.celi |= MHD_EPOLL_STATE_ERROR; | 886 | urh->mhd.celi |= MHD_EPOLL_STATE_ERROR; |
887 | if (0 != (p[1].revents & MHD_POLL_REVENTS_ERRROR)) | ||
888 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY; | ||
854 | } | 889 | } |
855 | #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ | 890 | #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ |
856 | 891 | ||
@@ -1165,6 +1200,8 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1165 | * each time. */ | 1200 | * each time. */ |
1166 | struct MHD_Connection * const connection = urh->connection; | 1201 | struct MHD_Connection * const connection = urh->connection; |
1167 | struct MHD_Daemon * const daemon = connection->daemon; | 1202 | struct MHD_Daemon * const daemon = connection->daemon; |
1203 | /* Prevent data races. */ | ||
1204 | bool was_closed; | ||
1168 | if (daemon->shutdown) | 1205 | if (daemon->shutdown) |
1169 | { | 1206 | { |
1170 | /* Daemon shutting down, application will not receive any more data. */ | 1207 | /* Daemon shutting down, application will not receive any more data. */ |
@@ -1177,7 +1214,8 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1177 | #endif | 1214 | #endif |
1178 | urh->was_closed = true; | 1215 | urh->was_closed = true; |
1179 | } | 1216 | } |
1180 | if (urh->was_closed) | 1217 | was_closed = urh->was_closed; |
1218 | if (was_closed) | ||
1181 | { | 1219 | { |
1182 | /* Application was closed connections: no more data | 1220 | /* Application was closed connections: no more data |
1183 | * can be forwarded to application socket. */ | 1221 | * can be forwarded to application socket. */ |
@@ -1191,6 +1229,13 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1191 | #endif | 1229 | #endif |
1192 | 1230 | ||
1193 | } | 1231 | } |
1232 | /* If application signaled MHD about socket closure then | ||
1233 | * check for any pending data even if socket is not marked | ||
1234 | * as 'ready' (signal may arrive after poll()/select()). | ||
1235 | * Socketpair for forwarding is always in non-blocking mode | ||
1236 | * so no risk that recv() will block the thread. */ | ||
1237 | if (0 != urh->out_buffer_size) | ||
1238 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
1194 | /* Discard any data received form remote. */ | 1239 | /* Discard any data received form remote. */ |
1195 | urh->in_buffer_used = 0; | 1240 | urh->in_buffer_used = 0; |
1196 | /* Do not try to push data to application. */ | 1241 | /* Do not try to push data to application. */ |
@@ -1201,13 +1246,19 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1201 | connection->tls_read_ready = false; | 1246 | connection->tls_read_ready = false; |
1202 | } | 1247 | } |
1203 | 1248 | ||
1204 | /* Some platforms (W32, possibly Darwin) may discard data in system buffers | 1249 | /* On some platforms (W32, possibly Darwin) failed send() (send() will always |
1205 | * received by system but unread by recv() if remote side was disconnected | 1250 | * fail after remote disconnect was detected) may discard data in system |
1206 | * and failed send() attempted (send() will always fail after remote disconnect | 1251 | * buffers received by system but not yet read by recv(). |
1207 | * was detected). | ||
1208 | * So, before trying send() on any socket, recv() must be performed at first | 1252 | * So, before trying send() on any socket, recv() must be performed at first |
1209 | * otherwise last part of incoming data may be lost. */ | 1253 | * otherwise last part of incoming data may be lost. */ |
1210 | 1254 | ||
1255 | /* If disconnect or error was detected - try to read from socket | ||
1256 | * to dry data possibly pending is system buffers. */ | ||
1257 | if (0 != (MHD_EPOLL_STATE_ERROR & urh->app.celi)) | ||
1258 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; | ||
1259 | if (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) | ||
1260 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
1261 | |||
1211 | /* | 1262 | /* |
1212 | * handle reading from remote TLS client | 1263 | * handle reading from remote TLS client |
1213 | */ | 1264 | */ |
@@ -1226,9 +1277,7 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1226 | res = gnutls_record_recv (connection->tls_session, | 1277 | res = gnutls_record_recv (connection->tls_session, |
1227 | &urh->in_buffer[urh->in_buffer_used], | 1278 | &urh->in_buffer[urh->in_buffer_used], |
1228 | buf_size); | 1279 | buf_size); |
1229 | if (GNUTLS_E_AGAIN == res) | 1280 | if (0 < res) |
1230 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1231 | else if (res > 0) | ||
1232 | { | 1281 | { |
1233 | urh->in_buffer_used += res; | 1282 | urh->in_buffer_used += res; |
1234 | if (buf_size > (size_t)res) | 1283 | if (buf_size > (size_t)res) |
@@ -1236,26 +1285,34 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1236 | else if (0 < gnutls_record_check_pending (connection->tls_session)) | 1285 | else if (0 < gnutls_record_check_pending (connection->tls_session)) |
1237 | connection->tls_read_ready = true; | 1286 | connection->tls_read_ready = true; |
1238 | } | 1287 | } |
1239 | else if ( (0 >= res ) && | 1288 | else /* 0 >= res */ |
1240 | (GNUTLS_E_INTERRUPTED != res) ) | ||
1241 | { | 1289 | { |
1242 | /* Connection was shut down or got unrecoverable error. | 1290 | if (GNUTLS_E_INTERRUPTED != res) |
1243 | * Reading from remote client is not required anymore. */ | 1291 | { |
1292 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1293 | if (GNUTLS_E_AGAIN != res) | ||
1294 | { | ||
1295 | /* Unrecoverable error on socket was detected or | ||
1296 | * socket was disconnected/shut down. */ | ||
1297 | /* Stop trying to read from this TLS socket. */ | ||
1298 | urh->in_buffer_size = 0; | ||
1299 | } | ||
1300 | } | ||
1301 | } | ||
1302 | if (MHD_EPOLL_STATE_ERROR == | ||
1303 | ((MHD_EPOLL_STATE_ERROR | MHD_EPOLL_STATE_READ_READY) & urh->app.celi)) | ||
1304 | { | ||
1305 | /* Unrecoverable error on socket was detected and all | ||
1306 | * pending data was read from system buffers. */ | ||
1307 | /* Stop trying to read from this TLS socket. */ | ||
1244 | urh->in_buffer_size = 0; | 1308 | urh->in_buffer_size = 0; |
1245 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1246 | } | 1309 | } |
1247 | } | 1310 | } |
1248 | 1311 | ||
1249 | /* | 1312 | /* |
1250 | * handle reading from application | 1313 | * handle reading from application |
1251 | */ | 1314 | */ |
1252 | /* If application signaled MHD about socket closure then | 1315 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && |
1253 | * check for any pending data even if socket is not marked | ||
1254 | * as 'ready' (signal may arrive after poll()/select()). | ||
1255 | * Socketpair for forwarding is always in non-blocking mode | ||
1256 | * so no risk that recv() will block the thread. */ | ||
1257 | if ( ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) || | ||
1258 | (urh->was_closed) ) && | ||
1259 | (urh->out_buffer_used < urh->out_buffer_size) ) | 1316 | (urh->out_buffer_used < urh->out_buffer_size) ) |
1260 | { | 1317 | { |
1261 | ssize_t res; | 1318 | ssize_t res; |
@@ -1268,44 +1325,41 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1268 | res = MHD_recv_ (urh->mhd.socket, | 1325 | res = MHD_recv_ (urh->mhd.socket, |
1269 | &urh->out_buffer[urh->out_buffer_used], | 1326 | &urh->out_buffer[urh->out_buffer_used], |
1270 | buf_size); | 1327 | buf_size); |
1271 | if (0 > res) | 1328 | if (0 < res) |
1329 | { | ||
1330 | urh->out_buffer_used += res; | ||
1331 | if (buf_size > (size_t)res) | ||
1332 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1333 | } | ||
1334 | else /* 0 >= res */ | ||
1272 | { | 1335 | { |
1273 | if (urh->was_closed) | 1336 | const int err = MHD_socket_get_error_ (); |
1337 | if ((0 == res) || | ||
1338 | ((! MHD_SCKT_ERR_IS_EINTR_ (err)) && | ||
1339 | (! MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)))) | ||
1274 | { | 1340 | { |
1275 | /* All data was received and application will not | ||
1276 | * forward any more data. */ | ||
1277 | /* Do not try to pull data from application. */ | ||
1278 | urh->out_buffer_size = 0; | ||
1279 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | 1341 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; |
1280 | } | 1342 | if ((0 == res) || |
1281 | else | 1343 | (was_closed) || |
1282 | { | 1344 | (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) || |
1283 | const int err = MHD_socket_get_error_ (); | 1345 | (! MHD_SCKT_ERR_IS_EAGAIN_ (err))) |
1284 | if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
1285 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1286 | else if ( (! MHD_SCKT_ERR_IS_EINTR_ (err)) && | ||
1287 | (! MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)) ) | ||
1288 | { | 1346 | { |
1289 | /* persistent / unrecoverable error, treat as | 1347 | /* Socket disconnect/shutdown was detected; |
1290 | if connection was shut down */ | 1348 | * Application signaled about closure of 'upgraded' socket; |
1291 | /* Do not try to pull data from application. */ | 1349 | * or persistent / unrecoverable error. */ |
1350 | /* Do not try to pull more data from application. */ | ||
1292 | urh->out_buffer_size = 0; | 1351 | urh->out_buffer_size = 0; |
1293 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1294 | } | 1352 | } |
1295 | } | 1353 | } |
1296 | } | 1354 | } |
1297 | else | 1355 | if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && |
1298 | { | 1356 | ( (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) || |
1299 | urh->out_buffer_used += res; | 1357 | (was_closed) ) ) |
1300 | if (buf_size > (size_t)res) | ||
1301 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1302 | } | ||
1303 | if (0 == res) | ||
1304 | { | 1358 | { |
1305 | /* Connection was shut down or got unrecoverable error. | 1359 | /* Unrecoverable error on socket was detected and all |
1306 | Do not try to pull data from application. */ | 1360 | * pending data was read from system buffers. */ |
1361 | /* Do not try to pull more data from application. */ | ||
1307 | urh->out_buffer_size = 0; | 1362 | urh->out_buffer_size = 0; |
1308 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1309 | } | 1363 | } |
1310 | } | 1364 | } |
1311 | 1365 | ||
@@ -1325,40 +1379,49 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1325 | res = gnutls_record_send (connection->tls_session, | 1379 | res = gnutls_record_send (connection->tls_session, |
1326 | urh->out_buffer, | 1380 | urh->out_buffer, |
1327 | data_size); | 1381 | data_size); |
1328 | if (GNUTLS_E_AGAIN == res) | 1382 | if (0 < res) |
1329 | { | 1383 | { |
1330 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | 1384 | const size_t next_out_buffer_used = urh->out_buffer_used - res; |
1331 | } | 1385 | if (0 != next_out_buffer_used) |
1332 | else if (res > 0) | ||
1333 | { | ||
1334 | if (urh->out_buffer_used != res) | ||
1335 | { | 1386 | { |
1336 | memmove (urh->out_buffer, | 1387 | memmove (urh->out_buffer, |
1337 | &urh->out_buffer[res], | 1388 | &urh->out_buffer[res], |
1338 | urh->out_buffer_used - res); | 1389 | next_out_buffer_used); |
1339 | urh->out_buffer_used -= res; | ||
1340 | if (data_size > (size_t)res) | 1390 | if (data_size > (size_t)res) |
1341 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | 1391 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; |
1342 | } | 1392 | } |
1343 | else | 1393 | urh->out_buffer_used = next_out_buffer_used; |
1394 | } | ||
1395 | else /* 0 >= res */ | ||
1396 | { | ||
1397 | if (GNUTLS_E_INTERRUPTED != res) | ||
1344 | { | 1398 | { |
1345 | urh->out_buffer_used = 0; | 1399 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; |
1400 | if (GNUTLS_E_INTERRUPTED != res) | ||
1401 | { | ||
1402 | /* TLS connection shut down or | ||
1403 | * persistent / unrecoverable error. */ | ||
1404 | #ifdef HAVE_MESSAGES | ||
1405 | MHD_DLOG (daemon, | ||
1406 | _("Failed to forward to remote client " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
1407 | " bytes of data received from application: %s\n"), | ||
1408 | (MHD_UNSIGNED_LONG_LONG) urh->out_buffer_used, | ||
1409 | gnutls_strerror(res)); | ||
1410 | #endif | ||
1411 | /* Discard any data unsent to remote. */ | ||
1412 | urh->out_buffer_used = 0; | ||
1413 | /* Do not try to pull more data from application. */ | ||
1414 | urh->out_buffer_size = 0; | ||
1415 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1416 | } | ||
1346 | } | 1417 | } |
1347 | } | 1418 | } |
1348 | else if (GNUTLS_E_INTERRUPTED != res) | 1419 | if ( (0 == urh->out_buffer_used) && |
1420 | (0 != (MHD_EPOLL_STATE_ERROR & urh->app.celi)) ) | ||
1349 | { | 1421 | { |
1350 | /* persistent / unrecoverable error, treat as | 1422 | /* Unrecoverable error on socket was detected and all |
1351 | if connection was shut down. */ | 1423 | * pending data was sent to remote. */ |
1352 | #ifdef HAVE_MESSAGES | 1424 | /* Do not try to send to remote anymore. */ |
1353 | MHD_DLOG (daemon, | ||
1354 | _("Failed to forward to remote client " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
1355 | " bytes of data received from application: %s\n"), | ||
1356 | (MHD_UNSIGNED_LONG_LONG) urh->out_buffer_used, | ||
1357 | gnutls_strerror(res)); | ||
1358 | #endif | ||
1359 | /* Discard any data unsent to remote. */ | ||
1360 | urh->out_buffer_used = 0; | ||
1361 | /* Do not try to sent to remote anymore. */ | ||
1362 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | 1425 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; |
1363 | /* Do not try to pull more data from application. */ | 1426 | /* Do not try to pull more data from application. */ |
1364 | urh->out_buffer_size = 0; | 1427 | urh->out_buffer_size = 0; |
@@ -1370,7 +1433,7 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1370 | * handle writing to application | 1433 | * handle writing to application |
1371 | */ | 1434 | */ |
1372 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | 1435 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && |
1373 | (urh->in_buffer_used > 0) ) | 1436 | (urh->in_buffer_used > 0) ) |
1374 | { | 1437 | { |
1375 | ssize_t res; | 1438 | ssize_t res; |
1376 | size_t data_size; | 1439 | size_t data_size; |
@@ -1382,50 +1445,56 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1382 | res = MHD_send_ (urh->mhd.socket, | 1445 | res = MHD_send_ (urh->mhd.socket, |
1383 | urh->in_buffer, | 1446 | urh->in_buffer, |
1384 | data_size); | 1447 | data_size); |
1385 | if (0 > res) | 1448 | if (0 < res) |
1386 | { | 1449 | { |
1387 | int err = MHD_socket_get_error_ (); | 1450 | const size_t next_in_buffer_used = urh->in_buffer_used - res; |
1388 | 1451 | if (0 != next_in_buffer_used) | |
1389 | if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
1390 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1391 | else if ( (! MHD_SCKT_ERR_IS_EINTR_ (err)) && | ||
1392 | (! MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)) ) | ||
1393 | { | ||
1394 | /* persistent / unrecoverable error, treat as | ||
1395 | if connection was shut down. */ | ||
1396 | #ifdef HAVE_MESSAGES | ||
1397 | MHD_DLOG (daemon, | ||
1398 | _("Failed to forward to application " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
1399 | " bytes of data received from remote side: %s\n"), | ||
1400 | (MHD_UNSIGNED_LONG_LONG) urh->in_buffer_used, | ||
1401 | MHD_socket_strerr_ (err)); | ||
1402 | #endif | ||
1403 | /* Discard any data received form remote. */ | ||
1404 | urh->in_buffer_used = 0; | ||
1405 | /* Do not try to push data to application. */ | ||
1406 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1407 | /* Reading from remote client is not required anymore. */ | ||
1408 | urh->in_buffer_size = 0; | ||
1409 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1410 | connection->tls_read_ready = false; | ||
1411 | } | ||
1412 | } | ||
1413 | else | ||
1414 | { | ||
1415 | if (urh->in_buffer_used != res) | ||
1416 | { | 1452 | { |
1417 | memmove (urh->in_buffer, | 1453 | memmove (urh->in_buffer, |
1418 | &urh->in_buffer[res], | 1454 | &urh->in_buffer[res], |
1419 | urh->in_buffer_used - res); | 1455 | next_in_buffer_used); |
1420 | urh->in_buffer_used -= res; | ||
1421 | if (data_size > (size_t)res) | 1456 | if (data_size > (size_t)res) |
1422 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | 1457 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; |
1423 | } | 1458 | } |
1424 | else | 1459 | urh->in_buffer_used = next_in_buffer_used; |
1460 | } | ||
1461 | else /* 0 >= res */ | ||
1462 | { | ||
1463 | const int err = MHD_socket_get_error_ (); | ||
1464 | if ( (! MHD_SCKT_ERR_IS_EINTR_ (err)) && | ||
1465 | (! MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)) ) | ||
1425 | { | 1466 | { |
1426 | urh->in_buffer_used = 0; | 1467 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; |
1468 | if (! MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
1469 | { | ||
1470 | /* Socketpair connection shut down or | ||
1471 | * persistent / unrecoverable error. */ | ||
1472 | #ifdef HAVE_MESSAGES | ||
1473 | MHD_DLOG (daemon, | ||
1474 | _("Failed to forward to application " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
1475 | " bytes of data received from remote side: %s\n"), | ||
1476 | (MHD_UNSIGNED_LONG_LONG) urh->in_buffer_used, | ||
1477 | MHD_socket_strerr_ (err)); | ||
1478 | #endif | ||
1479 | /* Discard any data received form remote. */ | ||
1480 | urh->in_buffer_used = 0; | ||
1481 | /* Reading from remote client is not required anymore. */ | ||
1482 | urh->in_buffer_size = 0; | ||
1483 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1484 | connection->tls_read_ready = false; | ||
1485 | } | ||
1427 | } | 1486 | } |
1428 | } | 1487 | } |
1488 | if ( (0 !=urh->in_buffer_used) && | ||
1489 | (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) ) | ||
1490 | { | ||
1491 | /* Do not try to push data to application. */ | ||
1492 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1493 | /* Reading from remote client is not required anymore. */ | ||
1494 | urh->in_buffer_size = 0; | ||
1495 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1496 | connection->tls_read_ready = false; | ||
1497 | } | ||
1429 | } | 1498 | } |
1430 | 1499 | ||
1431 | /* Check whether data is present in TLS buffers | 1500 | /* Check whether data is present in TLS buffers |
@@ -3835,6 +3904,10 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
3835 | ueh->celi |= MHD_EPOLL_STATE_READ_READY; | 3904 | ueh->celi |= MHD_EPOLL_STATE_READ_READY; |
3836 | if (0 != (events[i].events & EPOLLOUT)) | 3905 | if (0 != (events[i].events & EPOLLOUT)) |
3837 | ueh->celi |= MHD_EPOLL_STATE_WRITE_READY; | 3906 | ueh->celi |= MHD_EPOLL_STATE_WRITE_READY; |
3907 | if (0 != (events[i].events & EPOLLHUP)) | ||
3908 | ueh->celi |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY; | ||
3909 | if (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) | ||
3910 | ueh->celi |= MHD_EPOLL_STATE_ERROR; | ||
3838 | 3911 | ||
3839 | process_urh (urh); | 3912 | process_urh (urh); |
3840 | /* Finished forwarding? */ | 3913 | /* Finished forwarding? */ |