~ubuntu-branches/ubuntu/vivid/libmicrohttpd/vivid

« back to all changes in this revision

Viewing changes to src/daemon/daemon.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-05-18 12:41:53 UTC
  • mfrom: (1.3.1 upstream) (7.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20090518124153-nfup3gwcwpt4soes
Tags: 0.4.2-1
MergingĀ upstreamĀ versionĀ 0.4.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
  This file is part of libmicrohttpd
3
 
  (C) 2007, 2008 Daniel Pittman and Christian Grothoff
 
3
  (C) 2007, 2008, 2009 Daniel Pittman and Christian Grothoff
4
4
 
5
5
  This library is free software; you can redistribute it and/or
6
6
  modify it under the terms of the GNU Lesser General Public
64
64
#endif
65
65
#endif
66
66
 
 
67
/**
 
68
 * Trace up to and return master daemon. If the supplied daemon
 
69
 * is a master, then return the daemon itself.
 
70
 */
 
71
static struct MHD_Daemon*
 
72
MHD_get_master (struct MHD_Daemon *daemon)
 
73
{
 
74
  while (NULL != daemon->master)
 
75
    daemon = daemon->master;
 
76
  return daemon;
 
77
}
 
78
 
 
79
/**
 
80
 * Maintain connection count for single address.
 
81
 */
 
82
struct MHD_IPCount
 
83
{
 
84
  int family;
 
85
  union
 
86
  {
 
87
    struct in_addr ipv4;
 
88
#if HAVE_IPV6
 
89
    struct in6_addr ipv6;
 
90
#endif
 
91
  } addr;
 
92
  unsigned int count;
 
93
};
 
94
 
 
95
/**
 
96
 * Lock shared structure for IP connection counts
 
97
 */
 
98
static void
 
99
MHD_ip_count_lock(struct MHD_Daemon *daemon)
 
100
{
 
101
  if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex))
 
102
    {
 
103
#if HAVE_MESSAGES
 
104
      MHD_DLOG (daemon, "Failed to acquire IP connection limit mutex\n");
 
105
#endif
 
106
      abort();
 
107
    }
 
108
}
 
109
 
 
110
/**
 
111
 * Unlock shared structure for IP connection counts
 
112
 */
 
113
static void
 
114
MHD_ip_count_unlock(struct MHD_Daemon *daemon)
 
115
{
 
116
  if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex))
 
117
    {
 
118
#if HAVE_MESSAGES
 
119
      MHD_DLOG (daemon, "Failed to release IP connection limit mutex\n");
 
120
#endif
 
121
      abort();
 
122
    }
 
123
}
 
124
 
 
125
/**
 
126
 * Tree comparison function for IP addresses (supplied to tsearch() family).
 
127
 * We compare everything in the struct up through the beginning of the
 
128
 * 'count' field.
 
129
 */
 
130
static int
 
131
MHD_ip_addr_compare(const void *a1, const void *a2)
 
132
{
 
133
  return memcmp (a1, a2, offsetof(struct MHD_IPCount, count));
 
134
}
 
135
 
 
136
/**
 
137
 * Parse address and initialize 'key' using the address. Returns MHD_YES
 
138
 * on success and MHD_NO otherwise (e.g., invalid address type).
 
139
 */
 
140
static int
 
141
MHD_ip_addr_to_key(struct sockaddr *addr, socklen_t addrlen,
 
142
                   struct MHD_IPCount *key)
 
143
{
 
144
  memset(key, 0, sizeof(*key));
 
145
 
 
146
  /* IPv4 addresses */
 
147
  if (addrlen == sizeof(struct sockaddr_in))
 
148
    {
 
149
      const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;
 
150
      key->family = AF_INET;
 
151
      memcpy (&key->addr.ipv4, &addr4->sin_addr, sizeof(addr4->sin_addr));
 
152
      return MHD_YES;
 
153
    }
 
154
 
 
155
#if HAVE_IPV6
 
156
  /* IPv6 addresses */
 
157
  if (addrlen == sizeof (struct sockaddr_in6))
 
158
    {
 
159
      const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)addr;
 
160
      key->family = AF_INET6;
 
161
      memcpy (&key->addr.ipv6, &addr6->sin6_addr, sizeof(addr6->sin6_addr));
 
162
      return MHD_YES;
 
163
    }
 
