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