aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/daemon.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-06-21 13:00:30 +0000
committerChristian Grothoff <christian@grothoff.org>2011-06-21 13:00:30 +0000
commit901090b07ba9c89e086072b14768a24241f6714c (patch)
tree9a7c95de963fc3a472ced2e3c668398676af4c90 /src/daemon/daemon.c
parent94bb1bb839e1dbb9e84f0b3a31cc8689df9a9d54 (diff)
downloadlibmicrohttpd-901090b07ba9c89e086072b14768a24241f6714c.tar.gz
libmicrohttpd-901090b07ba9c89e086072b14768a24241f6714c.zip
fixing race condition, minor leak, O(n) shutdown is now O(1)
Diffstat (limited to 'src/daemon/daemon.c')
-rw-r--r--src/daemon/daemon.c289
1 files changed, 171 insertions, 118 deletions
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 6c6144be..0fa51260 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -150,7 +150,7 @@ struct MHD_IPCount
150}; 150};
151 151
152/** 152/**
153 * Lock shared structure for IP connection counts 153 * Lock shared structure for IP connection counts and connection DLLs.
154 * 154 *
155 * @param daemon handle to daemon where lock is 155 * @param daemon handle to daemon where lock is
156 */ 156 */
@@ -167,7 +167,7 @@ MHD_ip_count_lock(struct MHD_Daemon *daemon)
167} 167}
168 168
169/** 169/**
170 * Unlock shared structure for IP connection counts 170 * Unlock shared structure for IP connection counts and connection DLLs.
171 * 171 *
172 * @param daemon handle to daemon where lock is 172 * @param daemon handle to daemon where lock is
173 */ 173 */
@@ -495,6 +495,7 @@ MHD_TLS_init (struct MHD_Daemon *daemon)
495} 495}
496#endif 496#endif
497 497
498
498/** 499/**
499 * Obtain the select sets for this daemon. 500 * Obtain the select sets for this daemon.
500 * 501 *
@@ -513,7 +514,8 @@ MHD_get_fdset (struct MHD_Daemon *daemon,
513 fd_set * read_fd_set, 514 fd_set * read_fd_set,
514 fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd) 515 fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd)
515{ 516{
516 struct MHD_Connection *con_itr; 517 struct MHD_Connection *pos;
518 struct MHD_Connection *next;
517 int fd; 519 int fd;
518 520
519 if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL) 521 if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL)
@@ -528,15 +530,15 @@ MHD_get_fdset (struct MHD_Daemon *daemon,
528 if ((*max_fd) < fd) 530 if ((*max_fd) < fd)
529 *max_fd = fd; 531 *max_fd = fd;
530 532
531 con_itr = daemon->connections; 533 next = daemon->connections_head;
532 while (con_itr != NULL) 534 while (NULL != (pos = next))
533 { 535 {
534 if (MHD_YES != MHD_connection_get_fdset (con_itr, 536 next = pos->next;
537 if (MHD_YES != MHD_connection_get_fdset (pos,
535 read_fd_set, 538 read_fd_set,
536 write_fd_set, 539 write_fd_set,
537 except_fd_set, max_fd)) 540 except_fd_set, max_fd))
538 return MHD_NO; 541 return MHD_NO;
539 con_itr = con_itr->next;
540 } 542 }
541#if DEBUG_CONNECT 543#if DEBUG_CONNECT
542 MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd); 544 MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
@@ -572,7 +574,8 @@ MHD_handle_connection (void *data)
572#endif 574#endif
573 575
574 timeout = con->daemon->connection_timeout; 576 timeout = con->daemon->connection_timeout;
575 while ((!con->daemon->shutdown) && (con->socket_fd != -1)) { 577 while ( (!con->daemon->shutdown) && (con->state != MHD_CONNECTION_CLOSED) )
578 {
576 tvp = NULL; 579 tvp = NULL;
577 if (timeout > 0) 580 if (timeout > 0)
578 { 581 {
@@ -624,17 +627,19 @@ MHD_handle_connection (void *data)
624 break; 627 break;
625 } 628 }
626 /* call appropriate connection handler if necessary */ 629 /* call appropriate connection handler if necessary */
627 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs))) 630 if (FD_ISSET (con->socket_fd, &rs))
628 con->read_handler (con); 631 con->read_handler (con);
629 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws))) 632 if (FD_ISSET (con->socket_fd, &ws))
630 con->write_handler (con); 633 con->write_handler (con);
631 if (con->socket_fd != -1) 634 if (MHD_NO == con->idle_handler (con))
632 con->idle_handler (con); 635 {
636 return NULL;
637 }
633 } 638 }
634#ifdef HAVE_POLL_H 639#ifdef HAVE_POLL_H
635 else 640 else
636 { 641 {
637 /* use poll */ 642 /* use poll */
638 memset(&mp, 0, sizeof (struct MHD_Pollfd)); 643 memset(&mp, 0, sizeof (struct MHD_Pollfd));
639 MHD_connection_get_pollfd(con, &mp); 644 MHD_connection_get_pollfd(con, &mp);
640 memset(&p, 0, sizeof (p)); 645 memset(&p, 0, sizeof (p));
@@ -666,21 +671,20 @@ MHD_handle_connection (void *data)
666#endif 671#endif
667 break; 672 break;
668 } 673 }
669 if ( (con->socket_fd != -1) && 674 if (0 != (p[0].revents & POLLIN))
670 (0 != (p[0].revents & POLLIN)) )
671 con->read_handler (con); 675 con->read_handler (con);
672 if ( (con->socket_fd != -1) && 676 if (0 != (p[0].revents & POLLOUT))
673 (0 != (p[0].revents & POLLOUT)) )
674 con->write_handler (con); 677 con->write_handler (con);
675 if (con->socket_fd != -1) 678 if (0 != (p[0].revents & (POLLERR | POLLHUP)))
676 con->idle_handler (con);
677 if ( (con->socket_fd != -1) &&
678 (0 != (p[0].revents & (POLLERR | POLLHUP))) )
679 MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR); 679 MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR);
680 if (MHD_NO == con->idle_handler (con))
681 {
682 return NULL; /* "instant" termination, 'con' no longer valid! */
683 }
680 } 684 }
681#endif 685#endif
682 } 686 }
683 if (con->socket_fd != -1) 687 if (con->state != MHD_CONNECTION_IN_CLEANUP)
684 { 688 {
685#if DEBUG_CLOSE 689#if DEBUG_CLOSE
686#if HAVE_MESSAGES 690#if HAVE_MESSAGES
@@ -688,7 +692,9 @@ MHD_handle_connection (void *data)
688 "Processing thread terminating, closing connection\n"); 692 "Processing thread terminating, closing connection\n");
689#endif 693#endif
690#endif 694#endif
691 MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); 695 if (con->state != MHD_CONNECTION_CLOSED)
696 MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
697 con->idle_handler (con);
692 } 698 }
693 return NULL; 699 return NULL;
694} 700}
@@ -706,8 +712,12 @@ recv_param_adapter (struct MHD_Connection *connection,
706 void *other, 712 void *other,
707 size_t i) 713 size_t i)
708{ 714{
709 if (connection->socket_fd == -1) 715 if ( (connection->socket_fd == -1) ||
710 return -1; 716 (connection->state == MHD_CONNECTION_CLOSED) )
717 {
718 errno = ENOTCONN;
719 return -1;
720 }
711 if (0 != (connection->daemon->options & MHD_USE_SSL)) 721 if (0 != (connection->daemon->options & MHD_USE_SSL))
712 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); 722 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
713 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); 723 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
@@ -732,8 +742,12 @@ send_param_adapter (struct MHD_Connection *connection,
732 off_t left; 742 off_t left;
733 ssize_t ret; 743 ssize_t ret;
734#endif 744#endif
735 if (connection->socket_fd == -1) 745 if ( (connection->socket_fd == -1) ||
736 return -1; 746 (connection->state == MHD_CONNECTION_CLOSED) )
747 {
748 errno = ENOTCONN;
749 return -1;
750 }
737 if (0 != (connection->daemon->options & MHD_USE_SSL)) 751 if (0 != (connection->daemon->options & MHD_USE_SSL))
738 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); 752 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
739#if LINUX 753#if LINUX
@@ -997,19 +1011,19 @@ MHD_add_connection (struct MHD_Daemon *daemon,
997 /* use non-blocking IO for gnutls */ 1011 /* use non-blocking IO for gnutls */
998 socket_set_nonblocking (connection->socket_fd); 1012 socket_set_nonblocking (connection->socket_fd);
999 } 1013 }
1000 switch (connection->daemon->cred_type) 1014 switch (daemon->cred_type)
1001 { 1015 {
1002 /* set needed credentials for certificate authentication. */ 1016 /* set needed credentials for certificate authentication. */
1003 case GNUTLS_CRD_CERTIFICATE: 1017 case GNUTLS_CRD_CERTIFICATE:
1004 gnutls_credentials_set (connection->tls_session, 1018 gnutls_credentials_set (connection->tls_session,
1005 GNUTLS_CRD_CERTIFICATE, 1019 GNUTLS_CRD_CERTIFICATE,
1006 connection->daemon->x509_cred); 1020 daemon->x509_cred);
1007 break; 1021 break;
1008 default: 1022 default:
1009#if HAVE_MESSAGES 1023#if HAVE_MESSAGES
1010 MHD_DLOG (connection->daemon, 1024 MHD_DLOG (connection->daemon,
1011 "Failed to setup TLS credentials: unknown credential type %d\n", 1025 "Failed to setup TLS credentials: unknown credential type %d\n",
1012 connection->daemon->cred_type); 1026 daemon->cred_type);
1013#endif 1027#endif
1014 SHUTDOWN (client_socket, SHUT_RDWR); 1028 SHUTDOWN (client_socket, SHUT_RDWR);
1015 CLOSE (client_socket); 1029 CLOSE (client_socket);
@@ -1059,8 +1073,10 @@ MHD_add_connection (struct MHD_Daemon *daemon,
1059 return MHD_NO; 1073 return MHD_NO;
1060 } 1074 }
1061 } 1075 }
1062 connection->next = daemon->connections; 1076 /* FIXME: race with removal operation! */
1063 daemon->connections = connection; 1077 DLL_insert (daemon->connections_head,
1078 daemon->connections_tail,
1079 connection);
1064 daemon->max_connections--; 1080 daemon->max_connections--;
1065 return MHD_YES; 1081 return MHD_YES;
1066} 1082}
@@ -1113,10 +1129,11 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
1113 addr, addrlen); 1129 addr, addrlen);
1114} 1130}
1115 1131
1132
1116/** 1133/**
1117 * Free resources associated with all closed connections. 1134 * Free resources associated with all closed connections.
1118 * (destroy responses, free buffers, etc.). A connection 1135 * (destroy responses, free buffers, etc.). All closed
1119 * is known to be closed if the socket_fd is -1. 1136 * connections are kept in the "cleanup" doubly-linked list.
1120 * 1137 *
1121 * @param daemon daemon to clean up 1138 * @param daemon daemon to clean up
1122 */ 1139 */
@@ -1124,59 +1141,61 @@ static void
1124MHD_cleanup_connections (struct MHD_Daemon *daemon) 1141MHD_cleanup_connections (struct MHD_Daemon *daemon)
1125{ 1142{
1126 struct MHD_Connection *pos; 1143 struct MHD_Connection *pos;
1127 struct MHD_Connection *prev;
1128 void *unused; 1144 void *unused;
1129 int rc; 1145 int rc;
1130 1146
1131 pos = daemon->connections; 1147 if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
1132 prev = NULL;
1133 while (pos != NULL)
1134 { 1148 {
1135 if ((pos->socket_fd == -1) ||
1136 (((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1137 (daemon->shutdown) && (pos->socket_fd != -1))))
1138 {
1139 if (prev == NULL)
1140 daemon->connections = pos->next;
1141 else
1142 prev->next = pos->next;
1143 if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1144 {
1145
1146 if (0 != (rc = pthread_join (pos->pid, &unused)))
1147 {
1148#if HAVE_MESSAGES 1149#if HAVE_MESSAGES
1149 MHD_DLOG (daemon, "Failed to join a thread: %s\n", 1150 MHD_DLOG (daemon, "Failed to acquire cleanup mutex\n");
1150 STRERROR (rc));
1151#endif
1152 abort();
1153 }
1154 }
1155 MHD_pool_destroy (pos->pool);
1156#if HTTPS_SUPPORT
1157 if (pos->tls_session != NULL)
1158 gnutls_deinit (pos->tls_session);
1159#endif 1151#endif
1160 MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); 1152 abort();
1161 if (pos->response != NULL) 1153 }
1154 while (NULL != (pos = daemon->cleanup_head))
1155 {
1156 DLL_remove (daemon->cleanup_head,
1157 daemon->cleanup_tail,
1158 pos);
1159 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
1160 (MHD_NO == pos->thread_joined) )
1161 {
1162 if (0 != (rc = pthread_join (pos->pid, &unused)))
1162 { 1163 {
1163 MHD_destroy_response (pos->response); 1164#if HAVE_MESSAGES
1164 pos->response = NULL; 1165 MHD_DLOG (daemon, "Failed to join a thread: %s\n",
1166 STRERROR (rc));
1167#endif
1168 abort();
1165 } 1169 }
1166 free (pos->addr); 1170 }
1167 free (pos); 1171 MHD_pool_destroy (pos->pool);
1168 daemon->max_connections++; 1172#if HTTPS_SUPPORT
1169 if (prev == NULL) 1173 if (pos->tls_session != NULL)
1170 pos = daemon->connections; 1174 gnutls_deinit (pos->tls_session);
1171 else 1175#endif
1172 pos = prev->next; 1176 MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
1173 continue; 1177 if (pos->response != NULL)
1174 } 1178 {
1175 prev = pos; 1179 MHD_destroy_response (pos->response);
1176 pos = pos->next; 1180 pos->response = NULL;
1181 }
1182 if (-1 != pos->socket_fd)
1183 CLOSE (pos->socket_fd);
1184 if (NULL != pos->addr)
1185 free (pos->addr);
1186 free (pos);
1187 daemon->max_connections++;
1188 }
1189 if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
1190 {
1191#if HAVE_MESSAGES
1192 MHD_DLOG (daemon, "Failed to release cleanup mutex\n");
1193#endif
1194 abort();
1177 } 1195 }
1178} 1196}
1179 1197
1198
1180/** 1199/**
1181 * Obtain timeout value for select for this daemon 1200 * Obtain timeout value for select for this daemon
1182 * (only needed if connection timeout is used). The 1201 * (only needed if connection timeout is used). The
@@ -1201,7 +1220,7 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
1201 dto = daemon->connection_timeout; 1220 dto = daemon->connection_timeout;
1202 if (0 == dto) 1221 if (0 == dto)
1203 return MHD_NO; 1222 return MHD_NO;
1204 pos = daemon->connections; 1223 pos = daemon->connections_head;
1205 if (pos == NULL) 1224 if (pos == NULL)
1206 return MHD_NO; /* no connections */ 1225 return MHD_NO; /* no connections */
1207 now = time (NULL); 1226 now = time (NULL);
@@ -1238,6 +1257,7 @@ MHD_select (struct MHD_Daemon *daemon,
1238 int may_block) 1257 int may_block)
1239{ 1258{
1240 struct MHD_Connection *pos; 1259 struct MHD_Connection *pos;
1260 struct MHD_Connection *next;
1241 int num_ready; 1261 int num_ready;
1242 fd_set rs; 1262 fd_set rs;
1243 fd_set ws; 1263 fd_set ws;
@@ -1313,21 +1333,19 @@ MHD_select (struct MHD_Daemon *daemon,
1313 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 1333 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1314 { 1334 {
1315 /* do not have a thread per connection, process all connections now */ 1335 /* do not have a thread per connection, process all connections now */
1316 pos = daemon->connections; 1336 next = daemon->connections_head;
1317 while (pos != NULL) 1337 while (NULL != (pos = next))
1318 { 1338 {
1339 next = pos->next;
1319 ds = pos->socket_fd; 1340 ds = pos->socket_fd;
1320 if (ds != -1) 1341 if (ds != -1)
1321 { 1342 {
1322 /* TODO call con->read handler */
1323 if (FD_ISSET (ds, &rs)) 1343 if (FD_ISSET (ds, &rs))
1324 pos->read_handler (pos); 1344 pos->read_handler (pos);
1325 if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws))) 1345 if (FD_ISSET (ds, &ws))
1326 pos->write_handler (pos); 1346 pos->write_handler (pos);
1327 if (pos->socket_fd != -1) 1347 pos->idle_handler (pos);
1328 pos->idle_handler (pos);
1329 } 1348 }
1330 pos = pos->next;
1331 } 1349 }
1332 } 1350 }
1333 return MHD_YES; 1351 return MHD_YES;
@@ -1349,9 +1367,10 @@ MHD_poll_all (struct MHD_Daemon *daemon,
1349{ 1367{
1350 unsigned int num_connections; 1368 unsigned int num_connections;
1351 struct MHD_Connection *pos; 1369 struct MHD_Connection *pos;
1370 struct MHD_Connection *next;
1352 1371
1353 num_connections = 0; 1372 num_connections = 0;
1354 pos = daemon->connections; 1373 pos = daemon->connections_head;
1355 while (pos != NULL) 1374 while (pos != NULL)
1356 { 1375 {
1357 num_connections++; 1376 num_connections++;
@@ -1385,7 +1404,7 @@ MHD_poll_all (struct MHD_Daemon *daemon,
1385 timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout; 1404 timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout;
1386 1405
1387 i = 0; 1406 i = 0;
1388 pos = daemon->connections; 1407 pos = daemon->connections_head;
1389 while (pos != NULL) 1408 while (pos != NULL)
1390 { 1409 {
1391 memset(&mp, 0, sizeof (struct MHD_Pollfd)); 1410 memset(&mp, 0, sizeof (struct MHD_Pollfd));
@@ -1413,9 +1432,10 @@ MHD_poll_all (struct MHD_Daemon *daemon,
1413 if (daemon->socket_fd < 0) 1432 if (daemon->socket_fd < 0)
1414 return MHD_YES; 1433 return MHD_YES;
1415 i = 0; 1434 i = 0;
1416 pos = daemon->connections; 1435 next = daemon->connections_head;
1417 while (pos != NULL) 1436 while (NULL != (pos = next))
1418 { 1437 {
1438 next = pos->next;
1419 /* first, sanity checks */ 1439 /* first, sanity checks */
1420 if (i >= num_connections) 1440 if (i >= num_connections)
1421 break; /* connection list changed somehow, retry later ... */ 1441 break; /* connection list changed somehow, retry later ... */
@@ -1427,11 +1447,9 @@ MHD_poll_all (struct MHD_Daemon *daemon,
1427 if (0 != (p[poll_server+i].revents & POLLIN)) 1447 if (0 != (p[poll_server+i].revents & POLLIN))
1428 pos->read_handler (pos); 1448 pos->read_handler (pos);
1429 if (0 != (p[poll_server+i].revents & POLLOUT)) 1449 if (0 != (p[poll_server+i].revents & POLLOUT))
1430 pos->write_handler (pos); 1450 pos->write_handler (pos);
1431 if (pos->socket_fd != -1) 1451 pos->idle_handler (pos);
1432 pos->idle_handler (pos);
1433 i++; 1452 i++;
1434 pos = pos->next;
1435 } 1453 }
1436 if ( (1 == poll_server) && 1454 if ( (1 == poll_server) &&
1437 (0 != (p[0].revents & POLLIN)) ) 1455 (0 != (p[0].revents & POLLIN)) )
@@ -1729,18 +1747,22 @@ parse_options_va (struct MHD_Daemon *daemon,
1729 daemon->cred_type = va_arg (ap, gnutls_credentials_type_t); 1747 daemon->cred_type = va_arg (ap, gnutls_credentials_type_t);
1730 break; 1748 break;
1731 case MHD_OPTION_HTTPS_PRIORITIES: 1749 case MHD_OPTION_HTTPS_PRIORITIES:
1732 ret = gnutls_priority_init (&daemon->priority_cache, 1750 if (daemon->options & MHD_USE_SSL)
1733 pstr = va_arg (ap, const char*), 1751 {
1734 NULL); 1752 gnutls_priority_deinit (daemon->priority_cache);
1753 ret = gnutls_priority_init (&daemon->priority_cache,
1754 pstr = va_arg (ap, const char*),
1755 NULL);
1735#if HAVE_MESSAGES 1756#if HAVE_MESSAGES
1736 if (ret != GNUTLS_E_SUCCESS) 1757 if (ret != GNUTLS_E_SUCCESS)
1737 FPRINTF (stderr, 1758 FPRINTF (stderr,
1738 "Setting priorities to `%s' failed: %s\n", 1759 "Setting priorities to `%s' failed: %s\n",
1739 pstr, 1760 pstr,
1740 gnutls_strerror (ret)); 1761 gnutls_strerror (ret));
1741#endif 1762#endif
1742 if (ret != GNUTLS_E_SUCCESS) 1763 if (ret != GNUTLS_E_SUCCESS)
1743 return MHD_NO; 1764 return MHD_NO;
1765 }
1744 break; 1766 break;
1745#endif 1767#endif
1746#ifdef DAUTH_SUPPORT 1768#ifdef DAUTH_SUPPORT
@@ -2174,6 +2196,16 @@ MHD_start_daemon_va (unsigned int options,
2174 CLOSE (socket_fd); 2196 CLOSE (socket_fd);
2175 goto free_and_fail; 2197 goto free_and_fail;
2176 } 2198 }
2199 if (0 != pthread_mutex_init (&retVal->cleanup_connection_mutex, NULL))
2200 {
2201#if HAVE_MESSAGES
2202 MHD_DLOG (retVal,
2203 "MHD failed to initialize IP connection limit mutex\n");
2204#endif
2205 pthread_mutex_destroy (&retVal->cleanup_connection_mutex);
2206 CLOSE (socket_fd);
2207 goto free_and_fail;
2208 }
2177 2209
2178#if HTTPS_SUPPORT 2210#if HTTPS_SUPPORT
2179 /* initialize HTTPS daemon certificate aspects & send / recv functions */ 2211 /* initialize HTTPS daemon certificate aspects & send / recv functions */
@@ -2184,6 +2216,7 @@ MHD_start_daemon_va (unsigned int options,
2184 "Failed to initialize TLS support\n"); 2216 "Failed to initialize TLS support\n");
2185#endif 2217#endif
2186 CLOSE (socket_fd); 2218 CLOSE (socket_fd);
2219 pthread_mutex_destroy (&retVal->cleanup_connection_mutex);
2187 pthread_mutex_destroy (&retVal->per_ip_connection_mutex); 2220 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
2188 goto free_and_fail; 2221 goto free_and_fail;
2189 } 2222 }
@@ -2199,6 +2232,7 @@ MHD_start_daemon_va (unsigned int options,
2199 "Failed to create listen thread: %s\n", 2232 "Failed to create listen thread: %s\n",
2200 STRERROR (res_thread_create)); 2233 STRERROR (res_thread_create));
2201#endif 2234#endif
2235 pthread_mutex_destroy (&retVal->cleanup_connection_mutex);
2202 pthread_mutex_destroy (&retVal->per_ip_connection_mutex); 2236 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
2203 CLOSE (socket_fd); 2237 CLOSE (socket_fd);
2204 goto free_and_fail; 2238 goto free_and_fail;
@@ -2292,6 +2326,7 @@ thread_failed:
2292 if (i == 0) 2326 if (i == 0)
2293 { 2327 {
2294 CLOSE (socket_fd); 2328 CLOSE (socket_fd);
2329 pthread_mutex_destroy (&retVal->cleanup_connection_mutex);
2295 pthread_mutex_destroy (&retVal->per_ip_connection_mutex); 2330 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
2296 if (NULL != retVal->worker_pool) 2331 if (NULL != retVal->worker_pool)
2297 free (retVal->worker_pool); 2332 free (retVal->worker_pool);
@@ -2319,27 +2354,45 @@ thread_failed:
2319 2354
2320 2355
2321/** 2356/**
2322 * Close all connections for the daemon 2357 * Close all connections for the daemon; must only be called after
2358 * all of the threads have been joined and there is no more concurrent
2359 * activity on the connection lists.
2323 * 2360 *
2324 * @param daemon daemon to close down 2361 * @param daemon daemon to close down
2325 */ 2362 */
2326static void 2363static void
2327MHD_close_connections (struct MHD_Daemon *daemon) 2364close_all_connections (struct MHD_Daemon *daemon)
2328{ 2365{
2329 while (daemon->connections != NULL) 2366 struct MHD_Connection *pos;
2367 void *unused;
2368 int rc;
2369
2370 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
2330 { 2371 {
2331 if (-1 != daemon->connections->socket_fd) 2372 while (NULL != (pos = daemon->connections_head))
2332 { 2373 {
2333#if DEBUG_CLOSE 2374 if (0 != (rc = pthread_join (pos->pid, &unused)))
2375 {
2334#if HAVE_MESSAGES 2376#if HAVE_MESSAGES
2335 MHD_DLOG (daemon, "MHD shutdown, closing active connections\n"); 2377 MHD_DLOG (daemon, "Failed to join a thread: %s\n",
2378 STRERROR (rc));
2336#endif 2379#endif
2337#endif 2380 abort();
2338 MHD_connection_close (daemon->connections, 2381 }
2339 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); 2382 pos->thread_joined = MHD_YES;
2340 } 2383 }
2341 MHD_cleanup_connections (daemon);
2342 } 2384 }
2385 while (NULL != (pos = daemon->connections_head))
2386 {
2387 pos->state = MHD_CONNECTION_CLOSED;
2388 DLL_remove (daemon->connections_head,
2389 daemon->connections_tail,
2390 pos);
2391 DLL_insert (daemon->cleanup_head,
2392 daemon->cleanup_tail,
2393 pos);
2394 }
2395 MHD_cleanup_connections (daemon);
2343} 2396}
2344 2397
2345 2398
@@ -2387,7 +2440,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
2387#endif 2440#endif
2388 abort(); 2441 abort();
2389 } 2442 }
2390 MHD_close_connections (&daemon->worker_pool[i]); 2443 close_all_connections (&daemon->worker_pool[i]);
2391 } 2444 }
2392 free (daemon->worker_pool); 2445 free (daemon->worker_pool);
2393 2446
@@ -2404,7 +2457,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
2404 abort(); 2457 abort();
2405 } 2458 }
2406 } 2459 }
2407 MHD_close_connections (daemon); 2460 close_all_connections (daemon);
2408 CLOSE (fd); 2461 CLOSE (fd);
2409 2462
2410 /* TLS clean up */ 2463 /* TLS clean up */
@@ -2437,7 +2490,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
2437 pthread_mutex_destroy (&daemon->nnc_lock); 2490 pthread_mutex_destroy (&daemon->nnc_lock);
2438#endif 2491#endif
2439 pthread_mutex_destroy (&daemon->per_ip_connection_mutex); 2492 pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
2440 2493 pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
2441 free (daemon); 2494 free (daemon);
2442} 2495}
2443 2496