164
#endif
 
165
 
 
166
  /* Some other address */
 
167
  return MHD_NO;
 
168
}
 
169
 
 
170
/**
 
171
 * Check if IP address is over its limit.
 
172
 *
 
173
 * @return Return MHD_YES if IP below limit, MHD_NO if IP has surpassed limit.
 
174
 *   Also returns MHD_NO if fails to allocate memory.
 
175
 */
 
176
static int
 
177
MHD_ip_limit_add(struct MHD_Daemon *daemon,
 
178
                 struct sockaddr *addr, socklen_t addrlen)
 
179
{
 
180
  struct MHD_IPCount *key;
 
181
  void *node;
 
182
  int result;
 
183
 
 
184
  daemon = MHD_get_master (daemon);
 
185
 
 
186
  /* Ignore if no connection limit assigned */
 
187
  if (daemon->per_ip_connection_limit == 0)
 
188
    return MHD_YES;
 
189
 
 
190
  key = malloc (sizeof(*key));
 
191
  if (NULL == key)
 
192
    return MHD_NO;
 
193
 
 
194
  /* Initialize key */
 
195
  if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key))
 
196
    {
 
197
      /* Allow unhandled address types through */
 
198
      free (key);
 
199
      return MHD_YES;
 
200
    }
 
201
 
 
202
  MHD_ip_count_lock (daemon);
 
203
 
 
204
  /* Search for the IP address */
 
205
  node = TSEARCH (key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
 
206
  if (!node)
 
207
    {
 
208
#if HAVE_MESSAGES
 
209
      MHD_DLOG(daemon,
 
210
               "Failed to add IP connection count node\n");
 
211
#endif
 
212
      MHD_ip_count_unlock (daemon);
 
213
      return MHD_NO;
 
214
    }
 
215
  node = *(void**)node;
 
216
 
 
217
  /* If we got an existing node back, free the one we created */
 
218
  if (node != key)
 
219
    free(key);
 
220
  key = (struct MHD_IPCount*)node;
 
221
 
 
222
  /* Test if there is room for another connection; if so,
 
223
   * increment count */
 
224
  result = (key->count < daemon->per_ip_connection_limit);
 
225
  if (result == MHD_YES)
 
226
    ++key->count;
 
227
 
 
228
  MHD_ip_count_unlock (daemon);
 
229
  return result;
 
230
}
 
231
 
 
232
/**
 
233
 * Decrement connection count for IP address, removing from table
 
234
 * count reaches 0
 
235
 */
 
236
static void
 
237
MHD_ip_limit_del(struct MHD_Daemon *daemon,
 
238
                 struct sockaddr *addr, socklen_t addrlen)
 
239
{
 
240
  struct MHD_IPCount search_key;
 
241
  struct MHD_IPCount *found_key;
 
242
  void *node;
 
243
 
 
244
  daemon = MHD_get_master (daemon);
 
245
 
 
246
  /* Ignore if no connection limit assigned */
 
247
  if (daemon->per_ip_connection_limit == 0)
 
248
    return;
 
249
 
 
250
  /* Initialize search key */
 
251
  if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key))
 
252
    return;
 
253
 
 
254
  MHD_ip_count_lock (daemon);
 
255
 
 
256
  /* Search for the IP address */
 
