GNU libmicrohttpd  0.9.72
daemon_poll.c
Go to the documentation of this file.
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 */
24 #include "internal.h"
25 #include "connection_add.h"
28 #include "daemon_poll.h"
29 #include "upgrade_process.h"
30 #include "request_resume.h"
31 
32 
33 #ifdef HAVE_POLL
34 
35 
36 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
37 
46 static void
47 urh_update_pollfd (struct MHD_UpgradeResponseHandle *urh,
48  struct pollfd p[2])
49 {
50  p[0].events = 0;
51  p[1].events = 0;
52 
53  if (urh->in_buffer_used < urh->in_buffer_size)
54  p[0].events |= POLLIN;
55  if (0 != urh->out_buffer_used)
56  p[0].events |= POLLOUT;
57 
58  /* Do not monitor again for errors if error was detected before as
59  * error state is remembered. */
60  if ((0 == (urh->app.celi & MHD_EPOLL_STATE_ERROR)) &&
61  ((0 != urh->in_buffer_size) ||
62  (0 != urh->out_buffer_size) ||
63  (0 != urh->out_buffer_used)))
64  p[0].events |= MHD_POLL_EVENTS_ERR_DISC;
65 
66  if (urh->out_buffer_used < urh->out_buffer_size)
67  p[1].events |= POLLIN;
68  if (0 != urh->in_buffer_used)
69  p[1].events |= POLLOUT;
70 
71  /* Do not monitor again for errors if error was detected before as
72  * error state is remembered. */
73  if ((0 == (urh->mhd.celi & MHD_EPOLL_STATE_ERROR)) &&
74  ((0 != urh->out_buffer_size) ||
75  (0 != urh->in_buffer_size) ||
76  (0 != urh->in_buffer_used)))
77  p[1].events |= MHD_POLL_EVENTS_ERR_DISC;
78 }
79 
80 
87 static void
88 urh_to_pollfd (struct MHD_UpgradeResponseHandle *urh,
89  struct pollfd p[2])
90 {
91  p[0].fd = urh->connection->socket_fd;
92  p[1].fd = urh->mhd.socket;
93  urh_update_pollfd (urh,
94  p);
95 }
96 
97 
103 static void
104 urh_from_pollfd (struct MHD_UpgradeResponseHandle *urh,
105  struct pollfd p[2])
106 {
107  /* Reset read/write ready, preserve error state. */
110 
111  if (0 != (p[0].revents & POLLIN))
112  urh->app.celi |= MHD_EPOLL_STATE_READ_READY;
113  if (0 != (p[0].revents & POLLOUT))
114  urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY;
115  if (0 != (p[0].revents & POLLHUP))
117  if (0 != (p[0].revents & MHD_POLL_REVENTS_ERRROR))
118  urh->app.celi |= MHD_EPOLL_STATE_ERROR;
119  if (0 != (p[1].revents & POLLIN))
120  urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY;
121  if (0 != (p[1].revents & POLLOUT))
122  urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY;
123  if (0 != (p[1].revents & POLLHUP))
124  urh->mhd.celi |= MHD_EPOLL_STATE_ERROR;
125  if (0 != (p[1].revents & MHD_POLL_REVENTS_ERRROR))
127 }
128 
129 
130 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
131 
132 
141 enum MHD_StatusCode
142 MHD_daemon_poll_all_ (struct MHD_Daemon *daemon,
143  bool may_block)
144 {
145  unsigned int num_connections;
146  struct MHD_Connection *pos;
147  struct MHD_Connection *prev;
148 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
149  struct MHD_UpgradeResponseHandle *urh;
150  struct MHD_UpgradeResponseHandle *urhn;
151 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
152 
153  if ( (! daemon->disallow_suspend_resume) &&
155  may_block = false;
156 
157  /* count number of connections and thus determine poll set size */
158  num_connections = 0;
159  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
160  num_connections++;
161 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
162  for (urh = daemon->urh_head; NULL != urh; urh = urh->next)
163  num_connections += 2;
164 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
165  {
166  MHD_UNSIGNED_LONG_LONG ltimeout;
167  unsigned int i;
168  int timeout;
169  unsigned int poll_server;
170  int poll_listen;
171  int poll_itc_idx;
172  struct pollfd *p;
173  MHD_socket ls;
174 
175  p = MHD_calloc_ ((2 + num_connections),
176  sizeof (struct pollfd));
177  if (NULL == p)
178  {
179 #ifdef HAVE_MESSAGES
180  MHD_DLOG (daemon,
181  MHD_SC_POLL_MALLOC_FAILURE,
182  _ ("Error allocating memory: %s\n"),
183  MHD_strerror_ (errno));
184 #endif
185  return MHD_SC_POLL_MALLOC_FAILURE;
186  }
187  poll_server = 0;
188  poll_listen = -1;
189  if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_socket)) &&
190  (! daemon->was_quiesced) &&
191  (daemon->connections < daemon->global_connection_limit) &&
192  (! daemon->at_limit) )
193  {
194  /* only listen if we are not at the connection limit */
195  p[poll_server].fd = ls;
196  p[poll_server].events = POLLIN;
197  p[poll_server].revents = 0;
198  poll_listen = (int) poll_server;
199  poll_server++;
200  }
201  poll_itc_idx = -1;
202  if (MHD_ITC_IS_VALID_ (daemon->itc))
203  {
204  p[poll_server].fd = MHD_itc_r_fd_ (daemon->itc);
205  p[poll_server].events = POLLIN;
206  p[poll_server].revents = 0;
207  poll_itc_idx = (int) poll_server;
208  poll_server++;
209  }
210  if (! may_block)
211  timeout = 0;
212  else if ( (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_mode) ||
213  (MHD_SC_OK != /* FIXME: distinguish between NO_TIMEOUT and errors! */
214  MHD_daemon_get_timeout (daemon,
215  &ltimeout)) )
216  timeout = -1;
217  else
218  timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout;
219 
220  i = 0;
221  for (pos = daemon->connections_tail; NULL != pos; pos = pos->prev)
222  {
223  p[poll_server + i].fd = pos->socket_fd;
224  switch (pos->request.event_loop_info)
225  {
227  p[poll_server + i].events |= POLLIN | MHD_POLL_EVENTS_ERR_DISC;
228  break;
230  p[poll_server + i].events |= POLLOUT | MHD_POLL_EVENTS_ERR_DISC;
231  break;
233  p[poll_server + i].events |= MHD_POLL_EVENTS_ERR_DISC;
234  break;
236  timeout = 0; /* clean up "pos" immediately */
237  break;
238  }
239  i++;
240  }
241 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
242  for (urh = daemon->urh_tail; NULL != urh; urh = urh->prev)
243  {
244  urh_to_pollfd (urh,
245  &(p[poll_server + i]));
246  i += 2;
247  }
248 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
249  if (0 == poll_server + num_connections)
250  {
251  free (p);
252  return MHD_SC_OK;
253  }
254  if (MHD_sys_poll_ (p,
255  poll_server + num_connections,
256  timeout) < 0)
257  {
258  const int err = MHD_socket_get_error_ ();
259  if (MHD_SCKT_ERR_IS_EINTR_ (err))
260  {
261  free (p);
262  return MHD_SC_OK;
263  }
264 #ifdef HAVE_MESSAGES
265  MHD_DLOG (daemon,
266  MHD_SC_UNEXPECTED_POLL_ERROR,
267  _ ("poll failed: %s\n"),
268  MHD_socket_strerr_ (err));
269 #endif
270  free (p);
271  return MHD_SC_UNEXPECTED_POLL_ERROR;
272  }
273 
274  /* Reset. New value will be set when connections are processed. */
275  daemon->data_already_pending = false;
276 
277  /* handle ITC FD */
278  /* do it before any other processing so
279  new signals will be processed in next loop */
280  if ( (-1 != poll_itc_idx) &&
281  (0 != (p[poll_itc_idx].revents & POLLIN)) )
282  MHD_itc_clear_ (daemon->itc);
283 
284  /* handle shutdown */
285  if (daemon->shutdown)
286  {
287  free (p);
288  return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
289  }
290  i = 0;
291  prev = daemon->connections_tail;
292  while (NULL != (pos = prev))
293  {
294  prev = pos->prev;
295  /* first, sanity checks */
296  if (i >= num_connections)
297  break; /* connection list changed somehow, retry later ... */
298  if (p[poll_server + i].fd != pos->socket_fd)
299  continue; /* fd mismatch, something else happened, retry later ... */
301  0 != (p[poll_server + i].revents & POLLIN),
302  0 != (p[poll_server + i].revents
303  & POLLOUT),
304  0 != (p[poll_server + i].revents
305  & MHD_POLL_REVENTS_ERR_DISC));
306  i++;
307  }
308 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
309  for (urh = daemon->urh_tail; NULL != urh; urh = urhn)
310  {
311  if (i >= num_connections)
312  break; /* connection list changed somehow, retry later ... */
313 
314  /* Get next connection here as connection can be removed
315  * from 'daemon->urh_head' list. */
316  urhn = urh->prev;
317  /* Check for fd mismatch. FIXME: required for safety? */
318  if ((p[poll_server + i].fd != urh->connection->socket_fd) ||
319  (p[poll_server + i + 1].fd != urh->mhd.socket))
320  break;
321  urh_from_pollfd (urh,
322  &p[poll_server + i]);
323  i += 2;
324  MHD_upgrade_response_handle_process_ (urh);
325  /* Finished forwarding? */
326  if ( (0 == urh->in_buffer_size) &&
327  (0 == urh->out_buffer_size) &&
328  (0 == urh->in_buffer_used) &&
329  (0 == urh->out_buffer_used) )
330  {
331  /* MHD_connection_finish_forward_() will remove connection from
332  * 'daemon->urh_head' list. */
333  MHD_connection_finish_forward_ (urh->connection);
334  urh->clean_ready = true;
335  /* If 'urh->was_closed' already was set to true, connection will be
336  * moved immediately to cleanup list. Otherwise connection
337  * will stay in suspended list until 'urh' will be marked
338  * with 'was_closed' by application. */
339  MHD_request_resume (&urh->connection->request);
340  }
341  }
342 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
343  /* handle 'listen' FD */
344  if ( (-1 != poll_listen) &&
345  (0 != (p[poll_listen].revents & POLLIN)) )
346  (void) MHD_accept_connection_ (daemon);
347 
348  free (p);
349  }
350  return MHD_SC_OK;
351 }
352 
353 
361 enum MHD_StatusCode
362 MHD_daemon_poll_listen_socket_ (struct MHD_Daemon *daemon,
363  bool may_block)
364 {
365  struct pollfd p[2];
366  int timeout;
367  unsigned int poll_count;
368  int poll_listen;
369  int poll_itc_idx;
370  MHD_socket ls;
371 
372  memset (&p,
373  0,
374  sizeof (p));
375  poll_count = 0;
376  poll_listen = -1;
377  poll_itc_idx = -1;
378  if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_socket)) &&
379  (! daemon->was_quiesced) )
380 
381  {
382  p[poll_count].fd = ls;
383  p[poll_count].events = POLLIN;
384  p[poll_count].revents = 0;
385  poll_listen = poll_count;
386  poll_count++;
387  }
388  if (MHD_ITC_IS_VALID_ (daemon->itc))
389  {
390  p[poll_count].fd = MHD_itc_r_fd_ (daemon->itc);
391  p[poll_count].events = POLLIN;
392  p[poll_count].revents = 0;
393  poll_itc_idx = poll_count;
394  poll_count++;
395  }
396 
397  if (! daemon->disallow_suspend_resume)
398  (void) MHD_resume_suspended_connections_ (daemon);
399 
400  if (! may_block)
401  timeout = 0;
402  else
403  timeout = -1;
404  if (0 == poll_count)
405  return MHD_SC_OK;
406  if (MHD_sys_poll_ (p,
407  poll_count,
408  timeout) < 0)
409  {
410  const int err = MHD_socket_get_error_ ();
411 
412  if (MHD_SCKT_ERR_IS_EINTR_ (err))
413  return MHD_SC_OK;
414 #ifdef HAVE_MESSAGES
415  MHD_DLOG (daemon,
416  MHD_SC_UNEXPECTED_POLL_ERROR,
417  _ ("poll failed: %s\n"),
418  MHD_socket_strerr_ (err));
419 #endif
420  return MHD_SC_UNEXPECTED_POLL_ERROR;
421  }
422  if ( (-1 != poll_itc_idx) &&
423  (0 != (p[poll_itc_idx].revents & POLLIN)) )
424  MHD_itc_clear_ (daemon->itc);
425 
426  /* handle shutdown */
427  if (daemon->shutdown)
428  return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
429  if ( (-1 != poll_listen) &&
430  (0 != (p[poll_listen].revents & POLLIN)) )
431  (void) MHD_accept_connection_ (daemon);
432  return MHD_SC_OK;
433 }
434 
435 
436 #endif
437 
438 
446 enum MHD_StatusCode
447 MHD_daemon_poll_ (struct MHD_Daemon *daemon,
448  bool may_block)
449 {
450 #ifdef HAVE_POLL
451  if (daemon->shutdown)
452  return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
453  if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_mode)
454  return MHD_daemon_poll_all_ (daemon,
455  may_block);
456  return MHD_daemon_poll_listen_socket_ (daemon,
457  may_block);
458 #else
459  /* This code should be dead, as we should have checked
460  this earlier... */
461  return MHD_SC_POLL_NOT_SUPPORTED;
462 #endif
463 }
464 
465 
466 #ifdef HAVE_POLL
467 #ifdef HTTPS_SUPPORT
474 void
475 MHD_daemon_upgrade_connection_with_poll_ (struct MHD_Connection *con)
476 {
477  struct MHD_UpgradeResponseHandle *urh = con->request.urh;
478  struct pollfd p[2];
479 
480  memset (p,
481  0,
482  sizeof (p));
483  p[0].fd = urh->connection->socket_fd;
484  p[1].fd = urh->mhd.socket;
485 
486  while ( (0 != urh->in_buffer_size) ||
487  (0 != urh->out_buffer_size) ||
488  (0 != urh->in_buffer_used) ||
489  (0 != urh->out_buffer_used) )
490  {
491  int timeout;
492 
493  urh_update_pollfd (urh,
494  p);
495 
496  if ( (con->tls_read_ready) &&
497  (urh->in_buffer_used < urh->in_buffer_size))
498  timeout = 0; /* No need to wait if incoming data is already pending in TLS buffers. */
499  else
500  timeout = -1;
501 
502  if (MHD_sys_poll_ (p,
503  2,
504  timeout) < 0)
505  {
506  const int err = MHD_socket_get_error_ ();
507 
508  if (MHD_SCKT_ERR_IS_EINTR_ (err))
509  continue;
510 #ifdef HAVE_MESSAGES
511  MHD_DLOG (con->daemon,
512  MHD_SC_UNEXPECTED_POLL_ERROR,
513  _ ("Error during poll: `%s'\n"),
514  MHD_socket_strerr_ (err));
515 #endif
516  break;
517  }
518  urh_from_pollfd (urh,
519  p);
520  MHD_upgrade_response_handle_process_ (urh);
521  }
522 }
523 
524 
525 #endif
526 #endif
527 
528 /* end of daemon_poll.c */
enum MHD_StatusCode MHD_accept_connection_(struct MHD_Daemon *daemon)
functions to add connection to our active set
int MHD_connection_call_handlers_(struct MHD_Connection *con, bool read_ready, bool write_ready, bool force_close)
function to call event handlers based on event mask
complete upgrade socket forwarding operation in TLS mode
void MHD_connection_finish_forward_(struct MHD_Connection *connection) MHD_NONNULL(1)
enum MHD_StatusCode MHD_daemon_poll_(struct MHD_Daemon *daemon, bool may_block)
Definition: daemon_poll.c:447
non-public functions provided by daemon_poll.c
enum MHD_StatusCode MHD_daemon_get_timeout(struct MHD_Daemon *daemon, MHD_UNSIGNED_LONG_LONG *timeout)
@ MHD_EPOLL_STATE_READ_READY
Definition: internal.h:600
@ MHD_EPOLL_STATE_WRITE_READY
Definition: internal.h:606
@ MHD_EPOLL_STATE_ERROR
Definition: internal.h:626
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:98
#define MHD_strerror_(errnum)
Definition: mhd_compat.h:44
#define MHD_socket_strerr_(err)
Definition: mhd_sockets.h:542
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:523
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:634
#define NULL
Definition: reason_phrase.c:30
#define _(String)
Definition: mhd_options.h:42
internal shared structures
@ MHD_EVENT_LOOP_INFO_READ
Definition: internal.h:234
@ MHD_EVENT_LOOP_INFO_WRITE
Definition: internal.h:239
@ MHD_EVENT_LOOP_INFO_CLEANUP
Definition: internal.h:249
@ MHD_EVENT_LOOP_INFO_BLOCK
Definition: internal.h:244
int MHD_socket
Definition: microhttpd.h:196
#define MHD_UNSIGNED_LONG_LONG
Definition: microhttpd.h:299
int fd
Definition: microhttpd.h:3195
#define MHD_INVALID_SOCKET
Definition: microhttpd.h:197
void MHD_request_resume(struct MHD_Request *request)
bool MHD_resume_suspended_connections_(struct MHD_Daemon *daemon)
implementation of MHD_request_resume()
MHD_socket socket_fd
Definition: internal.h:752
bool tls_read_ready
Definition: internal.h:769
struct MHD_Request request
Definition: internal.h:717
struct MHD_Connection * next
Definition: internal.h:651
struct MHD_Connection * prev
Definition: internal.h:656
struct MHD_Daemon * daemon
Definition: internal.h:675
bool data_already_pending
Definition: internal.h:1500
bool at_limit
Definition: internal.h:1483
bool was_quiesced
Definition: internal.h:1505
struct MHD_Connection * connections_head
Definition: internal.h:1155
unsigned int connections
Definition: internal.h:1361
struct MHD_itc_ itc
Definition: internal.h:1410
volatile bool shutdown
Definition: internal.h:1526
bool disallow_suspend_resume
Definition: internal.h:1468
MHD_socket listen_socket
Definition: internal.h:1377
enum MHD_ThreadingMode threading_mode
Definition: internal.h:1417
unsigned int global_connection_limit
Definition: internal.h:1351
struct MHD_Connection * connections_tail
Definition: internal.h:1160
enum MHD_RequestEventLoopInfo event_loop_info
Definition: internal.h:559
function to process upgrade activity (over TLS)