aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/daemon.c')
-rw-r--r--src/daemon/daemon.c1194
1 files changed, 612 insertions, 582 deletions
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 971196f8..ef575dd6 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -1,22 +1,22 @@
1/* 1/*
2 This file is part of libmicrohttpd 2 This file is part of libmicrohttpd
3 (C) 2007 Daniel Pittman and Christian Grothoff 3 (C) 2007 Daniel Pittman and Christian Grothoff
4 4
5 This library is free software; you can redistribute it and/or 5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either 7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version. 8 version 2.1 of the License, or (at your option) any later version.
9 9
10 This library is distributed in the hope that it will be useful, 10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details. 13 Lesser General Public License for more details.
14 14
15 You should have received a copy of the GNU Lesser General Public 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 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 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 18
19*/ 19 */
20 20
21/** 21/**
22 * @file daemon.c 22 * @file daemon.c
@@ -52,7 +52,6 @@
52 */ 52 */
53#define DEBUG_CONNECT MHD_NO 53#define DEBUG_CONNECT MHD_NO
54 54
55
56/** 55/**
57 * Obtain the select sets for this daemon. 56 * Obtain the select sets for this daemon.
58 * 57 *
@@ -60,307 +59,331 @@
60 * daemon was not started with the right 59 * daemon was not started with the right
61 * options for this call. 60 * options for this call.
62 */ 61 */
63int 62int MHD_get_fdset(struct MHD_Daemon *daemon,
64MHD_get_fdset (struct MHD_Daemon *daemon, 63 fd_set * read_fd_set,
65 fd_set * read_fd_set, 64 fd_set * write_fd_set,
66 fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd) 65 fd_set * except_fd_set,
67{ 66 int *max_fd)
68 struct MHD_Connection *pos; 67 {
69 int fd; 68 struct MHD_Connection *con_itr;
70 69 int fd;
71 if ((daemon == NULL) || 70
72 (read_fd_set == NULL) || 71 if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL)
73 (write_fd_set == NULL) || 72 || (except_fd_set == NULL) || (max_fd == NULL) || (-1 == (fd = daemon->
74 (except_fd_set == NULL) || 73 socket_fd)) || (daemon->shutdown == MHD_YES) || ((daemon->options
75 (max_fd == NULL) || 74 & MHD_USE_THREAD_PER_CONNECTION) != 0))
76 (-1 == (fd = daemon->socket_fd)) || 75 return MHD_NO;
77 (daemon->shutdown == MHD_YES) || 76
78 ((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0)) 77 __FD_SET (fd, read_fd_set);
79 return MHD_NO; 78
80 FD_SET (fd, read_fd_set); 79 /* update max file descriptor */
81 if ((*max_fd) < fd) 80 if ((*max_fd) < fd)
82 *max_fd = fd; 81 *max_fd = fd;
83 pos = daemon->connections; 82
84 while (pos != NULL) 83 con_itr = daemon->connections;
85 { 84 while (con_itr != NULL)
86 if (MHD_YES != MHD_connection_get_fdset (pos, 85 {
87 read_fd_set, 86 if (MHD_YES != MHD_connection_get_fdset (con_itr,
88 write_fd_set, 87 read_fd_set,
89 except_fd_set, max_fd)) 88 write_fd_set,
90 return MHD_NO; 89 except_fd_set, max_fd))
91 pos = pos->next; 90 return MHD_NO;
92 } 91 con_itr = con_itr->next;
92 }
93#if DEBUG_CONNECT 93#if DEBUG_CONNECT
94 MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd); 94 MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
95#endif 95#endif
96 return MHD_YES; 96 return MHD_YES;
97} 97 }
98 98
99/** 99/**
100 * Main function of the thread that handles an individual 100 * Main function of the thread that handles an individual
101 * connection. 101 * connection.
102 */ 102 */
103static void * 103static void * MHD_handle_connection(void *data)
104MHD_handle_connection (void *data) 104 {
105{ 105 struct MHD_Connection *con = data;
106 struct MHD_Connection *con = data; 106 int num_ready;
107 int num_ready; 107 fd_set rs;
108 fd_set rs; 108 fd_set ws;
109 fd_set ws; 109 fd_set es;
110 fd_set es; 110 int max;
111 int max; 111 struct timeval tv;
112 struct timeval tv; 112 unsigned int timeout;
113 unsigned int timeout; 113 unsigned int now;
114 unsigned int now; 114
115 115 if (con == NULL)
116 if (con == NULL) 116 abort();
117 abort (); 117 timeout = con->daemon->connection_timeout;
118 timeout = con->daemon->connection_timeout; 118 while ((!con->daemon->shutdown) && (con->socket_fd != -1))
119 while ((!con->daemon->shutdown) && (con->socket_fd != -1)) 119 {
120 { 120 FD_ZERO (&rs);
121 FD_ZERO (&rs); 121 FD_ZERO (&ws);
122 FD_ZERO (&ws); 122 FD_ZERO (&es);
123 FD_ZERO (&es); 123 max = 0;
124 max = 0; 124 MHD_connection_get_fdset(con, &rs, &ws, &es, &max);
125 MHD_connection_get_fdset (con, &rs, &ws, &es, &max); 125 now = time(NULL);
126 now = time (NULL); 126 tv.tv_usec = 0;
127 tv.tv_usec = 0; 127 if (timeout > (now - con->last_activity))
128 if (timeout > (now - con->last_activity)) 128 tv.tv_sec = timeout - (now - con->last_activity);
129 tv.tv_sec = timeout - (now - con->last_activity); 129 else
130 else 130 tv.tv_sec = 0;
131 tv.tv_sec = 0; 131 num_ready = SELECT (max + 1,
132 num_ready = SELECT (max + 1, 132 &rs, &ws, &es, (timeout != 0) ? &tv : NULL);
133 &rs, &ws, &es, (timeout != 0) ? &tv : NULL); 133 if (num_ready < 0)
134 if (num_ready < 0) 134 {
135 { 135 if (errno == EINTR)
136 if (errno == EINTR) 136 continue;
137 continue;
138#if HAVE_MESSAGES 137#if HAVE_MESSAGES
139 MHD_DLOG (con->daemon, "Error during select (%d): `%s'\n", 138 MHD_DLOG(con->daemon, "Error during select (%d): `%s'\n", max,
140 max, STRERROR (errno)); 139 STRERROR (errno));
141#endif 140#endif
142 break; 141 break;
143 } 142 }
144 if (FD_ISSET (con->socket_fd, &rs)) 143 if (FD_ISSET (con->socket_fd, &rs))
145 MHD_connection_handle_read (con); 144 MHD_connection_handle_read(con);
146 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws))) 145 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws)))
147 MHD_connection_handle_write (con); 146 MHD_connection_handle_write(con);
148 if (con->socket_fd != -1) 147 if (con->socket_fd != -1)
149 MHD_connection_handle_idle (con); 148 MHD_connection_handle_idle(con);
150 } 149 }
151 if (con->socket_fd != -1) 150 if (con->socket_fd != -1)
152 { 151 {
153#if DEBUG_CLOSE 152#if DEBUG_CLOSE
154#if HAVE_MESSAGES 153#if HAVE_MESSAGES
155 MHD_DLOG (con->daemon, 154 MHD_DLOG (con->daemon,
156 "Processing thread terminating, closing connection\n"); 155 "Processing thread terminating, closing connection\n");
157#endif 156#endif
158#endif 157#endif
159 SHUTDOWN (con->socket_fd, SHUT_RDWR); 158 SHUTDOWN (con->socket_fd, SHUT_RDWR);
160 CLOSE (con->socket_fd); 159 CLOSE (con->socket_fd);
161 con->socket_fd = -1; 160 con->socket_fd = -1;
162 } 161 }
163 return NULL; 162 return NULL;
164} 163 }
164
165/**
166 * Handle an individual TLS connection.
167 */
168static void * MHDS_handle_connection(void *data)
169 {
170 struct MHD_Connection *con = data;
171
172 if (con == NULL)
173 abort();
174
175 /* forward call to handler */
176 con->daemon->default_handler(NULL, con, NULL, NULL, NULL, NULL, NULL,
177 NULL);
165 178
179 return NULL;
180 }
166 181
167/** 182/**
168 * Accept an incoming connection and create the MHD_Connection object for 183 * Accept an incoming connection and create the MHD_Connection object for
169 * it. This function also enforces policy by way of checking with the 184 * it. This function also enforces policy by way of checking with the
170 * accept policy callback. 185 * accept policy callback.
171 */ 186 */
172static int 187static int MHD_accept_connection(struct MHD_Daemon *daemon)
173MHD_accept_connection (struct MHD_Daemon *daemon) 188 {
174{ 189 struct MHD_Connection *pos;
175 struct MHD_Connection *pos; 190 struct MHD_Connection *connection;
176 struct MHD_Connection *connection; 191 struct sockaddr_in6 addr6;
177 struct sockaddr_in6 addr6; 192 struct sockaddr *addr = (struct sockaddr *) &addr6;
178 struct sockaddr *addr = (struct sockaddr *) &addr6; 193 socklen_t addrlen;
179 socklen_t addrlen; 194 unsigned int have;
180 unsigned int have; 195 int s, res_thread_create;
181 int s;
182#if OSX 196#if OSX
183 static int on = 1; 197 static int on = 1;
184#endif 198#endif
185 199
200 if (sizeof(struct sockaddr) > sizeof(struct sockaddr_in6))
201 abort(); /* fatal, serious error */
202 addrlen = sizeof(struct sockaddr_in6);
203 memset(addr, 0, sizeof(struct sockaddr_in6));
204
205 s = ACCEPT (daemon->socket_fd, addr, &addrlen);
186 206
187 if (sizeof (struct sockaddr) > sizeof (struct sockaddr_in6)) 207 if ((s < 0) || (addrlen <= 0))
188 abort (); /* fatal, serious error */ 208 {
189 addrlen = sizeof (struct sockaddr_in6);
190 memset (addr, 0, sizeof (struct sockaddr_in6));
191 s = ACCEPT (daemon->socket_fd, addr, &addrlen);
192 if ((s < 0) || (addrlen <= 0))
193 {
194#if HAVE_MESSAGES 209#if HAVE_MESSAGES
195 MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); 210 MHD_DLOG(daemon, "Error accepting connection: %s\n", STRERROR (errno));
196#endif 211#endif
197 if (s != -1) 212 if (s != -1)
198 { 213 {
199 SHUTDOWN (s, SHUT_RDWR); 214 SHUTDOWN (s, SHUT_RDWR);
200 CLOSE (s); /* just in case */ 215 CLOSE (s);
201 } 216 /* just in case */
202 return MHD_NO; 217 }
203 } 218 return MHD_NO;
219 }
204#if DEBUG_CONNECT 220#if DEBUG_CONNECT
205 MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); 221 MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
206#endif 222#endif
207 have = 0; 223 have = 0;
208 if ((daemon->per_ip_connection_limit != 0) && (daemon->max_connections > 0)) 224 if ((daemon->per_ip_connection_limit != 0) && (daemon->max_connections > 0))
209 { 225 {
210 pos = daemon->connections; 226 pos = daemon->connections;
211 while (pos != NULL) 227 while (pos != NULL)
212 { 228 {
213 if ((pos->addr != NULL) && (pos->addr_len == addrlen)) 229 if ((pos->addr != NULL) && (pos->addr_len == addrlen))
214 { 230 {
215 if (addrlen == sizeof (struct sockaddr_in)) 231 if (addrlen == sizeof(struct sockaddr_in))
216 { 232 {
217 const struct sockaddr_in *a1 = 233 const struct sockaddr_in *a1 =
218 (const struct sockaddr_in *) &addr; 234 (const struct sockaddr_in *) &addr;
219 const struct sockaddr_in *a2 = 235 const struct sockaddr_in *a2 =
220 (const struct sockaddr_in *) pos->addr; 236 (const struct sockaddr_in *) pos->addr;
221 if (0 == 237 if (0 == memcmp(&a1->sin_addr, &a2->sin_addr,
222 memcmp (&a1->sin_addr, &a2->sin_addr, 238 sizeof(struct in_addr)))
223 sizeof (struct in_addr))) 239 have++;
224 have++; 240 }
225 } 241 if (addrlen == sizeof(struct sockaddr_in6))
226 if (addrlen == sizeof (struct sockaddr_in6)) 242 {
227 { 243 const struct sockaddr_in6 *a1 =
228 const struct sockaddr_in6 *a1 = 244 (const struct sockaddr_in6 *) &addr;
229 (const struct sockaddr_in6 *) &addr; 245 const struct sockaddr_in6 *a2 =
230 const struct sockaddr_in6 *a2 = 246 (const struct sockaddr_in6 *) pos->addr;
231 (const struct sockaddr_in6 *) pos->addr; 247 if (0 == memcmp(&a1->sin6_addr, &a2->sin6_addr,
232 if (0 == 248 sizeof(struct in6_addr)))
233 memcmp (&a1->sin6_addr, &a2->sin6_addr, 249 have++;
234 sizeof (struct in6_addr))) 250 }
235 have++; 251 }
236 } 252 pos = pos->next;
237 } 253 }
238 pos = pos->next; 254 }
239 } 255
240 } 256 if ((daemon->max_connections == 0) || ((daemon->per_ip_connection_limit
241 257 != 0) && (daemon->
242 if ((daemon->max_connections == 0) || 258 per_ip_connection_limit <= have)))
243 ((daemon->per_ip_connection_limit != 0) && 259 {
244 (daemon->per_ip_connection_limit <= have))) 260 /* above connection limit - reject */
245 {
246 /* above connection limit - reject */
247#if HAVE_MESSAGES 261#if HAVE_MESSAGES
248 MHD_DLOG (daemon, 262 MHD_DLOG(daemon,
249 "Server reached connection limit (closing inbound connection)\n"); 263 "Server reached connection limit (closing inbound connection)\n");
250#endif 264#endif
251 SHUTDOWN (s, SHUT_RDWR); 265 SHUTDOWN (s, SHUT_RDWR);
252 CLOSE (s); 266 CLOSE (s);
253 return MHD_NO; 267 return MHD_NO;
254 } 268 }
255 if ((daemon->apc != NULL) && 269 if ((daemon->apc != NULL) && (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen)))
256 (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen))) 270 {
257 {
258#if DEBUG_CLOSE 271#if DEBUG_CLOSE
259#if HAVE_MESSAGES 272#if HAVE_MESSAGES
260 MHD_DLOG (daemon, "Connection rejected, closing connection\n"); 273 MHD_DLOG (daemon, "Connection rejected, closing connection\n");
261#endif 274#endif
262#endif 275#endif
263 SHUTDOWN (s, SHUT_RDWR); 276 SHUTDOWN (s, SHUT_RDWR);
264 CLOSE (s); 277 CLOSE (s);
265 return MHD_YES; 278 return MHD_YES;
266 } 279 }
267#if OSX 280#if OSX
268#ifdef SOL_SOCKET 281#ifdef SOL_SOCKET
269#ifdef SO_NOSIGPIPE 282#ifdef SO_NOSIGPIPE
270 setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on)); 283 setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on));
271#endif 284#endif
272#endif 285#endif
273#endif 286#endif
274 connection = malloc (sizeof (struct MHD_Connection)); 287 connection = malloc(sizeof(struct MHD_Connection));
275 if (connection == NULL) 288 if (connection == NULL)
276 { 289 {
277#if HAVE_MESSAGES 290#if HAVE_MESSAGES
278 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); 291 MHD_DLOG(daemon, "Error allocating memory: %s\n", STRERROR (errno));
279#endif 292#endif
280 SHUTDOWN (s, SHUT_RDWR); 293 SHUTDOWN (s, SHUT_RDWR);
281 CLOSE (s); 294 CLOSE (s);
282 return MHD_NO; 295 return MHD_NO;
283 } 296 }
284 memset (connection, 0, sizeof (struct MHD_Connection)); 297 memset(connection, 0, sizeof(struct MHD_Connection));
285 connection->pool = NULL; 298 connection->pool = NULL;
286 connection->addr = malloc (addrlen); 299 connection->addr = malloc(addrlen);
287 if (connection->addr == NULL) 300 if (connection->addr == NULL)
288 { 301 {
289#if HAVE_MESSAGES 302#if HAVE_MESSAGES
290 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); 303 MHD_DLOG(daemon, "Error allocating memory: %s\n", STRERROR (errno));
291#endif 304#endif
292 SHUTDOWN (s, SHUT_RDWR); 305 SHUTDOWN (s, SHUT_RDWR);
293 CLOSE (s); 306 CLOSE (s);
294 free (connection); 307 free(connection);
295 return MHD_NO; 308 return MHD_NO;
296 } 309 }
297 memcpy (connection->addr, addr, addrlen); 310 memcpy(connection->addr, addr, addrlen);
298 connection->addr_len = addrlen; 311 connection->addr_len = addrlen;
299 connection->socket_fd = s; 312 connection->socket_fd = s;
300 connection->daemon = daemon; 313 connection->daemon = daemon;
301 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 314
302 (0 != pthread_create (&connection->pid, 315 /* attempt to create handler thread */
303 NULL, &MHD_handle_connection, connection))) 316 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
304 { 317 {
318 if (daemon->options & MHD_USE_SSL)
319 res_thread_create= pthread_create(&connection->pid, NULL,
320 &MHDS_handle_connection, connection);
321 else
322 {
323 res_thread_create= pthread_create(&connection->pid, NULL,
324 &MHD_handle_connection, connection);
325 }
326 if (res_thread_create != 0)
327 {
305#if HAVE_MESSAGES 328#if HAVE_MESSAGES
306 MHD_DLOG (daemon, "Failed to create a thread: %s\n", STRERROR (errno)); 329 MHD_DLOG(daemon, "Failed to create a thread: %s\n", STRERROR (errno));
307#endif 330#endif
308 SHUTDOWN (s, SHUT_RDWR); 331 SHUTDOWN (s, SHUT_RDWR);
309 CLOSE (s); 332 CLOSE (s);
310 free (connection->addr); 333 free(connection->addr);
311 free (connection); 334 free(connection);
312 return MHD_NO; 335 return MHD_NO;
313 } 336 }
314 connection->last_activity = time (NULL); 337 }
315 connection->next = daemon->connections; 338
316 daemon->connections = connection; 339 connection->last_activity = time(NULL);
317 daemon->max_connections--; 340 connection->next = daemon->connections;
318 return MHD_YES; 341 daemon->connections = connection;
319} 342 daemon->max_connections--;
320 343 return MHD_YES;
344 }
321 345
322/** 346/**
323 * Free resources associated with all closed connections. 347 * Free resources associated with all closed connections.
324 * (destroy responses, free buffers, etc.). A connection 348 * (destroy responses, free buffers, etc.). A connection
325 * is known to be closed if the socket_fd is -1. 349 * is known to be closed if the socket_fd is -1.
326 */ 350 */
327static void 351static void MHD_cleanup_connections(struct MHD_Daemon *daemon)
328MHD_cleanup_connections (struct MHD_Daemon *daemon) 352 {
329{ 353 struct MHD_Connection *pos;
330 struct MHD_Connection *pos; 354 struct MHD_Connection *prev;
331 struct MHD_Connection *prev; 355 void *unused;
332 void *unused; 356
333 357 pos = daemon->connections;
334 pos = daemon->connections; 358 prev = NULL;
335 prev = NULL; 359 while (pos != NULL)
336 while (pos != NULL) 360 {
337 { 361 if (pos->socket_fd == -1)
338 if (pos->socket_fd == -1) 362 {
339 { 363 if (prev == NULL)
340 if (prev == NULL) 364 daemon->connections = pos->next;
341 daemon->connections = pos->next; 365 else
342 else 366 prev->next = pos->next;
343 prev->next = pos->next; 367 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
344 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 368 {
345 { 369 pthread_kill(pos->pid, SIGALRM);
346 pthread_kill (pos->pid, SIGALRM); 370 pthread_join(pos->pid, &unused);
347 pthread_join (pos->pid, &unused); 371 }
348 } 372 MHD_destroy_response(pos->response);
349 MHD_destroy_response (pos->response); 373 MHD_pool_destroy(pos->pool);
350 MHD_pool_destroy (pos->pool); 374 free(pos->addr);
351 free (pos->addr); 375 free(pos);
352 free (pos); 376 daemon->max_connections++;
353 daemon->max_connections++; 377 if (prev == NULL)
354 if (prev == NULL) 378 pos = daemon->connections;
355 pos = daemon->connections; 379 else
356 else 380 pos = prev->next;
357 pos = prev->next; 381 continue;
358 continue; 382 }
359 } 383 prev = pos;
360 prev = pos; 384 pos = pos->next;
361 pos = pos->next; 385 }
362 } 386 }
363}
364 387
365/** 388/**
366 * Obtain timeout value for select for this daemon 389 * Obtain timeout value for select for this daemon
@@ -373,35 +396,34 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
373 * not used (or no connections exist that would 396 * not used (or no connections exist that would
374 * necessiate the use of a timeout right now). 397 * necessiate the use of a timeout right now).
375 */ 398 */
376int 399int MHD_get_timeout(struct MHD_Daemon *daemon, unsigned long long *timeout)
377MHD_get_timeout (struct MHD_Daemon *daemon, unsigned long long *timeout) 400 {
378{ 401 time_t earliest_deadline;
379 time_t earliest_deadline; 402 time_t now;
380 time_t now; 403 struct MHD_Connection *pos;
381 struct MHD_Connection *pos; 404 unsigned int dto;
382 unsigned int dto; 405
383 406 dto = daemon->connection_timeout;
384 dto = daemon->connection_timeout; 407 if (0 == dto)
385 if (0 == dto) 408 return MHD_NO;
386 return MHD_NO; 409 pos = daemon->connections;
387 pos = daemon->connections; 410 if (pos == NULL)
388 if (pos == NULL) 411 return MHD_NO; /* no connections */
389 return MHD_NO; /* no connections */ 412 now = time(NULL);
390 now = time (NULL); 413 /* start with conservative estimate */
391 /* start with conservative estimate */ 414 earliest_deadline = now + dto;
392 earliest_deadline = now + dto; 415 while (pos != NULL)
393 while (pos != NULL) 416 {
394 { 417 if (earliest_deadline > pos->last_activity + dto)
395 if (earliest_deadline > pos->last_activity + dto) 418 earliest_deadline = pos->last_activity + dto;
396 earliest_deadline = pos->last_activity + dto; 419 pos = pos->next;
397 pos = pos->next; 420 }
398 } 421 if (earliest_deadline < now)
399 if (earliest_deadline < now) 422 *timeout = 0;
400 *timeout = 0; 423 else
401 else 424 *timeout = (earliest_deadline - now);
402 *timeout = (earliest_deadline - now); 425 return MHD_YES;
403 return MHD_YES; 426 }
404}
405 427
406/** 428/**
407 * Main select call. 429 * Main select call.
@@ -409,101 +431,102 @@ MHD_get_timeout (struct MHD_Daemon *daemon, unsigned long long *timeout)
409 * @param may_block YES if blocking, NO if non-blocking 431 * @param may_block YES if blocking, NO if non-blocking
410 * @return MHD_NO on serious errors, MHD_YES on success 432 * @return MHD_NO on serious errors, MHD_YES on success
411 */ 433 */
412static int 434static int MHD_select(struct MHD_Daemon *daemon, int may_block)
413MHD_select (struct MHD_Daemon *daemon, int may_block) 435 {
414{ 436 struct MHD_Connection *pos;
415 struct MHD_Connection *pos; 437 int num_ready;
416 int num_ready; 438 fd_set rs;
417 fd_set rs; 439 fd_set ws;
418 fd_set ws; 440 fd_set es;
419 fd_set es; 441 int max;
420 int max; 442 struct timeval timeout;
421 struct timeval timeout; 443 unsigned long long ltimeout;
422 unsigned long long ltimeout; 444 int ds;
423 int ds; 445 time_t now;
424 time_t now; 446
425 447 timeout.tv_sec = 0;
426 timeout.tv_sec = 0; 448 timeout.tv_usec = 0;
427 timeout.tv_usec = 0; 449 if (daemon == NULL)
428 if (daemon == NULL) 450 abort();
429 abort (); 451 if (daemon->shutdown == MHD_YES)
430 if (daemon->shutdown == MHD_YES) 452 return MHD_NO;
431 return MHD_NO; 453 FD_ZERO (&rs);
432 FD_ZERO (&rs); 454 FD_ZERO (&ws);
433 FD_ZERO (&ws); 455 FD_ZERO (&es);
434 FD_ZERO (&es); 456 max = 0;
435 max = 0; 457
436 458 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
437 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 459 {
438 { 460 /* single-threaded, go over everything */
439 /* single-threaded, go over everything */ 461 if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
440 if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max)) 462 return MHD_NO;
441 return MHD_NO; 463 }
442 } 464 else
443 else 465 {
444 { 466 /* accept only, have one thread per connection */
445 /* accept only, have one thread per connection */ 467 max = daemon->socket_fd;
446 max = daemon->socket_fd; 468 if (max == -1)
447 if (max == -1) 469 return MHD_NO;
448 return MHD_NO; 470 FD_SET (max, &rs);
449 FD_SET (max, &rs); 471 }
450 } 472
451 if (may_block == MHD_NO) 473 if (may_block == MHD_NO)
452 { 474 {
453 timeout.tv_usec = 0; 475 timeout.tv_usec = 0;
454 timeout.tv_sec = 0; 476 timeout.tv_sec = 0;
455 } 477 }
456 else 478 else
457 { 479 {
458 /* ltimeout is in ms */ 480 /* ltimeout is in ms */
459 if (MHD_YES == MHD_get_timeout (daemon, &ltimeout)) 481 if (MHD_YES == MHD_get_timeout (daemon, &ltimeout))
460 { 482 {
461 timeout.tv_usec = (ltimeout % 1000) * 1000; 483 timeout.tv_usec = (ltimeout % 1000) * 1000;
462 timeout.tv_sec = ltimeout / 1000; 484 timeout.tv_sec = ltimeout / 1000;
463 may_block = MHD_NO; 485 may_block = MHD_NO;
464 } 486 }
465 } 487 }
466 num_ready = SELECT (max + 1, 488
467 &rs, &ws, &es, may_block == MHD_NO ? &timeout : NULL); 489 num_ready = select(max + 1, &rs, &ws, &es, may_block == MHD_NO ? &timeout
468 if (daemon->shutdown == MHD_YES) 490 : NULL);
469 return MHD_NO; 491
470 if (num_ready < 0) 492 if (daemon->shutdown == MHD_YES)
471 { 493 return MHD_NO;
472 if (errno == EINTR) 494 if (num_ready < 0)
473 return MHD_YES; 495 {
496 if (errno == EINTR)
497 return MHD_YES;
474#if HAVE_MESSAGES 498#if HAVE_MESSAGES
475 MHD_DLOG (daemon, "Select failed: %s\n", STRERROR (errno)); 499 MHD_DLOG(daemon, "Select failed: %s\n", STRERROR (errno));
476#endif 500#endif
477 return MHD_NO; 501 return MHD_NO;
478 } 502 }
479 ds = daemon->socket_fd; 503 ds = daemon->socket_fd;
480 if (ds == -1) 504 if (ds == -1)
505 return MHD_YES;
506 if (__FD_ISSET (ds, &rs))
507 MHD_accept_connection(daemon);
508 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
509 {
510 /* do not have a thread per connection, process all connections now */
511 now = time(NULL);
512 pos = daemon->connections;
513 while (pos != NULL)
514 {
515 ds = pos->socket_fd;
516 if (ds != -1)
517 {
518 if (FD_ISSET (ds, &rs))
519 MHD_connection_handle_read(pos);
520 if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws)))
521 MHD_connection_handle_write(pos);
522 if (pos->socket_fd != -1)
523 MHD_connection_handle_idle(pos);
524 }
525 pos = pos->next;
526 }
527 }
481 return MHD_YES; 528 return MHD_YES;
482 if (FD_ISSET (ds, &rs)) 529 }
483 MHD_accept_connection (daemon);
484 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
485 {
486 /* do not have a thread per connection, process all connections now */
487 now = time (NULL);
488 pos = daemon->connections;
489 while (pos != NULL)
490 {
491 ds = pos->socket_fd;
492 if (ds != -1)
493 {
494 if (FD_ISSET (ds, &rs))
495 MHD_connection_handle_read (pos);
496 if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws)))
497 MHD_connection_handle_write (pos);
498 if (pos->socket_fd != -1)
499 MHD_connection_handle_idle (pos);
500 }
501 pos = pos->next;
502 }
503 }
504 return MHD_YES;
505}
506
507 530
508/** 531/**
509 * Run webserver operations (without blocking unless 532 * Run webserver operations (without blocking unless
@@ -515,35 +538,31 @@ MHD_select (struct MHD_Daemon *daemon, int may_block)
515 * daemon was not started with the right 538 * daemon was not started with the right
516 * options for this call. 539 * options for this call.
517 */ 540 */
518int 541int MHD_run(struct MHD_Daemon *daemon)
519MHD_run (struct MHD_Daemon *daemon) 542 {
520{ 543 if ((daemon->shutdown != MHD_NO) || (0 != (daemon->options
521 if ((daemon->shutdown != MHD_NO) || 544 & MHD_USE_THREAD_PER_CONNECTION)) || (0 != (daemon->options
522 (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || 545 & MHD_USE_SELECT_INTERNALLY)))
523 (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) 546 return MHD_NO;
524 return MHD_NO; 547 MHD_select(daemon, MHD_NO);
525 MHD_select (daemon, MHD_NO); 548 MHD_cleanup_connections(daemon);
526 MHD_cleanup_connections (daemon); 549 return MHD_YES;
527 return MHD_YES; 550 }
528}
529
530 551
531/** 552/**
532 * Thread that runs the select loop until the daemon 553 * Thread that runs the select loop until the daemon
533 * is explicitly shut down. 554 * is explicitly shut down.
534 */ 555 */
535static void * 556static void * MHD_select_thread(void *cls)
536MHD_select_thread (void *cls) 557 {
537{ 558 struct MHD_Daemon *daemon = cls;
538 struct MHD_Daemon *daemon = cls; 559 while (daemon->shutdown == MHD_NO)
539 while (daemon->shutdown == MHD_NO) 560 {
540 { 561 MHD_select(daemon, MHD_YES);
541 MHD_select (daemon, MHD_YES); 562 MHD_cleanup_connections(daemon);
542 MHD_cleanup_connections (daemon); 563 }
543 } 564 return NULL;
544 return NULL; 565 }
545}
546
547 566
548/** 567/**
549 * Start a webserver on the given port. 568 * Start a webserver on the given port.
@@ -556,106 +575,119 @@ MHD_select_thread (void *cls)
556 * @param dh_cls extra argument to dh 575 * @param dh_cls extra argument to dh
557 * @return NULL on error, handle to daemon on success 576 * @return NULL on error, handle to daemon on success
558 */ 577 */
559struct MHD_Daemon * 578struct MHD_Daemon * MHD_start_daemon(unsigned int options,
560MHD_start_daemon (unsigned int options, 579 unsigned short port,
561 unsigned short port, 580 MHD_AcceptPolicyCallback apc,
562 MHD_AcceptPolicyCallback apc, 581 void *apc_cls,
563 void *apc_cls, 582 MHD_AccessHandlerCallback dh,
564 MHD_AccessHandlerCallback dh, void *dh_cls, ...) 583 void *dh_cls,
565{ 584 ...)
566 const int on = 1; 585 {
567 struct MHD_Daemon *retVal; 586 const int on = 1;
568 int socket_fd; 587 struct MHD_Daemon *retVal;
569 struct sockaddr_in servaddr4; 588
570 struct sockaddr_in6 servaddr6; 589 /* listeningss sockets used by the daemon */
571 const struct sockaddr *servaddr; 590 int socket_fd;
572 socklen_t addrlen; 591
573 va_list ap; 592 struct sockaddr_in servaddr4;
574 enum MHD_OPTION opt; 593 struct sockaddr_in6 servaddr6;
575 594 const struct sockaddr *servaddr;
576 if ((options & MHD_USE_SSL) != 0) 595 socklen_t addrlen;
577 return NULL; 596 va_list ap;
578 if ((port == 0) || (dh == NULL)) 597 enum MHD_OPTION opt;
579 return NULL; 598
580 if ((options & MHD_USE_IPv6) != 0) 599 if ((port == 0) || (dh == NULL))
581 socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0); 600 return NULL;
582 else 601 if ((options & MHD_USE_IPv6) != 0)
583 socket_fd = SOCKET (PF_INET, SOCK_STREAM, 0); 602 socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0);
584 if (socket_fd < 0) 603 else
585 { 604 socket_fd = SOCKET (PF_INET, SOCK_STREAM, 0);
605 if (socket_fd < 0)
606 {
586#if HAVE_MESSAGES 607#if HAVE_MESSAGES
587 if ((options & MHD_USE_DEBUG) != 0) 608 if ((options & MHD_USE_DEBUG) != 0)
588 fprintf (stderr, "Call to socket failed: %s\n", STRERROR (errno)); 609 fprintf(stderr, "Call to socket failed: %s\n", STRERROR (errno));
589#endif 610#endif
590 return NULL; 611 return NULL;
591 } 612 }
592 if ((SETSOCKOPT (socket_fd, 613 if ((SETSOCKOPT (socket_fd,
593 SOL_SOCKET, 614 SOL_SOCKET,
594 SO_REUSEADDR, 615 SO_REUSEADDR,
595 &on, sizeof (on)) < 0) && (options & MHD_USE_DEBUG) != 0) 616 &on, sizeof (on)) < 0) && (options & MHD_USE_DEBUG) != 0)
596 { 617 {
597#if HAVE_MESSAGES 618#if HAVE_MESSAGES
598 fprintf (stderr, "setsockopt failed: %s\n", STRERROR (errno)); 619 fprintf(stderr, "setsockopt failed: %s\n", STRERROR (errno));
599#endif 620#endif
600 } 621 }
601 if ((options & MHD_USE_IPv6) != 0) 622 if ((options & MHD_USE_IPv6) != 0)
602 { 623 {
603 memset (&servaddr6, 0, sizeof (struct sockaddr_in6)); 624 memset(&servaddr6, 0, sizeof(struct sockaddr_in6));
604 servaddr6.sin6_family = AF_INET6; 625 servaddr6.sin6_family = AF_INET6;
605 servaddr6.sin6_port = htons (port); 626 servaddr6.sin6_port = htons(port);
606 servaddr = (struct sockaddr *) &servaddr6; 627 servaddr = (struct sockaddr *) &servaddr6;
607 addrlen = sizeof (struct sockaddr_in6); 628 addrlen = sizeof(struct sockaddr_in6);
608 } 629 }
609 else 630 else
610 { 631 {
611 memset (&servaddr4, 0, sizeof (struct sockaddr_in)); 632 memset(&servaddr4, 0, sizeof(struct sockaddr_in));
612 servaddr4.sin_family = AF_INET; 633 servaddr4.sin_family = AF_INET;
613 servaddr4.sin_port = htons (port); 634 servaddr4.sin_port = htons(port);
614 servaddr = (struct sockaddr *) &servaddr4; 635 servaddr = (struct sockaddr *) &servaddr4;
615 addrlen = sizeof (struct sockaddr_in); 636 addrlen = sizeof(struct sockaddr_in);
616 } 637 }
617 if (BIND (socket_fd, servaddr, addrlen) < 0) 638 if (BIND (socket_fd, servaddr, addrlen) < 0)
618 { 639 {
619#if HAVE_MESSAGES 640#if HAVE_MESSAGES
620 if ((options & MHD_USE_DEBUG) != 0) 641 if ((options & MHD_USE_DEBUG) != 0)
621 fprintf (stderr, 642 fprintf(stderr,
622 "Failed to bind to port %u: %s\n", port, STRERROR (errno)); 643 "Failed to bind to port %u: %s\n", port, STRERROR (errno));
623#endif 644#endif
624 CLOSE (socket_fd); 645 CLOSE (socket_fd);
625 return NULL; 646 return NULL;
626 } 647 }
627 if (LISTEN (socket_fd, 20) < 0) 648 if (LISTEN (socket_fd, 20) < 0)
628 { 649 {
629#if HAVE_MESSAGES 650#if HAVE_MESSAGES
630 if ((options & MHD_USE_DEBUG) != 0) 651 if ((options & MHD_USE_DEBUG) != 0)
631 fprintf (stderr, 652 fprintf(stderr,
632 "Failed to listen for connections: %s\n", STRERROR (errno)); 653 "Failed to listen for connections: %s\n", STRERROR (errno));
633#endif 654#endif
634 CLOSE (socket_fd); 655 CLOSE (socket_fd);
635 return NULL; 656 return NULL;
636 } 657 }
637 retVal = malloc (sizeof (struct MHD_Daemon)); 658
638 if (retVal == NULL) 659 /* allocate the mhd daemon */
639 { 660
640 CLOSE (socket_fd); 661 retVal = malloc(sizeof(struct MHD_Daemon));
641 return NULL; 662
642 } 663 if (retVal == NULL)
643 memset (retVal, 0, sizeof (struct MHD_Daemon)); 664 {
644 retVal->options = options; 665 CLOSE (socket_fd);
645 retVal->port = port; 666 return NULL;
646 retVal->apc = apc; 667 }
647 retVal->apc_cls = apc_cls; 668
648 retVal->socket_fd = socket_fd; 669 memset(retVal, 0, sizeof(struct MHD_Daemon));
649 retVal->default_handler = dh; 670 retVal->options = options;
650 retVal->default_handler_cls = dh_cls; 671 retVal->port = port;
651 retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT; 672 retVal->apc = apc;
652 retVal->pool_size = MHD_POOL_SIZE_DEFAULT; 673 retVal->apc_cls = apc_cls;
653 retVal->connection_timeout = 0; /* no timeout */ 674 retVal->socket_fd = socket_fd;
654 va_start (ap, dh_cls); 675 retVal->default_handler = dh;
655 while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION))) 676 retVal->default_handler_cls = dh_cls;
656 { 677 retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
657 switch (opt) 678 retVal->pool_size = MHD_POOL_SIZE_DEFAULT;
658 { 679 retVal->connection_timeout = 0; /* no timeout */
680
681 /* initializes the argument pointer variable */
682 va_start (ap, dh_cls);
683
684 /*
685 * loop through daemon options
686 */
687 while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION)))
688 {
689 switch (opt)
690 {
659 case MHD_OPTION_CONNECTION_MEMORY_LIMIT: 691 case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
660 retVal->pool_size = va_arg (ap, unsigned int); 692 retVal->pool_size = va_arg (ap, unsigned int);
661 break; 693 break;
@@ -666,8 +698,7 @@ MHD_start_daemon (unsigned int options,
666 retVal->connection_timeout = va_arg (ap, unsigned int); 698 retVal->connection_timeout = va_arg (ap, unsigned int);
667 break; 699 break;
668 case MHD_OPTION_NOTIFY_COMPLETED: 700 case MHD_OPTION_NOTIFY_COMPLETED:
669 retVal->notify_completed = 701 retVal->notify_completed = va_arg (ap, MHD_RequestCompletedCallback);
670 va_arg (ap, MHD_RequestCompletedCallback);
671 retVal->notify_completed_cls = va_arg (ap, void *); 702 retVal->notify_completed_cls = va_arg (ap, void *);
672 break; 703 break;
673 case MHD_OPTION_PER_IP_CONNECTION_LIMIT: 704 case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
@@ -675,76 +706,76 @@ MHD_start_daemon (unsigned int options,
675 break; 706 break;
676 default: 707 default:
677#if HAVE_MESSAGES 708#if HAVE_MESSAGES
678 fprintf (stderr, 709 fprintf(stderr,
679 "Invalid MHD_OPTION argument! (Did you terminate the list with MHD_OPTION_END?)\n"); 710 "Invalid MHD_OPTION argument! (Did you terminate the list with MHD_OPTION_END?)\n");
680#endif 711#endif
681 abort (); 712 abort();
682 } 713 }
683 } 714 }
684 va_end (ap); 715 va_end (ap);
685 if (((0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || 716 if (((0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || (0 != (options
686 (0 != (options & MHD_USE_SELECT_INTERNALLY))) && 717 & MHD_USE_SELECT_INTERNALLY))) && (0 != pthread_create(&retVal->pid,
687 (0 != pthread_create (&retVal->pid, NULL, &MHD_select_thread, retVal))) 718 NULL, &MHD_select_thread, retVal)))
688 { 719 {
689#if HAVE_MESSAGES 720#if HAVE_MESSAGES
690 MHD_DLOG (retVal, 721 MHD_DLOG(retVal, "Failed to create listen thread: %s\n",
691 "Failed to create listen thread: %s\n", STRERROR (errno)); 722 STRERROR (errno));
692#endif 723#endif
693 free (retVal); 724 free(retVal);
694 CLOSE (socket_fd); 725 CLOSE (socket_fd);
695 return NULL; 726 return NULL;
696 } 727 }
697 return retVal; 728
698} 729 return retVal;
730 }
699 731
700/** 732/**
701 * Shutdown an http daemon. 733 * Shutdown an http daemon.
702 */ 734 */
703void 735void MHD_stop_daemon(struct MHD_Daemon *daemon)
704MHD_stop_daemon (struct MHD_Daemon *daemon) 736 {
705{ 737 void *unused;
706 void *unused; 738 int fd;
707 int fd; 739
708 740 if (daemon == NULL)
709 if (daemon == NULL) 741 return;
710 return; 742 daemon->shutdown = MHD_YES;
711 daemon->shutdown = MHD_YES; 743 fd = daemon->socket_fd;
712 fd = daemon->socket_fd; 744 daemon->socket_fd = -1;
713 daemon->socket_fd = -1;
714#if DEBUG_CLOSE 745#if DEBUG_CLOSE
715#if HAVE_MESSAGES 746#if HAVE_MESSAGES
716 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n"); 747 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
717#endif 748#endif
718#endif 749#endif
719 CLOSE (fd); 750 CLOSE (fd);
720 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || 751 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || (0
721 (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) 752 != (daemon->
722 { 753 options & MHD_USE_SELECT_INTERNALLY)))
723 pthread_kill (daemon->pid, SIGALRM); 754 {
724 pthread_join (daemon->pid, &unused); 755 pthread_kill(daemon->pid, SIGALRM);
725 } 756 pthread_join(daemon->pid, &unused);
726 while (daemon->connections != NULL) 757 }
727 { 758 while (daemon->connections != NULL)
728 if (-1 != daemon->connections->socket_fd) 759 {
729 { 760 if (-1 != daemon->connections->socket_fd)
761 {
730#if DEBUG_CLOSE 762#if DEBUG_CLOSE
731#if HAVE_MESSAGES 763#if HAVE_MESSAGES
732 MHD_DLOG (daemon, "MHD shutdown, closing active connections\n"); 764 MHD_DLOG (daemon, "MHD shutdown, closing active connections\n");
733#endif 765#endif
734#endif 766#endif
735 if (daemon->notify_completed != NULL) 767 if (daemon->notify_completed != NULL)
736 daemon->notify_completed (daemon->notify_completed_cls, 768 daemon->notify_completed(daemon->notify_completed_cls,
737 daemon->connections, 769 daemon->connections, &daemon->connections->client_context,
738 &daemon->connections->client_context, 770 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
739 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); 771 SHUTDOWN (daemon->connections->socket_fd, SHUT_RDWR);
740 SHUTDOWN (daemon->connections->socket_fd, SHUT_RDWR); 772 CLOSE (daemon->connections->socket_fd);
741 CLOSE (daemon->connections->socket_fd); 773 daemon->connections->socket_fd = -1;
742 daemon->connections->socket_fd = -1; 774 }
743 } 775 MHD_cleanup_connections(daemon);
744 MHD_cleanup_connections (daemon); 776 }
745 } 777 free(daemon);
746 free (daemon); 778 }
747}
748 779
749#ifndef WINDOWS 780#ifndef WINDOWS
750 781
@@ -752,38 +783,37 @@ static struct sigaction sig;
752 783
753static struct sigaction old; 784static struct sigaction old;
754 785
755static void 786static void sigalrmHandler(int sig)
756sigalrmHandler (int sig) 787 {
757{ 788 }
758}
759 789
760/** 790/**
761 * Initialize the signal handler for SIGALRM. 791 * Initialize the signal handler for SIGALRM.
762 */ 792 */
763void __attribute__ ((constructor)) MHD_pthread_handlers_ltdl_init () 793void __attribute__ ((constructor)) MHD_pthread_handlers_ltdl_init()
764{ 794 {
765 /* make sure SIGALRM does not kill us */ 795 /* make sure SIGALRM does not kill us */
766 memset (&sig, 0, sizeof (struct sigaction)); 796 memset(&sig, 0, sizeof(struct sigaction));
767 memset (&old, 0, sizeof (struct sigaction)); 797 memset(&old, 0, sizeof(struct sigaction));
768 sig.sa_flags = SA_NODEFER; 798 sig.sa_flags = SA_NODEFER;
769 sig.sa_handler = &sigalrmHandler; 799 sig.sa_handler = &sigalrmHandler;
770 sigaction (SIGALRM, &sig, &old); 800 sigaction(SIGALRM, &sig, &old);
771} 801 }
772 802
773void __attribute__ ((destructor)) MHD_pthread_handlers_ltdl_fini () 803void __attribute__ ((destructor)) MHD_pthread_handlers_ltdl_fini()
774{ 804 {
775 sigaction (SIGALRM, &old, &sig); 805 sigaction(SIGALRM, &old, &sig);
776} 806 }
777#else 807#else
778void __attribute__ ((constructor)) MHD_win_ltdl_init () 808void __attribute__ ((constructor)) MHD_win_ltdl_init ()
779{ 809 {
780 plibc_init ("CRISP", "libmicrohttpd"); 810 plibc_init ("CRISP", "libmicrohttpd");
781} 811 }
782 812
783void __attribute__ ((destructor)) MHD_win_ltdl_fini () 813void __attribute__ ((destructor)) MHD_win_ltdl_fini ()
784{ 814 {
785 plibc_shutdown (); 815 plibc_shutdown ();
786} 816 }
787#endif 817#endif
788 818
789/* end of daemon.c */ 819/* end of daemon.c */