257
  node = TFIND (&search_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
 
258
 
 
259
  /* Something's wrong if we couldn't find an IP address
 
260
   * that was previously added */
 
261
  if (!node)
 
262
    {
 
263
#if HAVE_MESSAGES
 
264
      MHD_DLOG (daemon,
 
265
                "Failed to find previously-added IP address\n");
 
266
#endif
 
267
      abort();
 
268
    }
 
269
  found_key = (struct MHD_IPCount*)*(void**)node;
 
270
 
 
271
  /* Validate existing count for IP address */
 
272
  if (found_key->count == 0)
 
273
    {
 
274
#if HAVE_MESSAGES
 
275
      MHD_DLOG (daemon,
 
276
                "Previously-added IP address had 0 count\n");
 
277
#endif
 
278
      abort();
 
279
    }
 
280
 
 
281
  /* Remove the node entirely if count reduces to 0 */
 
282
  if (--found_key->count == 0)
 
283
    {
 
284
      TDELETE (found_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
 
285
      free (found_key);
 
286
    }
 
287
 
 
288
  MHD_ip_count_unlock (daemon);
 
289
}
 
290
 
67
291
#if HTTPS_SUPPORT
68
292
pthread_mutex_t MHD_gnutls_init_mutex;
69
293
 
298
522
{
299
523
  if (connection->socket_fd == -1)
300
524
    return -1;
301
 
  return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
 
525
  if (0 != (connection->daemon->options & MHD_USE_SSL))
 
526
    return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
 
527
  else
 
528
    return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT);
302
529
}
303
530
 
304
531
/**
315
542
{
316
543
  if (connection->socket_fd == -1)
317
544
    return -1;
318
 
  return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
 
545
  if (0 != (connection->daemon->options & MHD_USE_SSL))
 
546
    return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
 
547
  else
 
548
    return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT);
319
549
}
320
550
 
321
551
/**
326
556
static int
327
557
MHD_accept_connection (struct MHD_Daemon *daemon)
328
558
{
329
 
  struct MHD_Connection *pos;
330
559
  struct MHD_Connection *connection;
331
560
#if HAVE_INET6
332
561
  struct sockaddr_in6 addrstorage;
335
564
#endif
336
565
  struct sockaddr *addr = (struct sockaddr *) &addrstorage;
337
566
  socklen_t addrlen;
338
 
  unsigned int have;
339
567
  int s, res_thread_create;
340
568
#if OSX
341
569
  static int on = 1;
353
581
  if ((s < 0) || (addrlen <= 0))
354
582
    {
355
583
#if HAVE_MESSAGES
356
 
      MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno));
 
584
      /* This could be a common occurance with multiple worker threads */
 
585
      if ((EAGAIN != errno) && (EWOULDBLOCK != errno))
 
586
        MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno));
357
587
#endif
358
588
      if (s != -1)
359
589
        {
368
598
  MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
369
599
#endif
370
600
#endif
371
 
  have = 0;
372
 
  if ((daemon->per_ip_connection_limit != 0) && (daemon->max_connections > 0))
373
 
    {
374
 
      pos = daemon->connections;
375
 
      while (pos != NULL)
376
 
        {
377
 
          if ((pos->addr != NULL) && (pos->addr_len == addrlen))
378
 
            {
379
 
              if (addrlen == sizeof (struct sockaddr_in))
380
 
                {
381
 
                  const struct sockaddr_in *a1 =
382
 
                    (const struct sockaddr_in *) addr;
383
 
                  const struct sockaddr_in *a2 =
384
 
                    (const struct sockaddr_in *) pos->addr;
385
 
                  if (0 == memcmp (&a1->sin_addr, &a2->sin_addr,
386
 
                                   sizeof (struct in_addr)))
387
 
                    have++;
388
 
                }
389
 
#if HAVE_INET6
390
 
              if (addrlen == sizeof (struct sockaddr_in6))
391
 
                {
392
 
                  const struct sockaddr_in6 *a1 =
393
 
                    (const struct sockaddr_in6 *) addr;
394
 
                  const struct sockaddr_in6 *a2 =
395
 
                    (const struct sockaddr_in6 *) pos->addr;
396
 
                  if (0 == memcmp (&a1->sin6_addr, &a2->sin6_addr,
397
 
                                   sizeof (struct in6_addr)))
398
 
                    have++;
399
 
                }
400
 
#endif
401
 
            }
402
 
          pos = pos->next;
403
 
        }
404
 
    }
405
 
 
406
 
  if ((daemon->max_connections == 0) || ((daemon->per_ip_connection_limit
407
 
                                          != 0)
408
 
                                         && (daemon->per_ip_connection_limit
409
 
                                             <= have)))
 
601
  if ((daemon->max_connections == 0)
 
602
      || (MHD_ip_limit_add (daemon, addr, addrlen) == MHD_NO))
410
603
    {
411
604
      /* above connection limit - reject */
412
605
#if HAVE_MESSAGES
429
622
#endif
430
623
      SHUTDOWN (s, SHUT_RDWR);
431
624
      CLOSE (s);
 
625
      MHD_ip_limit_del (daemon, addr, addrlen);
432
626
      return MHD_YES;
433
627
    }
434
628
#if OSX
439
633
#endif
440
634
#endif
441
635
  connection = malloc (sizeof (struct MHD_Connection));
442
 
  if (connection == NULL)
 
636
  if (NULL == connection)
443
637
    {
444
638
#if HAVE_MESSAGES
445
639
      MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
446
640
#endif
447
641
      SHUTDOWN (s, SHUT_RDWR);
448
642
      CLOSE (s);
 
643
      MHD_ip_limit_del (daemon, addr, addrlen);
449
644
      return MHD_NO;
450
645
    }
451
646
  memset (connection, 0, sizeof (struct MHD_Connection));
458
653
#endif
459
654
      SHUTDOWN (s, SHUT_RDWR);
460
655
      CLOSE (s);
 
656
      MHD_ip_limit_del (daemon, addr, addrlen);
461
657
      free (connection);
462
658
      return MHD_NO;
463
659
    }
