GNU libmicrohttpd  0.9.62
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
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) &&
152  (MHD_resume_suspended_connections_ (daemon)) )
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 & POLLOUT),
301  0 != (p[poll_server+i].revents & MHD_POLL_REVENTS_ERR_DISC));
302  i++;
303  }
304 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
305  for (urh = daemon->urh_tail; NULL != urh; urh = urhn)
306  {
307  if (i >= num_connections)
308  break; /* connection list changed somehow, retry later ... */
309 
310  /* Get next connection here as connection can be removed
311  * from 'daemon->urh_head' list. */
312  urhn = urh->prev;
313  /* Check for fd mismatch. FIXME: required for safety? */
314  if ((p[poll_server+i].fd != urh->connection->socket_fd) ||
315  (p[poll_server+i+1].fd != urh->mhd.socket))
316  break;
317  urh_from_pollfd (urh,
318  &p[poll_server+i]);
319  i += 2;
320  MHD_upgrade_response_handle_process_ (urh);
321  /* Finished forwarding? */
322  if ( (0 == urh->in_buffer_size) &&
323  (0 == urh->out_buffer_size) &&
324  (0 == urh->in_buffer_used) &&
325  (0 == urh->out_buffer_used) )
326  {
327  /* MHD_connection_finish_forward_() will remove connection from
328  * 'daemon->urh_head' list. */
329  MHD_connection_finish_forward_ (urh->connection);
330  urh->clean_ready = true;
331  /* If 'urh->was_closed' already was set to true, connection will be
332  * moved immediately to cleanup list. Otherwise connection
333  * will stay in suspended list until 'urh' will be marked
334  * with 'was_closed' by application. */
335  MHD_request_resume (&urh->connection->request);
336  }
337  }
338 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
339  /* handle 'listen' FD */
340  if ( (-1 != poll_listen) &&
341  (0 != (p[poll_listen].revents & POLLIN)) )
342  (void) MHD_accept_connection_ (daemon);
343 
344  free(p);
345  }
346  return MHD_SC_OK;
347 }
348 
349 
357 enum MHD_StatusCode
358 MHD_daemon_poll_listen_socket_ (struct MHD_Daemon *daemon,
359  bool may_block)
360 {
361  struct pollfd p[2];
362  int timeout;
363  unsigned int poll_count;
364  int poll_listen;
365  int poll_itc_idx;
366  MHD_socket ls;
367 
368  memset (&p,
369  0,
370  sizeof (p));
371  poll_count = 0;
372  poll_listen = -1;
373  poll_itc_idx = -1;
374  if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_socket)) &&
375  (! daemon->was_quiesced) )
376 
377  {
378  p[poll_count].fd = ls;
379  p[poll_count].events = POLLIN;
380  p[poll_count].revents = 0;
381  poll_listen = poll_count;
382  poll_count++;
383  }
384  if (MHD_ITC_IS_VALID_(daemon->itc))
385  {
386  p[poll_count].fd = MHD_itc_r_fd_ (daemon->itc);
387  p[poll_count].events = POLLIN;
388  p[poll_count].revents = 0;
389  poll_itc_idx = poll_count;
390  poll_count++;
391  }
392 
393  if (! daemon->disallow_suspend_resume)
394  (void) MHD_resume_suspended_connections_ (daemon);
395 
396  if (! may_block)
397  timeout = 0;
398  else
399  timeout = -1;
400  if (0 == poll_count)
401  return MHD_SC_OK;
402  if (MHD_sys_poll_(p,
403  poll_count,
404  timeout) < 0)
405  {
406  const int err = MHD_socket_get_error_ ();
407 
408  if (MHD_SCKT_ERR_IS_EINTR_ (err))
409  return MHD_SC_OK;
410 #ifdef HAVE_MESSAGES
411  MHD_DLOG (daemon,
412  MHD_SC_UNEXPECTED_POLL_ERROR,
413  _("poll failed: %s\n"),
414  MHD_socket_strerr_ (err));
415 #endif
416  return MHD_SC_UNEXPECTED_POLL_ERROR;
417  }
418  if ( (-1 != poll_itc_idx) &&
419  (0 != (p[poll_itc_idx].revents & POLLIN)) )
420  MHD_itc_clear_ (daemon->itc);
421 
422  /* handle shutdown */
423  if (daemon->shutdown)
424  return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
425  if ( (-1 != poll_listen) &&
426  (0 != (p[poll_listen].revents & POLLIN)) )
427  (void) MHD_accept_connection_ (daemon);
428  return MHD_SC_OK;
429 }
430 #endif
431 
432 
440 enum MHD_StatusCode
441 MHD_daemon_poll_ (struct MHD_Daemon *daemon,
442  bool may_block)
443 {
444 #ifdef HAVE_POLL
445  if (daemon->shutdown)
446  return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
447  if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_mode)
448  return MHD_daemon_poll_all_ (daemon,
449  may_block);
450  return MHD_daemon_poll_listen_socket_ (daemon,
451  may_block);
452 #else
453  /* This code should be dead, as we should have checked
454  this earlier... */
455  return MHD_SC_POLL_NOT_SUPPORTED;
456 #endif
457 }
458 
459 
460 #ifdef HAVE_POLL
461 #ifdef HTTPS_SUPPORT
462 
468 void
469 MHD_daemon_upgrade_connection_with_poll_ (struct MHD_Connection *con)
470 {
471  struct MHD_UpgradeResponseHandle *urh = con->request.urh;
472  struct pollfd p[2];
473 
474  memset (p,
475  0,
476  sizeof (p));
477  p[0].fd = urh->connection->socket_fd;
478  p[1].fd = urh->mhd.socket;
479 
480  while ( (0 != urh->in_buffer_size) ||
481  (0 != urh->out_buffer_size) ||
482  (0 != urh->in_buffer_used) ||
483  (0 != urh->out_buffer_used) )
484  {
485  int timeout;
486 
487  urh_update_pollfd (urh,
488  p);
489 
490  if ( (con->tls_read_ready) &&
491  (urh->in_buffer_used < urh->in_buffer_size))
492  timeout = 0; /* No need to wait if incoming data is already pending in TLS buffers. */
493  else
494  timeout = -1;
495 
496  if (MHD_sys_poll_ (p,
497  2,
498  timeout) < 0)
499  {
500  const int err = MHD_socket_get_error_ ();
501 
502  if (MHD_SCKT_ERR_IS_EINTR_ (err))
503  continue;
504 #ifdef HAVE_MESSAGES
505  MHD_DLOG (con->daemon,
506  MHD_SC_UNEXPECTED_POLL_ERROR,
507  _("Error during poll: `%s'\n"),
508  MHD_socket_strerr_ (err));
509 #endif
510  break;
511  }
512  urh_from_pollfd (urh,
513  p);
514  MHD_upgrade_response_handle_process_ (urh);
515  }
516 }
517 #endif
518 #endif
519 
520 /* end of daemon_poll.c */
struct MHD_Request request
Definition: internal.h:714
bool data_already_pending
Definition: internal.h:1497
if(daemon->resuming)
MHD_mutex_lock_chk_ & daemon
unsigned int global_connection_limit
Definition: internal.h:1348
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:507
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:96
#define MHD_socket_strerr_(err)
Definition: mhd_sockets.h:525
struct MHD_Connection * prev
int MHD_socket
Definition: microhttpd.h:181
internal shared structures
MHD_socket listen_socket
Definition: internal.h:1374
#define MHD_UNSIGNED_LONG_LONG
Definition: microhttpd.h:277
struct MHD_Daemon * daemon
Definition: internal.h:672
struct MHD_Connection * next
Definition: internal.h:648
bool was_quiesced
Definition: internal.h:1502
struct MHD_Connection * connections_tail
Definition: internal.h:1157
enum MHD_StatusCode MHD_daemon_get_timeout(struct MHD_Daemon *daemon, MHD_UNSIGNED_LONG_LONG *timeout)
int fd
Definition: microhttpd.h:2837
#define MHD_INVALID_SOCKET
Definition: microhttpd.h:182
MHD_socket socket_fd
Definition: internal.h:749
struct MHD_Connection * connections_head
Definition: internal.h:1152
complete upgrade socket forwarding operation in TLS mode
enum MHD_RequestEventLoopInfo event_loop_info
Definition: internal.h:556
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:1358
struct MHD_Connection * prev
Definition: internal.h:653
enum MHD_StatusCode MHD_daemon_poll_(struct MHD_Daemon *daemon, bool may_block)
Definition: daemon_poll.c:441
#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)
bool tls_read_ready
Definition: internal.h:766
struct MHD_itc_ itc
Definition: internal.h:1407
#define MHD_connection_finish_forward_(conn)
Definition: connection.h:156
non-public functions provided by daemon_poll.c
bool at_limit
Definition: internal.h:1480
#define _(String)
Definition: mhd_options.h:42
bool disallow_suspend_resume
Definition: internal.h:1465
enum MHD_ThreadingMode threading_mode
Definition: internal.h:1414
volatile bool shutdown
Definition: internal.h:1523
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:613
function to process upgrade activity (over TLS)
functions to add connection to our active set
implementation of MHD_request_resume()