diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-02-16 06:30:29 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-02-16 06:30:29 +0100 |
commit | 6450f55f0c18d7a4b2fac829d9eff5d567348d19 (patch) | |
tree | 63a062752ac68f9339d31f455e01a36059cc5943 /src/lib | |
parent | 552f3aa7b23b958c8ad275fbf28682f229dbc4f7 (diff) | |
download | libmicrohttpd-6450f55f0c18d7a4b2fac829d9eff5d567348d19.tar.gz libmicrohttpd-6450f55f0c18d7a4b2fac829d9eff5d567348d19.zip |
add upgrade_process.c
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/Makefile.am | 1 | ||||
-rw-r--r-- | src/lib/connection_add.c | 3 | ||||
-rw-r--r-- | src/lib/daemon_epoll.c | 4 | ||||
-rw-r--r-- | src/lib/daemon_ip_limit.c | 6 | ||||
-rw-r--r-- | src/lib/daemon_poll.c | 5 | ||||
-rw-r--r-- | src/lib/daemon_run.c | 19 | ||||
-rw-r--r-- | src/lib/daemon_select.c | 5 | ||||
-rw-r--r-- | src/lib/upgrade_process.c | 388 | ||||
-rw-r--r-- | src/lib/upgrade_process.h | 44 |
9 files changed, 460 insertions, 15 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index b53e00b4..1667978a 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am | |||
@@ -100,6 +100,7 @@ libmicrohttpd_la_SOURCES = \ | |||
100 | request_info.c \ | 100 | request_info.c \ |
101 | request_resume.c \ | 101 | request_resume.c \ |
102 | sysfdsetsize.c sysfdsetsize.h \ | 102 | sysfdsetsize.c sysfdsetsize.h \ |
103 | upgrade_process.c upgrade_process.h \ | ||
103 | panic.c \ | 104 | panic.c \ |
104 | version.c | 105 | version.c |
105 | 106 | ||
diff --git a/src/lib/connection_add.c b/src/lib/connection_add.c index eb5984e3..0aebe501 100644 --- a/src/lib/connection_add.c +++ b/src/lib/connection_add.c | |||
@@ -23,6 +23,8 @@ | |||
23 | */ | 23 | */ |
24 | #include "internal.h" | 24 | #include "internal.h" |
25 | #include "connection_add.h" | 25 | #include "connection_add.h" |
26 | #include "connection_close.h" | ||
27 | #include "connection_finish_forward.h" | ||
26 | #include "connection_update_last_activity.h" | 28 | #include "connection_update_last_activity.h" |
27 | #include "daemon_ip_limit.h" | 29 | #include "daemon_ip_limit.h" |
28 | #include "daemon_select.h" | 30 | #include "daemon_select.h" |
@@ -42,7 +44,6 @@ static void | |||
42 | thread_main_connection_upgrade (struct MHD_Connection *con) | 44 | thread_main_connection_upgrade (struct MHD_Connection *con) |
43 | { | 45 | { |
44 | #ifdef HTTPS_SUPPORT | 46 | #ifdef HTTPS_SUPPORT |
45 | struct MHD_UpgradeResponseHandle *urh = con->request.urh; | ||
46 | struct MHD_Daemon *daemon = con->daemon; | 47 | struct MHD_Daemon *daemon = con->daemon; |
47 | 48 | ||
48 | /* Here, we need to bi-directionally forward | 49 | /* Here, we need to bi-directionally forward |
diff --git a/src/lib/daemon_epoll.c b/src/lib/daemon_epoll.c index d85d54e7..115bb9d0 100644 --- a/src/lib/daemon_epoll.c +++ b/src/lib/daemon_epoll.c | |||
@@ -24,7 +24,9 @@ | |||
24 | */ | 24 | */ |
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | #include "daemon_epoll.h" | 26 | #include "daemon_epoll.h" |
27 | #include "upgrade_process.h" | ||
27 | #include "request_resume.h" | 28 | #include "request_resume.h" |
29 | #include "connection_add.h" | ||
28 | #include "connection_finish_forward.h" | 30 | #include "connection_finish_forward.h" |
29 | 31 | ||
30 | #ifdef EPOLL_SUPPORT | 32 | #ifdef EPOLL_SUPPORT |
@@ -170,7 +172,7 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) | |||
170 | while (NULL != (pos = prev)) | 172 | while (NULL != (pos = prev)) |
171 | { | 173 | { |
172 | prev = pos->prevE; | 174 | prev = pos->prevE; |
173 | process_urh (pos); | 175 | MHD_upgrade_response_handle_process_ (pos); |
174 | if (! is_urh_ready(pos)) | 176 | if (! is_urh_ready(pos)) |
175 | { | 177 | { |
176 | EDLL_remove (daemon->eready_urh_head, | 178 | EDLL_remove (daemon->eready_urh_head, |
diff --git a/src/lib/daemon_ip_limit.c b/src/lib/daemon_ip_limit.c index d368893b..4a131c92 100644 --- a/src/lib/daemon_ip_limit.c +++ b/src/lib/daemon_ip_limit.c | |||
@@ -24,6 +24,12 @@ | |||
24 | */ | 24 | */ |
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | #include "daemon_ip_limit.h" | 26 | #include "daemon_ip_limit.h" |
27 | #if HAVE_SEARCH_H | ||
28 | #include <search.h> | ||
29 | #else | ||
30 | #include "tsearch.h" | ||
31 | #endif | ||
32 | |||
27 | 33 | ||
28 | /** | 34 | /** |
29 | * Maintain connection count for single address. | 35 | * Maintain connection count for single address. |
diff --git a/src/lib/daemon_poll.c b/src/lib/daemon_poll.c index 63747bd0..39d22ccf 100644 --- a/src/lib/daemon_poll.c +++ b/src/lib/daemon_poll.c | |||
@@ -23,6 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | #include "internal.h" | 24 | #include "internal.h" |
25 | #include "daemon_poll.h" | 25 | #include "daemon_poll.h" |
26 | #include "upgrade_process.h" | ||
26 | #include "request_resume.h" | 27 | #include "request_resume.h" |
27 | #include "connection_add.h" | 28 | #include "connection_add.h" |
28 | #include "connection_finish_forward.h" | 29 | #include "connection_finish_forward.h" |
@@ -315,7 +316,7 @@ MHD_daemon_poll_all_ (struct MHD_Daemon *daemon, | |||
315 | urh_from_pollfd (urh, | 316 | urh_from_pollfd (urh, |
316 | &(p[poll_server+i])); | 317 | &(p[poll_server+i])); |
317 | i += 2; | 318 | i += 2; |
318 | process_urh (urh); | 319 | MHD_upgrade_response_handle_process_ (urh); |
319 | /* Finished forwarding? */ | 320 | /* Finished forwarding? */ |
320 | if ( (0 == urh->in_buffer_size) && | 321 | if ( (0 == urh->in_buffer_size) && |
321 | (0 == urh->out_buffer_size) && | 322 | (0 == urh->out_buffer_size) && |
@@ -508,7 +509,7 @@ MHD_daemon_upgrade_connection_with_poll_ (struct MHD_Connection *con) | |||
508 | } | 509 | } |
509 | urh_from_pollfd (urh, | 510 | urh_from_pollfd (urh, |
510 | p); | 511 | p); |
511 | process_urh (urh); | 512 | MHD_upgrade_response_handle_process_ (urh); |
512 | } | 513 | } |
513 | } | 514 | } |
514 | #endif | 515 | #endif |
diff --git a/src/lib/daemon_run.c b/src/lib/daemon_run.c index c93a5f83..d95cff12 100644 --- a/src/lib/daemon_run.c +++ b/src/lib/daemon_run.c | |||
@@ -49,6 +49,8 @@ | |||
49 | enum MHD_StatusCode | 49 | enum MHD_StatusCode |
50 | MHD_daemon_run (struct MHD_Daemon *daemon) | 50 | MHD_daemon_run (struct MHD_Daemon *daemon) |
51 | { | 51 | { |
52 | enum MHD_StatusCode sc; | ||
53 | |||
52 | if (daemon->shutdown) | 54 | if (daemon->shutdown) |
53 | return MHD_SC_DAEMON_ALREADY_SHUTDOWN; | 55 | return MHD_SC_DAEMON_ALREADY_SHUTDOWN; |
54 | if (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_model) | 56 | if (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_model) |
@@ -56,22 +58,21 @@ MHD_daemon_run (struct MHD_Daemon *daemon) | |||
56 | switch (daemon->event_loop_syscall) | 58 | switch (daemon->event_loop_syscall) |
57 | { | 59 | { |
58 | case MHD_ELS_POLL: | 60 | case MHD_ELS_POLL: |
59 | MHD_daemon_poll_ (daemon, | 61 | sc = MHD_daemon_poll_ (daemon, |
60 | MHD_NO); | 62 | MHD_NO); |
61 | MHD_cleanup_connections (daemon); | 63 | MHD_cleanup_connections (daemon); |
62 | break; | 64 | return sc; |
63 | #ifdef EPOLL_SUPPORT | 65 | #ifdef EPOLL_SUPPORT |
64 | case MHD_ELS_EPOLL: | 66 | case MHD_ELS_EPOLL: |
65 | MHD_daemon_epoll_ (daemon, | 67 | sc = MHD_daemon_epoll_ (daemon, |
66 | MHD_NO); | 68 | MHD_NO); |
67 | MHD_cleanup_connections (daemon); | 69 | MHD_cleanup_connections (daemon); |
68 | break; | 70 | return sc; |
69 | #endif | 71 | #endif |
70 | case MHD_ELS_SELECT: | 72 | case MHD_ELS_SELECT: |
71 | MHD_daemon_select_ (daemon, | 73 | return MHD_daemon_select_ (daemon, |
72 | MHD_NO); | 74 | MHD_NO); |
73 | /* MHD_select does MHD_cleanup_connections already */ | 75 | /* MHD_select does MHD_cleanup_connections already */ |
74 | break; | ||
75 | default: | 76 | default: |
76 | return MHD_SC_CONFIGURATION_UNEXPECTED_ELS; | 77 | return MHD_SC_CONFIGURATION_UNEXPECTED_ELS; |
77 | } | 78 | } |
diff --git a/src/lib/daemon_select.c b/src/lib/daemon_select.c index 9c80812c..ec4da399 100644 --- a/src/lib/daemon_select.c +++ b/src/lib/daemon_select.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | #include "daemon_select.h" | 26 | #include "daemon_select.h" |
27 | #include "request_resume.h" | 27 | #include "request_resume.h" |
28 | #include "upgrade_process.h" | ||
28 | #include "connection_finish_forward.h" | 29 | #include "connection_finish_forward.h" |
29 | 30 | ||
30 | 31 | ||
@@ -461,7 +462,7 @@ internal_run_from_select (struct MHD_Daemon *daemon, | |||
461 | write_fd_set, | 462 | write_fd_set, |
462 | except_fd_set); | 463 | except_fd_set); |
463 | /* call generic forwarding function for passing data */ | 464 | /* call generic forwarding function for passing data */ |
464 | process_urh (urh); | 465 | MHD_upgrade_response_handle_process_ (urh); |
465 | /* Finished forwarding? */ | 466 | /* Finished forwarding? */ |
466 | if ( (0 == urh->in_buffer_size) && | 467 | if ( (0 == urh->in_buffer_size) && |
467 | (0 == urh->out_buffer_size) && | 468 | (0 == urh->out_buffer_size) && |
@@ -566,7 +567,7 @@ MHD_daemon_upgrade_connection_with_select_ (struct MHD_Connection *con) | |||
566 | &rs, | 567 | &rs, |
567 | &ws, | 568 | &ws, |
568 | &es); | 569 | &es); |
569 | process_urh (urh); | 570 | MHD_upgrade_response_handle_process_ (urh); |
570 | } | 571 | } |
571 | } | 572 | } |
572 | #endif | 573 | #endif |
diff --git a/src/lib/upgrade_process.c b/src/lib/upgrade_process.c new file mode 100644 index 00000000..318881ab --- /dev/null +++ b/src/lib/upgrade_process.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | /** | ||
20 | * @file lib/upgrade_process.c | ||
21 | * @brief function to process upgrade activity (over TLS) | ||
22 | * @author Christian Grothoff | ||
23 | */ | ||
24 | #include "internal.h" | ||
25 | #include "upgrade_process.h" | ||
26 | |||
27 | |||
28 | #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) | ||
29 | /** | ||
30 | * Performs bi-directional forwarding on upgraded HTTPS connections | ||
31 | * based on the readyness state stored in the @a urh handle. | ||
32 | * @remark To be called only from thread that process | ||
33 | * connection's recv(), send() and response. | ||
34 | * | ||
35 | * @param urh handle to process | ||
36 | */ | ||
37 | void | ||
38 | MHD_upgrade_response_handle_process_ (struct MHD_UpgradeResponseHandle *urh) | ||
39 | { | ||
40 | /* Help compiler to optimize: | ||
41 | * pointers to 'connection' and 'daemon' are not changed | ||
42 | * during this processing, so no need to chain dereference | ||
43 | * each time. */ | ||
44 | struct MHD_Connection * const connection = urh->connection; | ||
45 | struct MHD_Daemon * const daemon = connection->daemon; | ||
46 | /* Prevent data races: use same value of 'was_closed' throughout | ||
47 | * this function. If 'was_closed' changed externally in the middle | ||
48 | * of processing - it will be processed on next iteration. */ | ||
49 | bool was_closed; | ||
50 | struct MHD_TLS_Plugin *tls = daemon->tls_api; | ||
51 | |||
52 | if (daemon->shutdown) | ||
53 | { | ||
54 | /* Daemon shutting down, application will not receive any more data. */ | ||
55 | #ifdef HAVE_MESSAGES | ||
56 | if (! urh->was_closed) | ||
57 | { | ||
58 | MHD_DLOG (daemon, | ||
59 | MHD_SC_DAEMON_ALREADY_SHUTDOWN, | ||
60 | _("Initiated daemon shutdown while \"upgraded\" connection was not closed.\n")); | ||
61 | } | ||
62 | #endif | ||
63 | urh->was_closed = true; | ||
64 | } | ||
65 | was_closed = urh->was_closed; | ||
66 | if (was_closed) | ||
67 | { | ||
68 | /* Application was closed connections: no more data | ||
69 | * can be forwarded to application socket. */ | ||
70 | if (0 < urh->in_buffer_used) | ||
71 | { | ||
72 | #ifdef HAVE_MESSAGES | ||
73 | MHD_DLOG (daemon, | ||
74 | MHD_SC_UPGRADE_FORWARD_INCOMPLETE, | ||
75 | _("Failed to forward to application " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
76 | " bytes of data received from remote side: application shut down socket\n"), | ||
77 | (MHD_UNSIGNED_LONG_LONG) urh->in_buffer_used); | ||
78 | #endif | ||
79 | |||
80 | } | ||
81 | /* If application signaled MHD about socket closure then | ||
82 | * check for any pending data even if socket is not marked | ||
83 | * as 'ready' (signal may arrive after poll()/select()). | ||
84 | * Socketpair for forwarding is always in non-blocking mode | ||
85 | * so no risk that recv() will block the thread. */ | ||
86 | if (0 != urh->out_buffer_size) | ||
87 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
88 | /* Discard any data received form remote. */ | ||
89 | urh->in_buffer_used = 0; | ||
90 | /* Do not try to push data to application. */ | ||
91 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
92 | /* Reading from remote client is not required anymore. */ | ||
93 | urh->in_buffer_size = 0; | ||
94 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
95 | connection->tls_read_ready = false; | ||
96 | } | ||
97 | |||
98 | /* On some platforms (W32, possibly Darwin) failed send() (send() will always | ||
99 | * fail after remote disconnect was detected) may discard data in system | ||
100 | * buffers received by system but not yet read by recv(). | ||
101 | * So, before trying send() on any socket, recv() must be performed at first | ||
102 | * otherwise last part of incoming data may be lost. */ | ||
103 | |||
104 | /* If disconnect or error was detected - try to read from socket | ||
105 | * to dry data possibly pending is system buffers. */ | ||
106 | if (0 != (MHD_EPOLL_STATE_ERROR & urh->app.celi)) | ||
107 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; | ||
108 | if (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) | ||
109 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
110 | |||
111 | /* | ||
112 | * handle reading from remote TLS client | ||
113 | */ | ||
114 | if ( ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) || | ||
115 | (connection->tls_read_ready) ) && | ||
116 | (urh->in_buffer_used < urh->in_buffer_size) ) | ||
117 | { | ||
118 | ssize_t res; | ||
119 | size_t buf_size; | ||
120 | |||
121 | buf_size = urh->in_buffer_size - urh->in_buffer_used; | ||
122 | if (buf_size > SSIZE_MAX) | ||
123 | buf_size = SSIZE_MAX; | ||
124 | |||
125 | connection->tls_read_ready = false; | ||
126 | res = tls->recv (tls->cls, | ||
127 | connection->tls_cs, | ||
128 | &urh->in_buffer[urh->in_buffer_used], | ||
129 | buf_size); | ||
130 | if (0 >= res) | ||
131 | { | ||
132 | // FIXME: define GNUTLS-independent error codes! | ||
133 | if (GNUTLS_E_INTERRUPTED != res) | ||
134 | { | ||
135 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
136 | if (GNUTLS_E_AGAIN != res) | ||
137 | { | ||
138 | /* Unrecoverable error on socket was detected or | ||
139 | * socket was disconnected/shut down. */ | ||
140 | /* Stop trying to read from this TLS socket. */ | ||
141 | urh->in_buffer_size = 0; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | else /* 0 < res */ | ||
146 | { | ||
147 | urh->in_buffer_used += res; | ||
148 | if (buf_size > (size_t)res) | ||
149 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
150 | else if (0 < tls->check_record_pending (tls->cls, | ||
151 | connection->tls_cs)) | ||
152 | connection->tls_read_ready = true; | ||
153 | } | ||
154 | if (MHD_EPOLL_STATE_ERROR == | ||
155 | ((MHD_EPOLL_STATE_ERROR | MHD_EPOLL_STATE_READ_READY) & urh->app.celi)) | ||
156 | { | ||
157 | /* Unrecoverable error on socket was detected and all | ||
158 | * pending data was read from system buffers. */ | ||
159 | /* Stop trying to read from this TLS socket. */ | ||
160 | urh->in_buffer_size = 0; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * handle reading from application | ||
166 | */ | ||
167 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && | ||
168 | (urh->out_buffer_used < urh->out_buffer_size) ) | ||
169 | { | ||
170 | ssize_t res; | ||
171 | size_t buf_size; | ||
172 | |||
173 | buf_size = urh->out_buffer_size - urh->out_buffer_used; | ||
174 | if (buf_size > MHD_SCKT_SEND_MAX_SIZE_) | ||
175 | buf_size = MHD_SCKT_SEND_MAX_SIZE_; | ||
176 | |||
177 | res = MHD_recv_ (urh->mhd.socket, | ||
178 | &urh->out_buffer[urh->out_buffer_used], | ||
179 | buf_size); | ||
180 | if (0 >= res) | ||
181 | { | ||
182 | const int err = MHD_socket_get_error_ (); | ||
183 | if ((0 == res) || | ||
184 | ((! MHD_SCKT_ERR_IS_EINTR_ (err)) && | ||
185 | (! MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)))) | ||
186 | { | ||
187 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
188 | if ((0 == res) || | ||
189 | (was_closed) || | ||
190 | (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) || | ||
191 | (! MHD_SCKT_ERR_IS_EAGAIN_ (err))) | ||
192 | { | ||
193 | /* Socket disconnect/shutdown was detected; | ||
194 | * Application signaled about closure of 'upgraded' socket; | ||
195 | * or persistent / unrecoverable error. */ | ||
196 | /* Do not try to pull more data from application. */ | ||
197 | urh->out_buffer_size = 0; | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | else /* 0 < res */ | ||
202 | { | ||
203 | urh->out_buffer_used += res; | ||
204 | if (buf_size > (size_t)res) | ||
205 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
206 | } | ||
207 | if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && | ||
208 | ( (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) || | ||
209 | (was_closed) ) ) | ||
210 | { | ||
211 | /* Unrecoverable error on socket was detected and all | ||
212 | * pending data was read from system buffers. */ | ||
213 | /* Do not try to pull more data from application. */ | ||
214 | urh->out_buffer_size = 0; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * handle writing to remote HTTPS client | ||
220 | */ | ||
221 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | ||
222 | (urh->out_buffer_used > 0) ) | ||
223 | { | ||
224 | ssize_t res; | ||
225 | size_t data_size; | ||
226 | |||
227 | data_size = urh->out_buffer_used; | ||
228 | if (data_size > SSIZE_MAX) | ||
229 | data_size = SSIZE_MAX; | ||
230 | |||
231 | res = tls->send (tls->cls, | ||
232 | connection->tls_cs, | ||
233 | urh->out_buffer, | ||
234 | data_size); | ||
235 | if (0 >= res) | ||
236 | { | ||
237 | // FIXME: define GNUTLS-independent error codes! | ||
238 | if (GNUTLS_E_INTERRUPTED != res) | ||
239 | { | ||
240 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
241 | if (GNUTLS_E_INTERRUPTED != res) | ||
242 | { | ||
243 | /* TLS connection shut down or | ||
244 | * persistent / unrecoverable error. */ | ||
245 | #ifdef HAVE_MESSAGES | ||
246 | MHD_DLOG (daemon, | ||
247 | MHD_SC_UPGRADE_FORWARD_INCOMPLETE, | ||
248 | _("Failed to forward to remote client " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
249 | " bytes of data received from application: %s\n"), | ||
250 | (MHD_UNSIGNED_LONG_LONG) urh->out_buffer_used, | ||
251 | tls->strerror (tls->cls, | ||
252 | res)); | ||
253 | #endif | ||
254 | /* Discard any data unsent to remote. */ | ||
255 | urh->out_buffer_used = 0; | ||
256 | /* Do not try to pull more data from application. */ | ||
257 | urh->out_buffer_size = 0; | ||
258 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | else /* 0 < res */ | ||
263 | { | ||
264 | const size_t next_out_buffer_used = urh->out_buffer_used - res; | ||
265 | if (0 != next_out_buffer_used) | ||
266 | { | ||
267 | memmove (urh->out_buffer, | ||
268 | &urh->out_buffer[res], | ||
269 | next_out_buffer_used); | ||
270 | if (data_size > (size_t)res) | ||
271 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
272 | } | ||
273 | urh->out_buffer_used = next_out_buffer_used; | ||
274 | } | ||
275 | if ( (0 == urh->out_buffer_used) && | ||
276 | (0 != (MHD_EPOLL_STATE_ERROR & urh->app.celi)) ) | ||
277 | { | ||
278 | /* Unrecoverable error on socket was detected and all | ||
279 | * pending data was sent to remote. */ | ||
280 | /* Do not try to send to remote anymore. */ | ||
281 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
282 | /* Do not try to pull more data from application. */ | ||
283 | urh->out_buffer_size = 0; | ||
284 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * handle writing to application | ||
290 | */ | ||
291 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | ||
292 | (urh->in_buffer_used > 0) ) | ||
293 | { | ||
294 | ssize_t res; | ||
295 | size_t data_size; | ||
296 | |||
297 | data_size = urh->in_buffer_used; | ||
298 | if (data_size > MHD_SCKT_SEND_MAX_SIZE_) | ||
299 | data_size = MHD_SCKT_SEND_MAX_SIZE_; | ||
300 | |||
301 | res = MHD_send_ (urh->mhd.socket, | ||
302 | urh->in_buffer, | ||
303 | data_size); | ||
304 | if (0 >= res) | ||
305 | { | ||
306 | const int err = MHD_socket_get_error_ (); | ||
307 | if ( (! MHD_SCKT_ERR_IS_EINTR_ (err)) && | ||
308 | (! MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)) ) | ||
309 | { | ||
310 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
311 | if (! MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
312 | { | ||
313 | /* Socketpair connection shut down or | ||
314 | * persistent / unrecoverable error. */ | ||
315 | #ifdef HAVE_MESSAGES | ||
316 | MHD_DLOG (daemon, | ||
317 | MHD_SC_UPGRADE_FORWARD_INCOMPLETE, | ||
318 | _("Failed to forward to application " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
319 | " bytes of data received from remote side: %s\n"), | ||
320 | (MHD_UNSIGNED_LONG_LONG) urh->in_buffer_used, | ||
321 | MHD_socket_strerr_ (err)); | ||
322 | #endif | ||
323 | /* Discard any data received form remote. */ | ||
324 | urh->in_buffer_used = 0; | ||
325 | /* Reading from remote client is not required anymore. */ | ||
326 | urh->in_buffer_size = 0; | ||
327 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
328 | connection->tls_read_ready = false; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | else /* 0 < res */ | ||
333 | { | ||
334 | const size_t next_in_buffer_used = urh->in_buffer_used - res; | ||
335 | if (0 != next_in_buffer_used) | ||
336 | { | ||
337 | memmove (urh->in_buffer, | ||
338 | &urh->in_buffer[res], | ||
339 | next_in_buffer_used); | ||
340 | if (data_size > (size_t)res) | ||
341 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
342 | } | ||
343 | urh->in_buffer_used = next_in_buffer_used; | ||
344 | } | ||
345 | if ( (0 == urh->in_buffer_used) && | ||
346 | (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) ) | ||
347 | { | ||
348 | /* Do not try to push data to application. */ | ||
349 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
350 | /* Reading from remote client is not required anymore. */ | ||
351 | urh->in_buffer_size = 0; | ||
352 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
353 | connection->tls_read_ready = false; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | /* Check whether data is present in TLS buffers | ||
358 | * and incoming forward buffer have some space. */ | ||
359 | if ( (connection->tls_read_ready) && | ||
360 | (urh->in_buffer_used < urh->in_buffer_size) && | ||
361 | (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) ) | ||
362 | daemon->data_already_pending = true; | ||
363 | |||
364 | if ( (daemon->shutdown) && | ||
365 | ( (0 != urh->out_buffer_size) || | ||
366 | (0 != urh->out_buffer_used) ) ) | ||
367 | { | ||
368 | /* Daemon shutting down, discard any remaining forward data. */ | ||
369 | #ifdef HAVE_MESSAGES | ||
370 | if (0 < urh->out_buffer_used) | ||
371 | MHD_DLOG (daemon, | ||
372 | MHD_SC_UPGRADE_FORWARD_INCOMPLETE, | ||
373 | _("Failed to forward to remote client " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
374 | " bytes of data received from application: daemon shut down\n"), | ||
375 | (MHD_UNSIGNED_LONG_LONG) urh->out_buffer_used); | ||
376 | #endif | ||
377 | /* Discard any data unsent to remote. */ | ||
378 | urh->out_buffer_used = 0; | ||
379 | /* Do not try to sent to remote anymore. */ | ||
380 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
381 | /* Do not try to pull more data from application. */ | ||
382 | urh->out_buffer_size = 0; | ||
383 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
384 | } | ||
385 | } | ||
386 | #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ | ||
387 | |||
388 | /* end of upgrade_process.c */ | ||
diff --git a/src/lib/upgrade_process.h b/src/lib/upgrade_process.h new file mode 100644 index 00000000..36a7ddff --- /dev/null +++ b/src/lib/upgrade_process.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | /** | ||
20 | * @file lib/upgrade_process.h | ||
21 | * @brief function to process upgrade activity (over TLS) | ||
22 | * @author Christian Grothoff | ||
23 | */ | ||
24 | #ifndef UPGRADE_PROCESS_H | ||
25 | #define UPGRADE_PROCESS_H | ||
26 | |||
27 | |||
28 | #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) | ||
29 | /** | ||
30 | * Performs bi-directional forwarding on upgraded HTTPS connections | ||
31 | * based on the readyness state stored in the @a urh handle. | ||
32 | * @remark To be called only from thread that process | ||
33 | * connection's recv(), send() and response. | ||
34 | * | ||
35 | * @param urh handle to process | ||
36 | */ | ||
37 | void | ||
38 | MHD_upgrade_response_handle_process_ (struct MHD_UpgradeResponseHandle *urh) | ||
39 | MHD_NONNULL(1); | ||
40 | |||
41 | |||
42 | #endif | ||
43 | |||
44 | #endif | ||