521
717
#endif
522
718
          SHUTDOWN (s, SHUT_RDWR);
523
719
          CLOSE (s);
 
720
          MHD_ip_limit_del (daemon, addr, addrlen);
524
721
          free (connection->addr);
525
722
          free (connection);
526
723
          return MHD_NO;
567
764
          if (pos->tls_session != NULL)
568
765
            MHD__gnutls_deinit (pos->tls_session);
569
766
#endif
 
767
          MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
570
768
          free (pos->addr);
571
769
          free (pos);
572
770
          daemon->max_connections++;
658
856
      /* single-threaded, go over everything */
659
857
      if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
660
858
        return MHD_NO;
 
859
 
 
860
      /* If we're at the connection limit, no need to
 
861
         accept new connections. */
 
862
      if ( (daemon->max_connections == 0) && (daemon->socket_fd != -1) )
 
863
        FD_CLR(daemon->socket_fd, &rs);
661
864
    }
662
865
  else
663
866
    {
794
997
  return ret;
795
998
}
796
999
 
 
1000
 
797
1001
/**
798
1002
 * Start a webserver on the given port.
799
1003
 *
822
1026
  const struct sockaddr *servaddr = NULL;
823
1027
  socklen_t addrlen;
824
1028
  enum MHD_OPTION opt;
 
1029
  unsigned int i;
825
1030
 
826
1031
  if ((port == 0) || (dh == NULL))
827
1032
    return NULL;
885
1090
            va_arg (ap, LogCallback);
886
1091
          retVal->uri_log_callback_cls = va_arg (ap, void *);
887
1092
          break;
 
1093
        case MHD_OPTION_THREAD_POOL_SIZE:
 
1094
          retVal->worker_pool_size = va_arg (ap, unsigned int);
 
1095
          break;
888
1096
#if HTTPS_SUPPORT
889
1097
        case MHD_OPTION_PROTOCOL_VERSION:
890
1098
          _set_priority (&retVal->priority_cache->protocol,
931
1139
        }
932
1140
    }
933
1141
 
 
1142
  /* Thread pooling currently works only with internal select thread model */
 
1143
  if ((0 == (options & MHD_USE_SELECT_INTERNALLY))
 
1144
      && (retVal->worker_pool_size > 0))
 
1145
    {
 
1146
#if HAVE_MESSAGES
 
1147
      FPRINTF (stderr,
 
1148
               "MHD thread pooling only works with MHD_USE_SELECT_INTERNALLY\n");
 
1149
#endif
 
1150
      free (retVal);
 
1151
      return NULL;
 
1152
    }
 
