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