aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/connection.c')
-rw-r--r--src/microhttpd/connection.c164
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 */
120static ssize_t
121recv_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 */
161static ssize_t
162send_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