• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2      This file is part of libmicrohttpd
3      Copyright (C) 2007, 2009, 2011 Christian Grothoff
4 
5      libmicrohttpd is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9 
10      libmicrohttpd is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14 
15      You should have received a copy of the GNU General Public License
16      along with libmicrohttpd; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 
21 /**
22  * @file test_get.c
23  * @brief  Testcase for libmicrohttpd GET operations
24  *         TODO: test parsing of query
25  * @author Christian Grothoff
26  */
27 
28 #include "MHD_config.h"
29 #include "platform.h"
30 #include "platform_interface.h"
31 #include <curl/curl.h>
32 #include <microhttpd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 
37 #ifdef _WIN32
38 #ifndef WIN32_LEAN_AND_MEAN
39 #define WIN32_LEAN_AND_MEAN 1
40 #endif /* !WIN32_LEAN_AND_MEAN */
41 #include <windows.h>
42 #endif
43 
44 #ifndef WINDOWS
45 #include <unistd.h>
46 #include <sys/socket.h>
47 #endif
48 
49 #if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
50 #undef CPU_COUNT
51 #endif
52 #if !defined(CPU_COUNT)
53 #define CPU_COUNT 2
54 #endif
55 
56 static int oneone;
57 
58 struct CBC
59 {
60   char *buf;
61   size_t pos;
62   size_t size;
63 };
64 
65 static size_t
copyBuffer(void * ptr,size_t size,size_t nmemb,void * ctx)66 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
67 {
68   struct CBC *cbc = ctx;
69 
70   if (cbc->pos + size * nmemb > cbc->size)
71     return 0;                   /* overflow */
72   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
73   cbc->pos += size * nmemb;
74   return size * nmemb;
75 }
76 
77 static int
ahc_echo(void * cls,struct MHD_Connection * connection,const char * url,const char * method,const char * version,const char * upload_data,size_t * upload_data_size,void ** unused)78 ahc_echo (void *cls,
79           struct MHD_Connection *connection,
80           const char *url,
81           const char *method,
82           const char *version,
83           const char *upload_data, size_t *upload_data_size,
84           void **unused)
85 {
86   static int ptr;
87   const char *me = cls;
88   struct MHD_Response *response;
89   int ret;
90 
91   if (0 != strcmp (me, method))
92     return MHD_NO;              /* unexpected method */
93   if (&ptr != *unused)
94     {
95       *unused = &ptr;
96       return MHD_YES;
97     }
98   *unused = NULL;
99   response = MHD_create_response_from_buffer (strlen (url),
100 					      (void *) url,
101 					      MHD_RESPMEM_MUST_COPY);
102   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
103   MHD_destroy_response (response);
104   if (ret == MHD_NO)
105     abort ();
106   return ret;
107 }
108 
109 
110 static int
testInternalGet(int poll_flag)111 testInternalGet (int poll_flag)
112 {
113   struct MHD_Daemon *d;
114   CURL *c;
115   char buf[2048];
116   struct CBC cbc;
117   CURLcode errornum;
118 
119   cbc.buf = buf;
120   cbc.size = 2048;
121   cbc.pos = 0;
122   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG  | poll_flag,
123                         11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
124   if (d == NULL)
125     return 1;
126   c = curl_easy_init ();
127   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world");
128   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
129   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
130   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
131   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
132   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
133   if (oneone)
134     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
135   else
136     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
137   /* NOTE: use of CONNECTTIMEOUT without also
138      setting NOSIGNAL results in really weird
139      crashes on my system!*/
140   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
141   if (CURLE_OK != (errornum = curl_easy_perform (c)))
142     {
143       fprintf (stderr,
144                "curl_easy_perform failed: `%s'\n",
145                curl_easy_strerror (errornum));
146       curl_easy_cleanup (c);
147       MHD_stop_daemon (d);
148       return 2;
149     }
150   curl_easy_cleanup (c);
151   MHD_stop_daemon (d);
152   if (cbc.pos != strlen ("/hello_world"))
153     return 4;
154   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
155     return 8;
156   return 0;
157 }
158 
159 
160 static int
testMultithreadedGet(int poll_flag)161 testMultithreadedGet (int poll_flag)
162 {
163   struct MHD_Daemon *d;
164   CURL *c;
165   char buf[2048];
166   struct CBC cbc;
167   CURLcode errornum;
168 
169   cbc.buf = buf;
170   cbc.size = 2048;
171   cbc.pos = 0;
172   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG  | poll_flag,
173                         1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
174   if (d == NULL)
175     return 16;
176   c = curl_easy_init ();
177   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
178   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
179   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
180   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
181   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
182   if (oneone)
183     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
184   else
185     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
186   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
187   /* NOTE: use of CONNECTTIMEOUT without also
188      setting NOSIGNAL results in really weird
189      crashes on my system! */
190   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
191   if (CURLE_OK != (errornum = curl_easy_perform (c)))
192     {
193       fprintf (stderr,
194                "curl_easy_perform failed: `%s'\n",
195                curl_easy_strerror (errornum));
196       curl_easy_cleanup (c);
197       MHD_stop_daemon (d);
198       return 32;
199     }
200   curl_easy_cleanup (c);
201   MHD_stop_daemon (d);
202   if (cbc.pos != strlen ("/hello_world"))
203     return 64;
204   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
205     return 128;
206   return 0;
207 }
208 
209 
210 static int
testMultithreadedPoolGet(int poll_flag)211 testMultithreadedPoolGet (int poll_flag)
212 {
213   struct MHD_Daemon *d;
214   CURL *c;
215   char buf[2048];
216   struct CBC cbc;
217   CURLcode errornum;
218 
219   cbc.buf = buf;
220   cbc.size = 2048;
221   cbc.pos = 0;
222   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
223                         1081, NULL, NULL, &ahc_echo, "GET",
224                         MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
225   if (d == NULL)
226     return 16;
227   c = curl_easy_init ();
228   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
229   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
230   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
231   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
232   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
233   if (oneone)
234     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
235   else
236     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
237   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
238   /* NOTE: use of CONNECTTIMEOUT without also
239      setting NOSIGNAL results in really weird
240      crashes on my system!*/
241   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
242   if (CURLE_OK != (errornum = curl_easy_perform (c)))
243     {
244       fprintf (stderr,
245                "curl_easy_perform failed: `%s'\n",
246                curl_easy_strerror (errornum));
247       curl_easy_cleanup (c);
248       MHD_stop_daemon (d);
249       return 32;
250     }
251   curl_easy_cleanup (c);
252   MHD_stop_daemon (d);
253   if (cbc.pos != strlen ("/hello_world"))
254     return 64;
255   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
256     return 128;
257   return 0;
258 }
259 
260 
261 static int
testExternalGet()262 testExternalGet ()
263 {
264   struct MHD_Daemon *d;
265   CURL *c;
266   char buf[2048];
267   struct CBC cbc;
268   CURLM *multi;
269   CURLMcode mret;
270   fd_set rs;
271   fd_set ws;
272   fd_set es;
273   MHD_socket max;
274   int running;
275   struct CURLMsg *msg;
276   time_t start;
277   struct timeval tv;
278 
279   multi = NULL;
280   cbc.buf = buf;
281   cbc.size = 2048;
282   cbc.pos = 0;
283   d = MHD_start_daemon (MHD_USE_DEBUG,
284                         1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
285   if (d == NULL)
286     return 256;
287   c = curl_easy_init ();
288   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
289   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
290   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
291   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
292   if (oneone)
293     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
294   else
295     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
296   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
297   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
298   /* NOTE: use of CONNECTTIMEOUT without also
299      setting NOSIGNAL results in really weird
300      crashes on my system! */
301   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
302 
303 
304   multi = curl_multi_init ();
305   if (multi == NULL)
306     {
307       curl_easy_cleanup (c);
308       MHD_stop_daemon (d);
309       return 512;
310     }
311   mret = curl_multi_add_handle (multi, c);
312   if (mret != CURLM_OK)
313     {
314       curl_multi_cleanup (multi);
315       curl_easy_cleanup (c);
316       MHD_stop_daemon (d);
317       return 1024;
318     }
319   start = time (NULL);
320   while ((time (NULL) - start < 5) && (multi != NULL))
321     {
322       max = 0;
323       FD_ZERO (&rs);
324       FD_ZERO (&ws);
325       FD_ZERO (&es);
326       curl_multi_perform (multi, &running);
327       mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
328       if (mret != CURLM_OK)
329         {
330           curl_multi_remove_handle (multi, c);
331           curl_multi_cleanup (multi);
332           curl_easy_cleanup (c);
333           MHD_stop_daemon (d);
334           return 2048;
335         }
336       if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
337         {
338           curl_multi_remove_handle (multi, c);
339           curl_multi_cleanup (multi);
340           curl_easy_cleanup (c);
341           MHD_stop_daemon (d);
342           return 4096;
343         }
344       tv.tv_sec = 0;
345       tv.tv_usec = 1000;
346       select (max + 1, &rs, &ws, &es, &tv);
347       curl_multi_perform (multi, &running);
348       if (running == 0)
349         {
350           msg = curl_multi_info_read (multi, &running);
351           if (msg == NULL)
352             break;
353           if (msg->msg == CURLMSG_DONE)
354             {
355               if (msg->data.result != CURLE_OK)
356                 printf ("%s failed at %s:%d: `%s'\n",
357                         "curl_multi_perform",
358                         __FILE__,
359                         __LINE__, curl_easy_strerror (msg->data.result));
360               curl_multi_remove_handle (multi, c);
361               curl_multi_cleanup (multi);
362               curl_easy_cleanup (c);
363               c = NULL;
364               multi = NULL;
365             }
366         }
367       MHD_run (d);
368     }
369   if (multi != NULL)
370     {
371       curl_multi_remove_handle (multi, c);
372       curl_easy_cleanup (c);
373       curl_multi_cleanup (multi);
374     }
375   MHD_stop_daemon (d);
376   if (cbc.pos != strlen ("/hello_world"))
377     return 8192;
378   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
379     return 16384;
380   return 0;
381 }
382 
383 
384 static int
testUnknownPortGet(int poll_flag)385 testUnknownPortGet (int poll_flag)
386 {
387   struct MHD_Daemon *d;
388   const union MHD_DaemonInfo *di;
389   CURL *c;
390   char buf[2048];
391   struct CBC cbc;
392   CURLcode errornum;
393 
394   struct sockaddr_in addr;
395   socklen_t addr_len = sizeof(addr);
396   memset(&addr, 0, sizeof(addr));
397   addr.sin_family = AF_INET;
398   addr.sin_port = 0;
399   addr.sin_addr.s_addr = INADDR_ANY;
400 
401   cbc.buf = buf;
402   cbc.size = 2048;
403   cbc.pos = 0;
404   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG  | poll_flag,
405                         1, NULL, NULL, &ahc_echo, "GET",
406                         MHD_OPTION_SOCK_ADDR, &addr,
407                         MHD_OPTION_END);
408   if (d == NULL)
409     return 32768;
410 
411   di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
412   if (di == NULL)
413     return 65536;
414 
415   if (0 != getsockname(di->listen_fd, (struct sockaddr *) &addr, &addr_len))
416     return 131072;
417 
418   if (addr.sin_family != AF_INET)
419     return 26214;
420 
421   snprintf(buf, sizeof(buf), "http://127.0.0.1:%hu/hello_world",
422            ntohs(addr.sin_port));
423 
424   c = curl_easy_init ();
425   curl_easy_setopt (c, CURLOPT_URL, buf);
426   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
427   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
428   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
429   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
430   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
431   if (oneone)
432     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
433   else
434     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
435   /* NOTE: use of CONNECTTIMEOUT without also
436      setting NOSIGNAL results in really weird
437      crashes on my system! */
438   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
439   if (CURLE_OK != (errornum = curl_easy_perform (c)))
440     {
441       fprintf (stderr,
442                "curl_easy_perform failed: `%s'\n",
443                curl_easy_strerror (errornum));
444       curl_easy_cleanup (c);
445       MHD_stop_daemon (d);
446       return 524288;
447     }
448   curl_easy_cleanup (c);
449   MHD_stop_daemon (d);
450   if (cbc.pos != strlen ("/hello_world"))
451     return 1048576;
452   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
453     return 2097152;
454   return 0;
455 }
456 
457 
458 static int
testStopRace(int poll_flag)459 testStopRace (int poll_flag)
460 {
461     struct sockaddr_in sin;
462     MHD_socket fd;
463     struct MHD_Daemon *d;
464 
465     d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
466                          1081, NULL, NULL, &ahc_echo, "GET",
467                          MHD_OPTION_CONNECTION_TIMEOUT, 5, MHD_OPTION_END);
468     if (d == NULL)
469        return 16;
470 
471     fd = socket (PF_INET, SOCK_STREAM, 0);
472     if (fd == MHD_INVALID_SOCKET)
473     {
474        fprintf(stderr, "socket error\n");
475        return 256;
476     }
477 
478     memset(&sin, 0, sizeof(sin));
479     sin.sin_family = AF_INET;
480     sin.sin_port = htons(1081);
481     sin.sin_addr.s_addr = htonl(0x7f000001);
482 
483     if (connect (fd, (struct sockaddr *)(&sin), sizeof(sin)) < 0)
484     {
485        fprintf(stderr, "connect error\n");
486        MHD_socket_close_ (fd);
487        return 512;
488     }
489 
490     /*  printf("Waiting\n"); */
491     /* Let the thread get going. */
492     usleep(500000);
493 
494     /* printf("Stopping daemon\n"); */
495     MHD_stop_daemon (d);
496 
497     MHD_socket_close_ (fd);
498 
499     /* printf("good\n"); */
500     return 0;
501 }
502 
503 
504 static int
ahc_empty(void * cls,struct MHD_Connection * connection,const char * url,const char * method,const char * version,const char * upload_data,size_t * upload_data_size,void ** unused)505 ahc_empty (void *cls,
506           struct MHD_Connection *connection,
507           const char *url,
508           const char *method,
509           const char *version,
510           const char *upload_data, size_t *upload_data_size,
511           void **unused)
512 {
513   static int ptr;
514   struct MHD_Response *response;
515   int ret;
516 
517   if (0 != strcmp ("GET", method))
518     return MHD_NO;              /* unexpected method */
519   if (&ptr != *unused)
520     {
521       *unused = &ptr;
522       return MHD_YES;
523     }
524   *unused = NULL;
525   response = MHD_create_response_from_buffer (0,
526 					      NULL,
527 					      MHD_RESPMEM_PERSISTENT);
528   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
529   MHD_destroy_response (response);
530   if (ret == MHD_NO)
531     abort ();
532   return ret;
533 }
534 
535 
536 static int
curlExcessFound(CURL * c,curl_infotype type,char * data,size_t size,void * cls)537 curlExcessFound(CURL *c, curl_infotype type, char *data, size_t size, void *cls)
538 {
539   static const char *excess_found = "Excess found";
540   const size_t str_size = strlen (excess_found);
541 
542   if (CURLINFO_TEXT == type
543       && size >= str_size
544       && 0 == strncmp(excess_found, data, str_size))
545     *(int *)cls = 1;
546   return 0;
547 }
548 
549 
550 static int
testEmptyGet(int poll_flag)551 testEmptyGet (int poll_flag)
552 {
553   struct MHD_Daemon *d;
554   CURL *c;
555   char buf[2048];
556   struct CBC cbc;
557   CURLcode errornum;
558   int excess_found = 0;
559 
560   cbc.buf = buf;
561   cbc.size = 2048;
562   cbc.pos = 0;
563   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG  | poll_flag,
564                         11081, NULL, NULL, &ahc_empty, NULL, MHD_OPTION_END);
565   if (d == NULL)
566     return 4194304;
567   c = curl_easy_init ();
568   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
569   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
570   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
571   curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, &curlExcessFound);
572   curl_easy_setopt (c, CURLOPT_DEBUGDATA, &excess_found);
573   curl_easy_setopt (c, CURLOPT_VERBOSE, 1);
574   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
575   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
576   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
577   if (oneone)
578     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
579   else
580     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
581   /* NOTE: use of CONNECTTIMEOUT without also
582      setting NOSIGNAL results in really weird
583      crashes on my system!*/
584   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
585   if (CURLE_OK != (errornum = curl_easy_perform (c)))
586     {
587       fprintf (stderr,
588                "curl_easy_perform failed: `%s'\n",
589                curl_easy_strerror (errornum));
590       curl_easy_cleanup (c);
591       MHD_stop_daemon (d);
592       return 8388608;
593     }
594   curl_easy_cleanup (c);
595   MHD_stop_daemon (d);
596   if (cbc.pos != 0)
597     return 16777216;
598   if (excess_found)
599     return 33554432;
600   return 0;
601 }
602 
603 
604 int
main(int argc,char * const * argv)605 main (int argc, char *const *argv)
606 {
607   unsigned int errorCount = 0;
608 
609   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
610     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
611   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
612     return 2;
613   errorCount += testInternalGet (0);
614   errorCount += testMultithreadedGet (0);
615   errorCount += testMultithreadedPoolGet (0);
616   errorCount += testUnknownPortGet (0);
617   errorCount += testStopRace (0);
618   errorCount += testExternalGet ();
619   errorCount += testEmptyGet (0);
620   if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_POLL))
621     {
622       errorCount += testInternalGet(MHD_USE_POLL);
623       errorCount += testMultithreadedGet(MHD_USE_POLL);
624       errorCount += testMultithreadedPoolGet(MHD_USE_POLL);
625       errorCount += testUnknownPortGet(MHD_USE_POLL);
626       errorCount += testStopRace(MHD_USE_POLL);
627       errorCount += testEmptyGet(MHD_USE_POLL);
628     }
629   if (MHD_YES == MHD_is_feature_supported(MHD_FEATURE_EPOLL))
630     {
631       errorCount += testInternalGet(MHD_USE_EPOLL_LINUX_ONLY);
632       errorCount += testMultithreadedPoolGet(MHD_USE_EPOLL_LINUX_ONLY);
633       errorCount += testUnknownPortGet(MHD_USE_EPOLL_LINUX_ONLY);
634       errorCount += testEmptyGet(MHD_USE_EPOLL_LINUX_ONLY);
635     }
636   if (errorCount != 0)
637     fprintf (stderr, "Error (code: %u)\n", errorCount);
638   curl_global_cleanup ();
639   return errorCount != 0;       /* 0 == pass */
640 }
641