diff options
Diffstat (limited to 'src/microhttpd/connection.c')
-rw-r--r-- | src/microhttpd/connection.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index f7a00bde..f1f2a80e 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -110,6 +110,168 @@ | |||
110 | 110 | ||
111 | 111 | ||
112 | /** | 112 | /** |
113 | * Callback for receiving data from the socket. | ||
114 | * | ||
115 | * @param connection the MHD connection structure | ||
116 | * @param other where to write received data to | ||
117 | * @param i maximum size of other (in bytes) | ||
118 | * @return number of bytes actually received | ||
119 | */ | ||
120 | static ssize_t | ||
121 | recv_param_adapter (struct MHD_Connection *connection, | ||
122 | void *other, | ||
123 | size_t i) | ||
124 | { | ||
125 | ssize_t ret; | ||
126 | |||
127 | if ( (MHD_INVALID_SOCKET == connection->socket_fd) || | ||
128 | (MHD_CONNECTION_CLOSED == connection->state) ) | ||
129 | { | ||
130 | MHD_socket_set_error_ (MHD_SCKT_ENOTCONN_); | ||
131 | return -1; | ||
132 | } | ||
133 | if (i > MHD_SCKT_SEND_MAX_SIZE_) | ||
134 | i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */ | ||
135 | |||
136 | ret = MHD_recv_ (connection->socket_fd, | ||
137 | other, | ||
138 | i); | ||
139 | #ifdef EPOLL_SUPPORT | ||
140 | if (0 > ret) | ||
141 | { | ||
142 | /* Got EAGAIN --- no longer read-ready */ | ||
143 | if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ())) | ||
144 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; | ||
145 | } | ||
146 | else if (i > (size_t)ret) | ||
147 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; | ||
148 | #endif | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | |||
153 | /** | ||
154 | * Callback for writing data to the socket. | ||
155 | * | ||
156 | * @param connection the MHD connection structure | ||
157 | * @param other data to write | ||
158 | * @param i number of bytes to write | ||
159 | * @return actual number of bytes written | ||
160 | */ | ||
161 | static ssize_t | ||
162 | send_param_adapter (struct MHD_Connection *connection, | ||
163 | const void *other, | ||
164 | size_t i) | ||
165 | { | ||
166 | ssize_t ret; | ||
167 | int err; | ||
168 | |||
169 | if ( (MHD_INVALID_SOCKET == connection->socket_fd) || | ||
170 | (MHD_CONNECTION_CLOSED == connection->state) ) | ||
171 | { | ||
172 | MHD_socket_set_error_ (MHD_SCKT_ENOTCONN_); | ||
173 | return -1; | ||
174 | } | ||
175 | if (i > MHD_SCKT_SEND_MAX_SIZE_) | ||
176 | i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */ | ||
177 | |||
178 | #if LINUX | ||
179 | if ( (connection->write_buffer_append_offset == | ||
180 | connection->write_buffer_send_offset) && | ||
181 | (NULL != connection->response) && | ||
182 | (MHD_resp_sender_sendfile == connection->resp_sender) ) | ||
183 | { | ||
184 | /* can use sendfile */ | ||
185 | int file_fd = connection->response->fd; | ||
186 | uint64_t left; | ||
187 | uint64_t offsetu64; | ||
188 | #ifndef HAVE_SENDFILE64 | ||
189 | off_t offset; | ||
190 | #else /* HAVE_SENDFILE64 */ | ||
191 | off64_t offset; | ||
192 | #endif /* HAVE_SENDFILE64 */ | ||
193 | offsetu64 = connection->response_write_position + connection->response->fd_off; | ||
194 | left = connection->response->total_size - connection->response_write_position; | ||
195 | ret = 0; | ||
196 | #ifndef HAVE_SENDFILE64 | ||
197 | if ((uint64_t)OFF_T_MAX < offsetu64) | ||
198 | MHD_socket_set_error_to_ENOMEM (); | ||
199 | else | ||
200 | { | ||
201 | offset = (off_t) offsetu64; | ||
202 | ret = sendfile (connection->socket_fd, | ||
203 | file_fd, | ||
204 | &offset, | ||
205 | left); | ||
206 | } | ||
207 | #else /* HAVE_SENDFILE64 */ | ||
208 | if ((uint64_t)OFF64_T_MAX < offsetu64) | ||
209 | MHD_socket_set_error_to_ENOMEM (); | ||
210 | else | ||
211 | { | ||
212 | offset = (off64_t) offsetu64; | ||
213 | ret = sendfile64 (connection->socket_fd, | ||
214 | file_fd, | ||
215 | &offset, | ||
216 | left); | ||
217 | } | ||
218 | #endif /* HAVE_SENDFILE64 */ | ||
219 | if (0 < ret) | ||
220 | { | ||
221 | /* write successful */ | ||
222 | #ifdef EPOLL_SUPPORT | ||
223 | if (left > (uint64_t)ret) | ||
224 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
225 | #endif /* EPOLL_SUPPORT */ | ||
226 | return ret; | ||
227 | } | ||
228 | err = MHD_socket_get_error_(); | ||
229 | #ifdef EPOLL_SUPPORT | ||
230 | if ( (0 > ret) && (MHD_SCKT_ERR_IS_EAGAIN_(err)) ) | ||
231 | { | ||
232 | /* EAGAIN --- no longer write-ready */ | ||
233 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
234 | } | ||
235 | #endif | ||
236 | if (MHD_SCKT_ERR_IS_EINTR_ (err) || | ||
237 | MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
238 | return 0; | ||
239 | if (MHD_SCKT_ERR_IS_(err, | ||
240 | MHD_SCKT_EBADF_)) | ||
241 | return -1; | ||
242 | /* sendfile() failed with EINVAL if mmap()-like operations are not | ||
243 | supported for FD or other 'unusual' errors occurred, so we should try | ||
244 | to fall back to 'SEND'; see also this thread for info on | ||
245 | odd libc/Linux behavior with sendfile: | ||
246 | http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */ | ||
247 | connection->resp_sender = MHD_resp_sender_std; | ||
248 | } | ||
249 | #endif | ||
250 | ret = MHD_send_ (connection->socket_fd, | ||
251 | other, | ||
252 | i); | ||
253 | err = MHD_socket_get_error_(); | ||
254 | #ifdef EPOLL_SUPPORT | ||
255 | if (0 > ret) | ||
256 | { | ||
257 | /* EAGAIN --- no longer write-ready */ | ||
258 | if (MHD_SCKT_ERR_IS_EAGAIN_(err)) | ||
259 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
260 | } | ||
261 | else if (i > (size_t)ret) | ||
262 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
263 | #endif | ||
264 | /* Handle broken kernel / libc, returning -1 but not setting errno; | ||
265 | kill connection as that should be safe; reported on mailinglist here: | ||
266 | http://lists.gnu.org/archive/html/libmicrohttpd/2014-10/msg00023.html */ | ||
267 | if ( (0 > ret) && | ||
268 | (0 == err) ) | ||
269 | MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_); | ||
270 | return ret; | ||
271 | } | ||
272 | |||
273 | |||
274 | /** | ||
113 | * Check whether is possible to force push socket buffer content as | 275 | * Check whether is possible to force push socket buffer content as |
114 | * partial packet. | 276 | * partial packet. |
115 | * MHD use different buffering logic depending on whether flushing of | 277 | * MHD use different buffering logic depending on whether flushing of |
@@ -3445,6 +3607,8 @@ MHD_set_http_callbacks_ (struct MHD_Connection *connection) | |||
3445 | { | 3607 | { |
3446 | connection->read_handler = &MHD_connection_handle_read; | 3608 | connection->read_handler = &MHD_connection_handle_read; |
3447 | connection->write_handler = &MHD_connection_handle_write; | 3609 | connection->write_handler = &MHD_connection_handle_write; |
3610 | connection->recv_cls = &recv_param_adapter; | ||
3611 | connection->send_cls = &send_param_adapter; | ||
3448 | } | 3612 | } |
3449 | 3613 | ||
3450 | 3614 | ||