1153
 
934
1154
  if ((options & MHD_USE_IPv6) != 0)
935
1155
#if HAVE_INET6
936
1156
    socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0);
1015
1235
      return NULL;
1016
1236
    }
1017
1237
 
 
1238
  if (0 != pthread_mutex_init (&retVal->per_ip_connection_mutex, NULL))
 
1239
    {
 
1240
#if HAVE_MESSAGES
 
1241
      MHD_DLOG (retVal,
 
1242
               "MHD failed to initialize IP connection limit mutex\n");
 
1243
#endif
 
1244
      CLOSE (socket_fd);
 
1245
      free (retVal);
 
1246
      return NULL;
 
1247
    }
 
1248
 
1018
1249
#if HTTPS_SUPPORT
1019
1250
  /* initialize HTTPS daemon certificate aspects & send / recv functions */
1020
1251
  if ((0 != (options & MHD_USE_SSL)) && (0 != MHD_TLS_init (retVal)))
1023
1254
      MHD_DLOG (retVal, "Failed to initialize TLS support\n");
1024
1255
#endif
1025
1256
      CLOSE (socket_fd);
 
1257
      pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
1026
1258
      free (retVal);
1027
1259
      return NULL;
1028
1260
    }
1029
1261
#endif
1030
1262
  if (((0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
1031
 
       (0 != (options & MHD_USE_SELECT_INTERNALLY)))
1032
 
      && (0 !=
 
1263
       ((0 != (options & MHD_USE_SELECT_INTERNALLY))
 
1264
        && (0 == retVal->worker_pool_size)))
 
1265
        && (0 !=
1033
1266
          pthread_create (&retVal->pid, NULL, &MHD_select_thread, retVal)))
1034
1267
    {
1035
1268
#if HAVE_MESSAGES
1036
1269
      MHD_DLOG (retVal,
1037
1270
                "Failed to create listen thread: %s\n", STRERROR (errno));
1038
1271
#endif
 
1272
      pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
1039
1273
      free (retVal);
1040
1274
      CLOSE (socket_fd);
1041
1275
      return NULL;
1042
1276
    }
 
1277
  else if (retVal->worker_pool_size > 0)
 
1278
    {
 
1279
#ifndef MINGW
 
1280
      int sk_flags;
 
1281
#else
 
1282
      unsigned long sk_flags;
 
1283
#endif
 
1284
 
 
1285
      /* Coarse-grained count of connections per thread (note error
 
1286
       * due to integer division). Also keep track of how many
 
1287
       * connections are leftover after an equal split. */
 
1288
      unsigned int conns_per_thread = retVal->max_connections
 
1289
                                      / retVal->worker_pool_size;
 
1290
      unsigned int leftover_conns = retVal->max_connections
 
1291
                                    % retVal->worker_pool_size;
 
1292
 
 
1293
      i = 0; /* we need this in case fcntl or malloc fails */
 
1294
 
 
1295
      /* Accept must be non-blocking. Multiple children may wake up
 
1296
       * to handle a new connection, but only one will win the race.
 
1297
       * The others must immediately return. */
 
1298
#ifndef MINGW
 
1299
      sk_flags = fcntl (socket_fd, F_GETFL);
 
1300
      if (sk_flags < 0)
 
1301
        goto thread_failed;
 
1302
      if (fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK) < 0)
 
1303
        goto thread_failed;
 
1304
#else
 
1305
      sk_flags = 1;
 
1306
#if HAVE_PLIBC_FD
 
1307
      if (ioctlsocket (plibc_fd_get_handle (socket_fd), FIONBIO, &sk_flags) ==
 
1308
          SOCKET_ERROR)
 
1309
#else
 
1310
      if (ioctlsocket (socket_fd, FIONBIO, &sk_flags) == SOCKET_ERROR)
 
1311
#endif // PLIBC_FD
 
1312
        goto thread_failed;
 
1313
#endif // MINGW
 
1314
 
 
1315
      /* Allocate memory for pooled objects */
 
1316
      retVal->worker_pool = malloc (sizeof (struct MHD_Daemon)
 
1317
                                    * retVal->worker_pool_size);
 
1318
      if (NULL == retVal->worker_pool)
 
1319
        goto thread_failed;
 
1320
 
 
1321
      /* Start the workers in the pool */
 
1322
      for (i = 0; i < retVal->worker_pool_size; ++i)
 
1323
        {
 
1324
          /* Create copy of the Daemon object for each worker */
 
1325
          struct MHD_Daemon *d = &retVal->worker_pool[i];
 
1326
          memcpy (d, retVal, sizeof (struct MHD_Daemon));
 
1327
 
 
1328
          /* Adjust pooling params for worker daemons; note that memcpy()
 
1329
             has already copied MHD_USE_SELECT_INTERNALLY thread model into
 
1330
             the worker threads. */
 
1331
          d->master = retVal;
 
1332
          d->worker_pool_size = 0;
 
1333
          d->worker_pool = NULL;
 
1334
 
 
1335
          /* Divide available connections evenly amongst the threads.
 
1336
           * Thread indexes in [0, leftover_conns) each get one of the
 
1337
           * leftover connections. */
 
1338
          d->max_connections = conns_per_thread;
 
1339
          if (i < leftover_conns)
 
1340
            ++d->max_connections;
 
1341
 
 
1342
          /* Spawn the worker thread */
 
1343
          if (0 != pthread_create (&d->pid, NULL, &MHD_select_thread, d))
 
1344
            {
 
1345
#if HAVE_MESSAGES
 
1346
              MHD_DLOG (retVal,
 
1347
                        "Failed to create pool thread: %d\n", STRERROR (errno));
 
1348
#endif
 
1349
              /* Free memory for this worker; cleanup below handles
 
1350
               * all previously-created workers. */
 
1351
              goto thread_failed;
 
1352
            }
 
1353
        }
 
1354
    }
