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 */
19 
20 /**
21  * @file lib/daemon_epoll.c
22  * @brief functions to run epoll()-based event loop
23  * @author Christian Grothoff
24  */
25 #include "internal.h"
26 #include "connection_add.h"
27 #include "connection_call_handlers.h"
28 #include "connection_finish_forward.h"
29 #include "daemon_epoll.h"
30 #include "upgrade_process.h"
31 #include "request_resume.h"
32 
33 #ifdef EPOLL_SUPPORT
34 
35 /**
36  * How many events to we process at most per epoll() call?  Trade-off
37  * between required stack-size and number of system calls we have to
38  * make; 128 should be way enough to avoid more than one system call
39  * for most scenarios, and still be moderate in stack size
40  * consumption.  Embedded systems might want to choose a smaller value
41  * --- but why use epoll() on such a system in the first place?
42  */
43 #define MAX_EVENTS 128
44 
45 
46 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
47 
48 /**
49  * Checks whether @a urh has some data to process.
50  *
51  * @param urh upgrade handler to analyse
52  * @return 'true' if @a urh has some data to process,
53  *         'false' otherwise
54  */
55 static bool
is_urh_ready(struct MHD_UpgradeResponseHandle * const urh)56 is_urh_ready (struct MHD_UpgradeResponseHandle *const urh)
57 {
58   const struct MHD_Connection *const connection = urh->connection;
59 
60   if ( (0 == urh->in_buffer_size) &&
61        (0 == urh->out_buffer_size) &&
62        (0 == urh->in_buffer_used) &&
63        (0 == urh->out_buffer_used) )
64     return false;
65 
66   if (connection->daemon->shutdown)
67     return true;
68 
69   if ( ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) ||
70          (connection->tls_read_ready) ) &&
71        (urh->in_buffer_used < urh->in_buffer_size) )
72     return true;
73 
74   if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) &&
75        (urh->out_buffer_used < urh->out_buffer_size) )
76     return true;
77 
78   if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) &&
79        (urh->out_buffer_used > 0) )
80     return true;
81 
82   if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) &&
83        (urh->in_buffer_used > 0) )
84     return true;
85 
86   return false;
87 }
88 
89 
90 /**
91  * Do epoll()-based processing for TLS connections that have been
92  * upgraded.  This requires a separate epoll() invocation as we
93  * cannot use the `struct MHD_Connection` data structures for
94  * the `union epoll_data` in this case.
95  * @remark To be called only from thread that process
96  * daemon's select()/poll()/etc.
97  *
98  * @param daemon the daemmon for which we process connections
99  * @return #MHD_SC_OK on success
100  */
101 static enum MHD_StatusCode
run_epoll_for_upgrade(struct MHD_Daemon * daemon)102 run_epoll_for_upgrade (struct MHD_Daemon *daemon)
103 {
104   struct epoll_event events[MAX_EVENTS];
105   int num_events;
106   struct MHD_UpgradeResponseHandle *pos;
107   struct MHD_UpgradeResponseHandle *prev;
108 
109   num_events = MAX_EVENTS;
110   while (MAX_EVENTS == num_events)
111   {
112     unsigned int i;
113 
114     /* update event masks */
115     num_events = epoll_wait (daemon->epoll_upgrade_fd,
116                              events,
117                              MAX_EVENTS,
118                              0);
119     if (-1 == num_events)
120     {
121       const int err = MHD_socket_get_error_ ();
122       if (MHD_SCKT_ERR_IS_EINTR_ (err))
123         return MHD_SC_OK;
124 #ifdef HAVE_MESSAGES
125       MHD_DLOG (daemon,
126                 MHD_SC_UNEXPECTED_EPOLL_WAIT_ERROR,
127                 _ ("Call to epoll_wait failed: %s\n"),
128                 MHD_socket_strerr_ (err));
129 #endif
130       return MHD_SC_UNEXPECTED_EPOLL_WAIT_ERROR;
131     }
132     for (i = 0; i < (unsigned int) num_events; i++)
133     {
134       struct UpgradeEpollHandle *const ueh = events[i].data.ptr;
135       struct MHD_UpgradeResponseHandle *const urh = ueh->urh;
136       bool new_err_state = false;
137 
138       if (urh->clean_ready)
139         continue;
140 
141       /* Update ueh state based on what is ready according to epoll() */
142       if (0 != (events[i].events & EPOLLIN))
143         ueh->celi |= MHD_EPOLL_STATE_READ_READY;
144       if (0 != (events[i].events & EPOLLOUT))
145         ueh->celi |= MHD_EPOLL_STATE_WRITE_READY;
146       if (0 != (events[i].events & EPOLLHUP))
147         ueh->celi |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY;
148 
149       if ( (0 == (ueh->celi & MHD_EPOLL_STATE_ERROR)) &&
150            (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) )
151       {
152         /* Process new error state only one time
153          * and avoid continuously marking this connection
154          * as 'ready'. */
155         ueh->celi |= MHD_EPOLL_STATE_ERROR;
156         new_err_state = true;
157       }
158 
159       if (! urh->in_eready_list)
160       {
161         if (new_err_state ||
162             is_urh_ready (urh))
163         {
164           EDLL_insert (daemon->eready_urh_head,
165                        daemon->eready_urh_tail,
166                        urh);
167           urh->in_eready_list = true;
168         }
169       }
170     }
171   }
172   prev = daemon->eready_urh_tail;
173   while (NULL != (pos = prev))
174   {
175     prev = pos->prevE;
176     MHD_upgrade_response_handle_process_ (pos);
177     if (! is_urh_ready (pos))
178     {
179       EDLL_remove (daemon->eready_urh_head,
180                    daemon->eready_urh_tail,
181                    pos);
182       pos->in_eready_list = false;
183     }
184     /* Finished forwarding? */
185     if ( (0 == pos->in_buffer_size) &&
186          (0 == pos->out_buffer_size) &&
187          (0 == pos->in_buffer_used) &&
188          (0 == pos->out_buffer_used) )
189     {
190       MHD_connection_finish_forward_ (pos->connection);
191       pos->clean_ready = true;
192       /* If 'pos->was_closed' already was set to true, connection
193        * will be moved immediately to cleanup list. Otherwise
194        * connection will stay in suspended list until 'pos' will
195        * be marked with 'was_closed' by application. */
196       MHD_request_resume (&pos->connection->request);
197     }
198   }
199 
200   return MHD_SC_OK;
201 }
202 
203 
204 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
205 
206 
207 /**
208  * Do epoll()-based processing (this function is allowed to
209  * block if @a may_block is set to #MHD_YES).
210  *
211  * @param daemon daemon to run poll loop for
212  * @param may_block true if blocking, false if non-blocking
213  * @return #MHD_SC_OK on success
214  */
215 enum MHD_StatusCode
MHD_daemon_epoll_(struct MHD_Daemon * daemon,bool may_block)216 MHD_daemon_epoll_ (struct MHD_Daemon *daemon,
217                    bool may_block)
218 {
219 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
220   static const char *const upgrade_marker = "upgrade_ptr";
221 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
222   struct MHD_Connection *pos;
223   struct MHD_Connection *prev;
224   struct epoll_event events[MAX_EVENTS];
225   struct epoll_event event;
226   int timeout_ms;
227   MHD_UNSIGNED_LONG_LONG timeout_ll;
228   int num_events;
229   unsigned int i;
230   MHD_socket ls;
231 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
232   bool run_upgraded = false;
233 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
234 
235   if (-1 == daemon->epoll_fd)
236     return MHD_SC_EPOLL_FD_INVALID; /* we're down! */
237   if (daemon->shutdown)
238     return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
239   if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_socket)) &&
240        (! daemon->was_quiesced) &&
241        (daemon->connections < daemon->global_connection_limit) &&
242        (! daemon->listen_socket_in_epoll) &&
243        (! daemon->at_limit) )
244   {
245     event.events = EPOLLIN;
246     event.data.ptr = daemon;
247     if (0 != epoll_ctl (daemon->epoll_fd,
248                         EPOLL_CTL_ADD,
249                         ls,
250                         &event))
251     {
252 #ifdef HAVE_MESSAGES
253       MHD_DLOG (daemon,
254                 MHD_SC_EPOLL_CTL_ADD_FAILED,
255                 _ ("Call to epoll_ctl failed: %s\n"),
256                 MHD_socket_last_strerr_ ());
257 #endif
258       return MHD_SC_EPOLL_CTL_ADD_FAILED;
259     }
260     daemon->listen_socket_in_epoll = true;
261   }
262   if ( (daemon->was_quiesced) &&
263        (daemon->listen_socket_in_epoll) )
264   {
265     if (0 != epoll_ctl (daemon->epoll_fd,
266                         EPOLL_CTL_DEL,
267                         ls,
268                         NULL))
269       MHD_PANIC ("Failed to remove listen FD from epoll set.\n");
270     daemon->listen_socket_in_epoll = false;
271   }
272 
273 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
274   if ( (! daemon->upgrade_fd_in_epoll) &&
275        (-1 != daemon->epoll_upgrade_fd) )
276   {
277     event.events = EPOLLIN | EPOLLOUT;
278     event.data.ptr = (void *) upgrade_marker;
279     if (0 != epoll_ctl (daemon->epoll_fd,
280                         EPOLL_CTL_ADD,
281                         daemon->epoll_upgrade_fd,
282                         &event))
283     {
284 #ifdef HAVE_MESSAGES
285       MHD_DLOG (daemon,
286                 MHD_SC_EPOLL_CTL_ADD_FAILED,
287                 _ ("Call to epoll_ctl failed: %s\n"),
288                 MHD_socket_last_strerr_ ());
289 #endif
290       return MHD_SC_EPOLL_CTL_ADD_FAILED;
291     }
292     daemon->upgrade_fd_in_epoll = true;
293   }
294 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
295   if ( (daemon->listen_socket_in_epoll) &&
296        ( (daemon->connections == daemon->global_connection_limit) ||
297          (daemon->at_limit) ||
298          (daemon->was_quiesced) ) )
299   {
300     /* we're at the connection limit, disable listen socket
301  for event loop for now */
302     if (0 != epoll_ctl (daemon->epoll_fd,
303                         EPOLL_CTL_DEL,
304                         ls,
305                         NULL))
306       MHD_PANIC (_ ("Failed to remove listen FD from epoll set.\n"));
307     daemon->listen_socket_in_epoll = false;
308   }
309 
310   if ( (! daemon->disallow_suspend_resume) &&
311        (MHD_resume_suspended_connections_ (daemon)) )
312     may_block = false;
313 
314   if (may_block)
315   {
316     if (MHD_SC_OK ==   /* FIXME: distinguish between NO_TIMEOUT and errors */
317         MHD_daemon_get_timeout (daemon,
318                                 &timeout_ll))
319     {
320       if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX)
321         timeout_ms = INT_MAX;
322       else
323         timeout_ms = (int) timeout_ll;
324     }
325     else
326       timeout_ms = -1;
327   }
328   else
329     timeout_ms = 0;
330 
331   /* Reset. New value will be set when connections are processed. */
332   /* Note: Used mostly for uniformity here as same situation is
333    * signaled in epoll mode by non-empty eready DLL. */
334   daemon->data_already_pending = false;
335 
336   /* drain 'epoll' event queue; need to iterate as we get at most
337      MAX_EVENTS in one system call here; in practice this should
338      pretty much mean only one round, but better an extra loop here
339      than unfair behavior... */
340   num_events = MAX_EVENTS;
341   while (MAX_EVENTS == num_events)
342   {
343     /* update event masks */
344     num_events = epoll_wait (daemon->epoll_fd,
345                              events,
346                              MAX_EVENTS,
347                              timeout_ms);
348     if (-1 == num_events)
349     {
350       const int err = MHD_socket_get_error_ ();
351       if (MHD_SCKT_ERR_IS_EINTR_ (err))
352         return MHD_SC_OK;
353 #ifdef HAVE_MESSAGES
354       MHD_DLOG (daemon,
355                 MHD_SC_UNEXPECTED_EPOLL_WAIT_ERROR,
356                 _ ("Call to epoll_wait failed: %s\n"),
357                 MHD_socket_strerr_ (err));
358 #endif
359       return MHD_SC_UNEXPECTED_EPOLL_WAIT_ERROR;
360     }
361     for (i = 0; i < (unsigned int) num_events; i++)
362     {
363       /* First, check for the values of `ptr` that would indicate
364          that this event is not about a normal connection. */
365       if (NULL == events[i].data.ptr)
366         continue; /* shutdown signal! */
367 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
368       if (upgrade_marker == events[i].data.ptr)
369       {
370         /* activity on an upgraded connection, we process
371            those in a separate epoll() */
372         run_upgraded = true;
373         continue;
374       }
375 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
376       if (daemon->epoll_itc_marker == events[i].data.ptr)
377       {
378         /* It's OK to clear ITC here as all external
379            conditions will be processed later. */
380         MHD_itc_clear_ (daemon->itc);
381         continue;
382       }
383       if (daemon == events[i].data.ptr)
384       {
385         /* Check for error conditions on listen socket. */
386         /* FIXME: Initiate MHD_quiesce_daemon() to prevent busy waiting? */
387         if (0 == (events[i].events & (EPOLLERR | EPOLLHUP)))
388         {
389           unsigned int series_length = 0;
390           /* Run 'accept' until it fails or daemon at limit of connections.
391            * Do not accept more then 10 connections at once. The rest will
392            * be accepted on next turn (level trigger is used for listen
393            * socket). */
394           while ( (MHD_SC_OK ==
395                    MHD_accept_connection_ (daemon)) &&
396                   (series_length < 10) &&
397                   (daemon->connections < daemon->global_connection_limit) &&
398                   (! daemon->at_limit) )
399             series_length++;
400         }
401         continue;
402       }
403       /* this is an event relating to a 'normal' connection,
404          remember the event and if appropriate mark the
405          connection as 'eready'. */
406       pos = events[i].data.ptr;
407       /* normal processing: update read/write data */
408       if (0 != (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP)))
409       {
410         pos->epoll_state |= MHD_EPOLL_STATE_ERROR;
411         if (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL))
412         {
413           EDLL_insert (daemon->eready_head,
414                        daemon->eready_tail,
415                        pos);
416           pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
417         }
418       }
419       else
420       {
421         if (0 != (events[i].events & EPOLLIN))
422         {
423           pos->epoll_state |= MHD_EPOLL_STATE_READ_READY;
424           if ( ( (MHD_EVENT_LOOP_INFO_READ == pos->request.event_loop_info) ||
425                  (pos->request.read_buffer_size >
426                   pos->request.read_buffer_offset) ) &&
427                (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
428           {
429             EDLL_insert (daemon->eready_head,
430                          daemon->eready_tail,
431                          pos);
432             pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
433           }
434         }
435         if (0 != (events[i].events & EPOLLOUT))
436         {
437           pos->epoll_state |= MHD_EPOLL_STATE_WRITE_READY;
438           if ( (MHD_EVENT_LOOP_INFO_WRITE == pos->request.event_loop_info) &&
439                (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
440           {
441             EDLL_insert (daemon->eready_head,
442                          daemon->eready_tail,
443                          pos);
444             pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
445           }
446         }
447       }
448     }
449   }
450 
451 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
452   if (run_upgraded)
453     run_epoll_for_upgrade (daemon); /* FIXME: return value? */
454 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
455 
456   /* process events for connections */
457   prev = daemon->eready_tail;
458   while (NULL != (pos = prev))
459   {
460     prev = pos->prevE;
461     MHD_connection_call_handlers_ (pos,
462                                    0 != (pos->epoll_state
463                                          & MHD_EPOLL_STATE_READ_READY),
464                                    0 != (pos->epoll_state
465                                          & MHD_EPOLL_STATE_WRITE_READY),
466                                    0 != (pos->epoll_state
467                                          & MHD_EPOLL_STATE_ERROR));
468     if (MHD_EPOLL_STATE_IN_EREADY_EDLL ==
469         (pos->epoll_state & (MHD_EPOLL_STATE_SUSPENDED
470                              | MHD_EPOLL_STATE_IN_EREADY_EDLL)))
471     {
472       if ( ((MHD_EVENT_LOOP_INFO_READ == pos->request.event_loop_info) &&
473             (0 == (pos->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ||
474            ((MHD_EVENT_LOOP_INFO_WRITE == pos->request.event_loop_info) &&
475             (0 == (pos->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) ) ||
476            (MHD_EVENT_LOOP_INFO_CLEANUP == pos->request.event_loop_info) )
477       {
478         EDLL_remove (daemon->eready_head,
479                      daemon->eready_tail,
480                      pos);
481         pos->epoll_state &= ~MHD_EPOLL_STATE_IN_EREADY_EDLL;
482       }
483     }
484   }
485 
486   /* Finally, handle timed-out connections; we need to do this here
487      as the epoll mechanism won't call the 'MHD_request_handle_idle_()' on everything,
488      as the other event loops do.  As timeouts do not get an explicit
489      event, we need to find those connections that might have timed out
490      here.
491 
492      Connections with custom timeouts must all be looked at, as we
493      do not bother to sort that (presumably very short) list. */prev = daemon->manual_timeout_tail;
494   while (NULL != (pos = prev))
495   {
496     prev = pos->prevX;
497     MHD_request_handle_idle_ (&pos->request);
498   }
499   /* Connections with the default timeout are sorted by prepending
500      them to the head of the list whenever we touch the connection;
501      thus it suffices to iterate from the tail until the first
502      connection is NOT timed out */
503   prev = daemon->normal_timeout_tail;
504   while (NULL != (pos = prev))
505   {
506     prev = pos->prevX;
507     MHD_request_handle_idle_ (&pos->request);
508     if (MHD_REQUEST_CLOSED != pos->request.state)
509       break; /* sorted by timeout, no need to visit the rest! */
510   }
511   return MHD_SC_OK;
512 }
513 
514 
515 #endif
516 
517 /* end of daemon_epoll.c */
518