aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r--src/microhttpd/daemon.c250
1 files changed, 186 insertions, 64 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index ac0299b9..171ab2cb 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -1026,7 +1026,6 @@ internal_add_connection (struct MHD_Daemon *daemon,
1026#if OSX 1026#if OSX
1027 static int on = 1; 1027 static int on = 1;
1028#endif 1028#endif
1029
1030 if (NULL != daemon->worker_pool) 1029 if (NULL != daemon->worker_pool)
1031 { 1030 {
1032 /* have a pool, try to find a pool with capacity; we use the 1031 /* have a pool, try to find a pool with capacity; we use the
@@ -1069,7 +1068,7 @@ internal_add_connection (struct MHD_Daemon *daemon,
1069 1068
1070#if HAVE_MESSAGES 1069#if HAVE_MESSAGES
1071#if DEBUG_CONNECT 1070#if DEBUG_CONNECT
1072 MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); 1071 MHD_DLOG (daemon, "Accepted connection on socket %d\n", client_socket);
1073#endif 1072#endif
1074#endif 1073#endif
1075 if ( (0 == daemon->max_connections) || 1074 if ( (0 == daemon->max_connections) ||
@@ -1396,14 +1395,17 @@ MHD_suspend_connection (struct MHD_Connection *connection)
1396 struct MHD_Daemon *daemon; 1395 struct MHD_Daemon *daemon;
1397 1396
1398 daemon = connection->daemon; 1397 daemon = connection->daemon;
1399 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 1398 if (0 == (daemon->options & MHD_USE_SUSPEND_RESUME))
1400 MHD_PANIC ("Cannot suspend connections in THREAD_PER_CONNECTION mode!\n"); 1399 MHD_PANIC ("Cannot suspend connections without enabling MHD_USE_SUSPEND_RESUME!\n");
1401 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 1400 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1402 (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) 1401 (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
1403 MHD_PANIC ("Failed to acquire cleanup mutex\n"); 1402 MHD_PANIC ("Failed to acquire cleanup mutex\n");
1404 DLL_remove (daemon->connections_head, 1403 DLL_remove (daemon->connections_head,
1405 daemon->connections_tail, 1404 daemon->connections_tail,
1406 connection); 1405 connection);
1406 DLL_insert (daemon->suspended_connections_head,
1407 daemon->suspended_connections_tail,
1408 connection);
1407 if (connection->connection_timeout == daemon->connection_timeout) 1409 if (connection->connection_timeout == daemon->connection_timeout)
1408 XDLL_remove (daemon->normal_timeout_head, 1410 XDLL_remove (daemon->normal_timeout_head,
1409 daemon->normal_timeout_tail, 1411 daemon->normal_timeout_tail,
@@ -1414,25 +1416,26 @@ MHD_suspend_connection (struct MHD_Connection *connection)
1414 connection); 1416 connection);
1415#if EPOLL_SUPPORT 1417#if EPOLL_SUPPORT
1416 if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) 1418 if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY))
1417 { 1419 {
1418 if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) 1420 if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL))
1419 { 1421 {
1420 EDLL_remove (daemon->eready_head, 1422 EDLL_remove (daemon->eready_head,
1421 daemon->eready_tail, 1423 daemon->eready_tail,
1422 connection); 1424 connection);
1423 } 1425 }
1424 if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) 1426 if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET))
1425 { 1427 {
1426 if (0 != epoll_ctl (daemon->epoll_fd, 1428 if (0 != epoll_ctl (daemon->epoll_fd,
1427 EPOLL_CTL_DEL, 1429 EPOLL_CTL_DEL,
1428 connection->socket_fd, 1430 connection->socket_fd,
1429 NULL)) 1431 NULL))
1430 MHD_PANIC ("Failed to remove FD from epoll set\n"); 1432 MHD_PANIC ("Failed to remove FD from epoll set\n");
1431 connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET; 1433 connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET;
1432 } 1434 }
1433 connection->epoll_state |= MHD_EPOLL_STATE_SUSPENDED; 1435 connection->epoll_state |= MHD_EPOLL_STATE_SUSPENDED;
1434 } 1436 }
1435#endif 1437#endif
1438 connection->suspended = MHD_YES;
1436 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 1439 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1437 (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) 1440 (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )
1438 MHD_PANIC ("Failed to release cleanup mutex\n"); 1441 MHD_PANIC ("Failed to release cleanup mutex\n");
@@ -1453,50 +1456,15 @@ MHD_resume_connection (struct MHD_Connection *connection)
1453 struct MHD_Daemon *daemon; 1456 struct MHD_Daemon *daemon;
1454 1457
1455 daemon = connection->daemon; 1458 daemon = connection->daemon;
1456 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 1459 if (0 == (daemon->options & MHD_USE_SUSPEND_RESUME))
1457 MHD_PANIC ("Cannot resume connections in THREAD_PER_CONNECTION mode!\n"); 1460 MHD_PANIC ("Cannot resume connections without enabling MHD_USE_SUSPEND_RESUME!\n");
1458 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 1461 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1459 (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) 1462 (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
1460 MHD_PANIC ("Failed to acquire cleanup mutex\n"); 1463 MHD_PANIC ("Failed to acquire cleanup mutex\n");
1461 DLL_insert (daemon->connections_head, 1464 connection->resuming = MHD_YES;
1462 daemon->connections_tail, 1465 daemon->resuming = MHD_YES;
1463 connection);
1464 if (connection->connection_timeout == daemon->connection_timeout)
1465 XDLL_insert (daemon->normal_timeout_head,
1466 daemon->normal_timeout_tail,
1467 connection);
1468 else
1469 XDLL_insert (daemon->manual_timeout_head,
1470 daemon->manual_timeout_tail,
1471 connection);
1472#if EPOLL_SUPPORT
1473 if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY))
1474 {
1475 if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL))
1476 {
1477 EDLL_insert (daemon->eready_head,
1478 daemon->eready_tail,
1479 connection);
1480 }
1481 else
1482 {
1483 struct epoll_event event;
1484
1485 event.events = EPOLLIN | EPOLLOUT | EPOLLET;
1486 event.data.ptr = connection;
1487 if (0 != epoll_ctl (daemon->epoll_fd,
1488 EPOLL_CTL_ADD,
1489 connection->socket_fd,
1490 &event))
1491 MHD_PANIC ("Failed to add FD to epoll set\n");
1492 else
1493 connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
1494 }
1495 connection->epoll_state &= ~MHD_EPOLL_STATE_SUSPENDED;
1496 }
1497#endif
1498 if ( (-1 != daemon->wpipe[1]) && 1466 if ( (-1 != daemon->wpipe[1]) &&
1499 (1 != WRITE (daemon->wpipe[1], "n", 1)) ) 1467 (1 != WRITE (daemon->wpipe[1], "r", 1)) )
1500 { 1468 {
1501#if HAVE_MESSAGES 1469#if HAVE_MESSAGES
1502 MHD_DLOG (daemon, 1470 MHD_DLOG (daemon,
@@ -1508,6 +1476,80 @@ MHD_resume_connection (struct MHD_Connection *connection)
1508 MHD_PANIC ("Failed to release cleanup mutex\n"); 1476 MHD_PANIC ("Failed to release cleanup mutex\n");
1509} 1477}
1510 1478
1479/**
1480 * Run through the suspended connections and move any that are no
1481 * longer suspended back to the active state.
1482 *
1483 * @param daemon daemon context
1484 */
1485static void
1486resume_suspended_connections (struct MHD_Daemon *daemon)
1487{
1488 struct MHD_Connection *pos;
1489 struct MHD_Connection *next = NULL;
1490
1491 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1492 (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
1493 MHD_PANIC ("Failed to acquire cleanup mutex\n");
1494
1495 if (MHD_YES == daemon->resuming)
1496 next = daemon->suspended_connections_head;
1497
1498 while (NULL != (pos = next))
1499 {
1500 next = pos->next;
1501 if (MHD_NO == pos->resuming)
1502 continue;
1503
1504 DLL_remove (daemon->suspended_connections_head,
1505 daemon->suspended_connections_tail,
1506 pos);
1507 DLL_insert (daemon->connections_head,
1508 daemon->connections_tail,
1509 pos);
1510 if (pos->connection_timeout == daemon->connection_timeout)
1511 XDLL_insert (daemon->normal_timeout_head,
1512 daemon->normal_timeout_tail,
1513 pos);
1514 else
1515 XDLL_insert (daemon->manual_timeout_head,
1516 daemon->manual_timeout_tail,
1517 pos);
1518#if EPOLL_SUPPORT
1519 if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY))
1520 {
1521 if (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL))
1522 {
1523 EDLL_insert (daemon->eready_head,
1524 daemon->eready_tail,
1525 pos);
1526 }
1527 else
1528 {
1529 struct epoll_event event;
1530
1531 event.events = EPOLLIN | EPOLLOUT | EPOLLET;
1532 event.data.ptr = pos;
1533 if (0 != epoll_ctl (daemon->epoll_fd,
1534 EPOLL_CTL_ADD,
1535 pos->socket_fd,
1536 &event))
1537 MHD_PANIC ("Failed to add FD to epoll set\n");
1538 else
1539 pos->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
1540 }
1541 pos->epoll_state &= ~MHD_EPOLL_STATE_SUSPENDED;
1542 }
1543#endif
1544 pos->suspended = MHD_NO;
1545 pos->resuming = MHD_NO;
1546 }
1547 daemon->resuming = MHD_NO;
1548 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1549 (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )
1550 MHD_PANIC ("Failed to release cleanup mutex\n");
1551}
1552
1511 1553
1512/** 1554/**
1513 * Change socket options to be non-blocking, non-inheritable. 1555 * Change socket options to be non-blocking, non-inheritable.
@@ -1995,6 +2037,9 @@ MHD_select (struct MHD_Daemon *daemon,
1995 max = -1; 2037 max = -1;
1996 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 2038 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1997 { 2039 {
2040 if (0 != (daemon->options & MHD_USE_SUSPEND_RESUME))
2041 resume_suspended_connections (daemon);
2042
1998 /* single-threaded, go over everything */ 2043 /* single-threaded, go over everything */
1999 if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max)) 2044 if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
2000 return MHD_NO; 2045 return MHD_NO;
@@ -2072,6 +2117,9 @@ MHD_poll_all (struct MHD_Daemon *daemon,
2072 struct MHD_Connection *pos; 2117 struct MHD_Connection *pos;
2073 struct MHD_Connection *next; 2118 struct MHD_Connection *next;
2074 2119
2120 if (0 != (daemon->options & MHD_USE_SUSPEND_RESUME))
2121 resume_suspended_connections (daemon);
2122
2075 /* count number of connections and thus determine poll set size */ 2123 /* count number of connections and thus determine poll set size */
2076 num_connections = 0; 2124 num_connections = 0;
2077 for (pos = daemon->connections_head; NULL != pos; pos = pos->next) 2125 for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
@@ -2322,6 +2370,7 @@ MHD_epoll (struct MHD_Daemon *daemon,
2322 int num_events; 2370 int num_events;
2323 unsigned int i; 2371 unsigned int i;
2324 unsigned int series_length; 2372 unsigned int series_length;
2373 char tmp;
2325 2374
2326 if (-1 == daemon->epoll_fd) 2375 if (-1 == daemon->epoll_fd)
2327 return MHD_NO; /* we're down! */ 2376 return MHD_NO; /* we're down! */
@@ -2402,6 +2451,12 @@ MHD_epoll (struct MHD_Daemon *daemon,
2402 { 2451 {
2403 if (NULL == events[i].data.ptr) 2452 if (NULL == events[i].data.ptr)
2404 continue; /* shutdown signal! */ 2453 continue; /* shutdown signal! */
2454 if ( (-1 != daemon->wpipe[0]) &&
2455 (daemon->wpipe[0] == events[i].data.fd) )
2456 {
2457 (void) read (daemon->wpipe[0], &tmp, sizeof (tmp));
2458 continue;
2459 }
2405 if (daemon != events[i].data.ptr) 2460 if (daemon != events[i].data.ptr)
2406 { 2461 {
2407 /* this is an event relating to a 'normal' connection, 2462 /* this is an event relating to a 'normal' connection,
@@ -2447,6 +2502,11 @@ MHD_epoll (struct MHD_Daemon *daemon,
2447 } 2502 }
2448 } 2503 }
2449 2504
2505 /* we handle resumes here because we may have ready connections
2506 that will not be placed into the epoll list immediately. */
2507 if (0 != (daemon->options & MHD_USE_SUSPEND_RESUME))
2508 resume_suspended_connections (daemon);
2509
2450 /* process events for connections */ 2510 /* process events for connections */
2451 while (NULL != (pos = daemon->eready_tail)) 2511 while (NULL != (pos = daemon->eready_tail))
2452 { 2512 {
@@ -3054,6 +3114,26 @@ setup_epoll_to_listen (struct MHD_Daemon *daemon)
3054#endif 3114#endif
3055 return MHD_NO; 3115 return MHD_NO;
3056 } 3116 }
3117 if ( (-1 != daemon->wpipe[0]) &&
3118 (0 != (daemon->options & MHD_USE_SUSPEND_RESUME)) )
3119 {
3120 event.events = EPOLLIN | EPOLLET;
3121 event.data.ptr = NULL;
3122 event.data.fd = daemon->wpipe[0];
3123 if (0 != epoll_ctl (daemon->epoll_fd,
3124 EPOLL_CTL_ADD,
3125 daemon->wpipe[0],
3126 &event))
3127 {
3128#if HAVE_MESSAGES
3129 if (0 != (daemon->options & MHD_USE_DEBUG))
3130 MHD_DLOG (daemon,
3131 "Call to epoll_ctl failed: %s\n",
3132 STRERROR (errno));
3133#endif
3134 return MHD_NO;
3135 }
3136 }
3057 daemon->listen_socket_in_epoll = MHD_YES; 3137 daemon->listen_socket_in_epoll = MHD_YES;
3058 return MHD_YES; 3138 return MHD_YES;
3059} 3139}
@@ -3274,6 +3354,16 @@ MHD_start_daemon_va (unsigned int flags,
3274 goto free_and_fail; 3354 goto free_and_fail;
3275 } 3355 }
3276 3356
3357 if ( (0 != (flags & MHD_USE_SUSPEND_RESUME)) &&
3358 (0 != (flags & MHD_USE_THREAD_PER_CONNECTION)) )
3359 {
3360#if HAVE_MESSAGES
3361 MHD_DLOG (daemon,
3362 "Combining MHD_USE_THREAD_PER_CONNECTION and MHD_USE_SUSPEND_RESUME is not supported.");
3363#endif
3364 goto free_and_fail;
3365 }
3366
3277#ifdef __SYMBIAN32__ 3367#ifdef __SYMBIAN32__
3278 if (0 != (flags & (MHD_USE_SELECT_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION))) 3368 if (0 != (flags & (MHD_USE_SELECT_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION)))
3279 { 3369 {
@@ -3588,6 +3678,38 @@ MHD_start_daemon_va (unsigned int flags,
3588 d->worker_pool_size = 0; 3678 d->worker_pool_size = 0;
3589 d->worker_pool = NULL; 3679 d->worker_pool = NULL;
3590 3680
3681 if ( (0 != (flags & MHD_USE_SUSPEND_RESUME)) &&
3682#ifdef WINDOWS
3683 (0 != SOCKETPAIR (AF_INET, SOCK_STREAM, IPPROTO_TCP, d->wpipe))
3684#else
3685 (0 != PIPE (d->wpipe))
3686#endif
3687 )
3688 {
3689#if HAVE_MESSAGES
3690 MHD_DLOG (daemon,
3691 "Failed to create worker control pipe: %s\n",
3692 STRERROR (errno));
3693#endif
3694 goto thread_failed;
3695 }
3696#ifndef WINDOWS
3697 if ( (0 == (flags & MHD_USE_POLL)) &&
3698 (0 != (flags & MHD_USE_SUSPEND_RESUME)) &&
3699 (d->wpipe[0] >= FD_SETSIZE) )
3700 {
3701#if HAVE_MESSAGES
3702 MHD_DLOG (daemon,
3703 "file descriptor for worker control pipe exceeds maximum value\n");
3704#endif
3705 if (0 != CLOSE (d->wpipe[0]))
3706 MHD_PANIC ("close failed\n");
3707 if (0 != CLOSE (d->wpipe[1]))
3708 MHD_PANIC ("close failed\n");
3709 goto thread_failed;
3710 }
3711#endif
3712
3591 /* Divide available connections evenly amongst the threads. 3713 /* Divide available connections evenly amongst the threads.
3592 * Thread indexes in [0, leftover_conns) each get one of the 3714 * Thread indexes in [0, leftover_conns) each get one of the
3593 * leftover connections. */ 3715 * leftover connections. */
@@ -3842,9 +3964,9 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
3842 /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to check */ 3964 /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to check */
3843 for (i = 0; i < daemon->worker_pool_size; ++i) 3965 for (i = 0; i < daemon->worker_pool_size; ++i)
3844 { 3966 {
3845 if (-1 != daemon->wpipe[1]) 3967 if (-1 != daemon->worker_pool[i].wpipe[1])
3846 { 3968 {
3847 if (1 != WRITE (daemon->wpipe[1], "e", 1)) 3969 if (1 != WRITE (daemon->worker_pool[i].wpipe[1], "e", 1))
3848 MHD_PANIC ("failed to signal shutdown via pipe"); 3970 MHD_PANIC ("failed to signal shutdown via pipe");
3849 } 3971 }
3850 if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused))) 3972 if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused)))