1043
1355
  return retVal;
1044
 
}
1045
 
 
1046
 
/**
1047
 
 * Shutdown an http daemon.
 
1356
 
 
1357
thread_failed:
 
1358
  /* If no worker threads created, then shut down normally. Calling
 
1359
     MHD_stop_daemon (as we do below) doesn't work here since it
 
1360
     assumes a 0-sized thread pool means we had been in the default
 
1361
     MHD_USE_SELECT_INTERNALLY mode. */
 
1362
  if (i == 0)
 
1363
    {
 
1364
      CLOSE (socket_fd);
 
1365
      pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
 
1366
      if (NULL != retVal->worker_pool)
 
1367
        free (retVal->worker_pool);
 
1368
      free (retVal);
 
1369
      return NULL;
 
1370
    }
 
1371
  
 
1372
  /* Shutdown worker threads we've already created. Pretend
 
1373
     as though we had fully initialized our daemon, but
 
1374
     with a smaller number of threads than had been
 
1375
     requested. */
 
1376
  retVal->worker_pool_size = i - 1;
 
1377
  MHD_stop_daemon (retVal);
 
1378
  return NULL;
 
1379
}
 
1380
 
 
1381
/**
 
1382
 * Close all connections for the daemon
 
1383
 */
 
1384
static void
 
1385
MHD_close_connections (struct MHD_Daemon *daemon)
 
1386
{
 
1387
  while (daemon->connections != NULL)
 
1388
    {
 
1389
      if (-1 != daemon->connections->socket_fd)
 
1390
        {
 
1391
#if DEBUG_CLOSE
 
1392
#if HAVE_MESSAGES
 
1393
          MHD_DLOG (daemon, "MHD shutdown, closing active connections\n");
 
1394
#endif
 
1395
#endif
 
1396
          MHD_connection_close (daemon->connections,
 
1397
                                MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
 
1398
        }
 
1399
      MHD_cleanup_connections (daemon);
 
1400
    }
 
1401
}
 
1402
 
 
1403
/**
 
1404
 * Shutdown an http daemon
1048
1405
 */
1049
1406
void
1050
1407
MHD_stop_daemon (struct MHD_Daemon *daemon)
1051
1408
{
1052
1409
  void *unused;
1053
1410
  int fd;
 
1411
  unsigned int i;
1054
1412
 
1055
1413
  if (daemon == NULL)
1056
1414
    return;
1057
1415
  daemon->shutdown = MHD_YES;
1058
1416
  fd = daemon->socket_fd;
1059
1417
  daemon->socket_fd = -1;
 
1418
 
 
1419
  /* Prepare workers for shutdown */
 
1420
  for (i = 0; i < daemon->worker_pool_size; ++i)
 
1421
    {
 
1422
      daemon->worker_pool[i].shutdown = MHD_YES;
 
1423
      daemon->worker_pool[i].socket_fd = -1;
 
1424
    }
 
1425
 
 
1426
#if OSX
 
1427
  /* without this, either (thread pool = 0) threads would get stuck or
 
1428
   * CLOSE would get stuck if attempted before (thread pool > 0) 
 
1429
   * threads have ended */
 
1430
  SHUTDOWN (fd, SHUT_RDWR);
 
1431
#else
1060
1432
#if DEBUG_CLOSE
1061
1433
#if HAVE_MESSAGES
1062
1434
  MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
1063
1435
#endif
1064
1436
#endif
1065
1437
  CLOSE (fd);
 
1438
#endif
 
1439
 
 
1440
  /* Signal workers to stop and clean them up */
 
1441
  for (i = 0; i < daemon->worker_pool_size; ++i)
 
1442
    pthread_kill (daemon->worker_pool[i].pid, SIGALRM);
 
1443
  for (i = 0; i < daemon->worker_pool_size; ++i)
 
1444
    {
 
1445
      pthread_join (daemon->worker_pool[i].pid, &unused);
 
1446
      MHD_close_connections (&daemon->worker_pool[i]);
 
1447
    }
 
1448
  free (daemon->worker_pool);
 
1449
 
1066
1450
  if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
1067
 
      (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)))
 
1451
      ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))
 
1452
        && (0 == daemon->worker_pool_size)))
1068
1453
    {
1069
1454
      pthread_kill (daemon->pid, SIGALRM);
1070
1455
      pthread_join (daemon->pid, &unused);
1071
1456
    }
1072
 
  while (daemon->connections != NULL)
1073
 
    {
1074
 
      if (-1 != daemon->connections->socket_fd)
1075
 
        {
 
1457
  MHD_close_connections (daemon);
 
1458
 
 
1459
#if OSX
1076
1460
#if DEBUG_CLOSE
1077
1461
#if HAVE_MESSAGES
1078
 
          MHD_DLOG (daemon, "MHD shutdown, closing active connections\n");
1079
 
#endif
1080
 
#endif
1081
 
          MHD_connection_close (daemon->connections,
1082
 
                                MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
1083
 
        }
1084
 
      MHD_cleanup_connections (daemon);
1085
 
    }
 
1462
  MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
 
1463
#endif
 
1464
#endif
 
1465
  CLOSE (fd);
 
1466
#endif
1086
1467
 
1087
1468
  /* TLS clean up */
1088
1469
#if HTTPS_SUPPORT
1097
1478
      pthread_mutex_unlock (&MHD_gnutls_init_mutex);
1098
1479
    }
1099
1480
#endif
 
1481
  pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
1100
1482
  free (daemon);
1101
1483
}
1102
1484
 
1117
1499
  return NULL;
1118
1500
}
1119
1501
 
 
1502
/**
 
1503
 * Obtain the version of this library
 
1504
 * 
 
1505
 * @return static version string, e.g. "0.4.1"
 
1506
 */
 
1507
const char *
 
1508
MHD_get_version (void)
 
1509
{
 
1510
  return PACKAGE_VERSION;
 
1511
}
 
1512
 
1120
1513
#ifndef WINDOWS
1121
1514
 
1122
1515
static struct sigaction sig;