Blame src/testcurl/test_concurrent_stop.c

Packit 875988
/*
Packit 875988
     This file is part of libmicrohttpd
Packit 875988
     Copyright (C) 2007, 2009, 2011, 2015, 2016 Christian Grothoff
Packit 875988
Packit 875988
     libmicrohttpd is free software; you can redistribute it and/or modify
Packit 875988
     it under the terms of the GNU General Public License as published
Packit 875988
     by the Free Software Foundation; either version 3, or (at your
Packit 875988
     option) any later version.
Packit 875988
Packit 875988
     libmicrohttpd is distributed in the hope that it will be useful, but
Packit 875988
     WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 875988
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 875988
     General Public License for more details.
Packit 875988
Packit 875988
     You should have received a copy of the GNU General Public License
Packit 875988
     along with libmicrohttpd; see the file COPYING.  If not, write to the
Packit 875988
     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit 875988
     Boston, MA 02110-1301, USA.
Packit 875988
*/
Packit 875988
Packit 875988
/**
Packit 875988
 * @file test_concurrent_stop.c
Packit 875988
 * @brief test stopping server while concurrent GETs are ongoing
Packit 875988
 * @author Christian Grothoff
Packit 875988
 */
Packit 875988
#include "MHD_config.h"
Packit 875988
#include "platform.h"
Packit 875988
#include <curl/curl.h>
Packit 875988
#include <microhttpd.h>
Packit 875988
#include <stdlib.h>
Packit 875988
#include <string.h>
Packit 875988
#include <time.h>
Packit 875988
#include <pthread.h>
Packit 875988
#include "gauger.h"
Packit 875988
Packit 875988
#ifdef CPU_COUNT
Packit 875988
#undef CPU_COUNT
Packit 875988
#endif
Packit 875988
#define CPU_COUNT 40
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * How many rounds of operations do we do for each
Packit 875988
 * test (total number of requests will be ROUNDS * PAR).
Packit 875988
 */
Packit 875988
#define ROUNDS 50000
Packit 875988
Packit 875988
/**
Packit 875988
 * How many requests do we do in parallel?
Packit 875988
 */
Packit 875988
#define PAR CPU_COUNT
Packit 875988
Packit 875988
/**
Packit 875988
 * Do we use HTTP 1.1?
Packit 875988
 */
Packit 875988
static int oneone;
Packit 875988
Packit 875988
/**
Packit 875988
 * Response to return (re-used).
Packit 875988
 */
Packit 875988
static struct MHD_Response *response;
Packit 875988
Packit 875988
Packit 875988
static size_t
Packit 875988
copyBuffer (void *ptr,
Packit 875988
	    size_t size, size_t nmemb,
Packit 875988
	    void *ctx)
Packit 875988
{
Packit 875988
  (void)ptr;(void)ctx;  /* Unused. Silent compiler warning. */
Packit 875988
  return size * nmemb;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
static int
Packit 875988
ahc_echo (void *cls,
Packit 875988
          struct MHD_Connection *connection,
Packit 875988
          const char *url,
Packit 875988
          const char *method,
Packit 875988
          const char *version,
Packit 875988
          const char *upload_data,
Packit 875988
          size_t *upload_data_size,
Packit 875988
          void **unused)
Packit 875988
{
Packit 875988
  static int ptr;
Packit 875988
  const char *me = cls;
Packit 875988
  int ret;
Packit 875988
  (void)url;(void)version;                      /* Unused. Silent compiler warning. */
Packit 875988
  (void)upload_data;(void)upload_data_size;     /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  if (0 != strcmp (me, method))
Packit 875988
    return MHD_NO;              /* unexpected method */
Packit 875988
  if (&ptr != *unused)
Packit 875988
    {
Packit 875988
      *unused = &pt;;
Packit 875988
      return MHD_YES;
Packit 875988
    }
Packit 875988
  *unused = NULL;
Packit 875988
  ret = MHD_queue_response (connection,
Packit 875988
                            MHD_HTTP_OK,
Packit 875988
                            response);
Packit 875988
  if (ret == MHD_NO)
Packit 875988
    abort ();
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
static void
Packit 875988
clean_curl(void * param)
Packit 875988
{
Packit 875988
  if (param)
Packit 875988
    {
Packit 875988
      CURL * const c = *((CURL **)param);
Packit 875988
      if (c)
Packit 875988
        curl_easy_cleanup (c);
Packit 875988
    }
Packit 875988
}
Packit 875988
Packit 875988
static void *
Packit 875988
thread_gets (void *param)
Packit 875988
{
Packit 875988
  CURL *c;
Packit 875988
  CURLcode errornum;
Packit 875988
  unsigned int i;
Packit 875988
  char * const url = (char*) param;
Packit 875988
  int pth_olst;
Packit 875988
  if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &pth_olst) ||
Packit 875988
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &pth_olst) )
Packit 875988
    {
Packit 875988
      fprintf(stderr,
Packit 875988
              "pthread_setcancelstate()/pthread_setcanceltype() failed.\n");
Packit 875988
      _exit(99);
Packit 875988
    }
Packit 875988
Packit 875988
  for (i=0;i
Packit 875988
    {
Packit 875988
      pthread_testcancel();
Packit 875988
      c = NULL;
Packit 875988
      pthread_cleanup_push(clean_curl, (void*)&c);
Packit 875988
      c = curl_easy_init ();
Packit 875988
      pthread_testcancel();
Packit 875988
      curl_easy_setopt (c, CURLOPT_URL, url);
Packit 875988
      curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
Packit 875988
      curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL);
Packit 875988
      curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
Packit 875988
      curl_easy_setopt (c, CURLOPT_TIMEOUT, 5L);
Packit 875988
      if (oneone)
Packit 875988
        curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
Packit 875988
      else
Packit 875988
        curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
Packit 875988
      curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L);
Packit 875988
      /* NOTE: use of CONNECTTIMEOUT without also
Packit 875988
         setting NOSIGNAL results in really weird
Packit 875988
         crashes on my system! */
Packit 875988
      curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
Packit 875988
      pthread_testcancel();
Packit 875988
      errornum = curl_easy_perform (c);
Packit 875988
      pthread_cleanup_pop (1);
Packit 875988
      if (CURLE_OK != errornum)
Packit 875988
        return NULL;
Packit 875988
    }
Packit 875988
Packit 875988
  return NULL;
Packit 875988
}
Packit 875988
Packit 875988
static void *
Packit 875988
do_gets (void * param)
Packit 875988
{
Packit 875988
  int j;
Packit 875988
  pthread_t par[PAR];
Packit 875988
  char url[64];
Packit 875988
  int port = (int)(intptr_t)param;
Packit 875988
Packit 875988
  sprintf(url, "http://127.0.0.1:%d/hello_world", port);
Packit 875988
Packit 875988
  for (j=0;j
Packit 875988
    {
Packit 875988
      if (0 != pthread_create(&par[j], NULL, &thread_gets, (void*)url))
Packit 875988
        {
Packit 875988
          fprintf(stderr, "pthread_create failed.\n");
Packit 875988
          for (j--; j >= 0; j--)
Packit 875988
            {
Packit 875988
              pthread_cancel(par[j]);
Packit 875988
              pthread_join(par[j], NULL);
Packit 875988
            }
Packit 875988
          _exit(99);
Packit 875988
        }
Packit 875988
    }
Packit 875988
  (void)sleep (1);
Packit 875988
  for (j=0;j
Packit 875988
    {
Packit 875988
      pthread_cancel(par[j]);
Packit 875988
      pthread_join(par[j], NULL);
Packit 875988
    }
Packit 875988
  return NULL;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
pthread_t start_gets(int port)
Packit 875988
{
Packit 875988
  pthread_t tid;
Packit 875988
  if (0 != pthread_create(&tid, NULL, &do_gets, (void*)(intptr_t)port))
Packit 875988
    {
Packit 875988
      fprintf(stderr, "pthread_create failed.\n");
Packit 875988
      _exit(99);
Packit 875988
    }
Packit 875988
  return tid;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
static int
Packit 875988
testMultithreadedGet (int port,
Packit 875988
                      int poll_flag)
Packit 875988
{
Packit 875988
  struct MHD_Daemon *d;
Packit 875988
  pthread_t p;
Packit 875988
Packit 875988
  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG  | poll_flag,
Packit 875988
                        port,
Packit 875988
                        NULL, NULL,
Packit 875988
                        &ahc_echo, "GET",
Packit 875988
                        MHD_OPTION_END);
Packit 875988
  if (d == NULL)
Packit 875988
    return 16;
Packit 875988
  if (0 == port)
Packit 875988
    {
Packit 875988
      const union MHD_DaemonInfo *dinfo;
Packit 875988
      dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
Packit 875988
      if (NULL == dinfo || 0 == dinfo->port)
Packit 875988
        { MHD_stop_daemon (d); return 32; }
Packit 875988
      port = (int)dinfo->port;
Packit 875988
    }
Packit 875988
  p = start_gets (port);
Packit 875988
  (void)sleep (1);
Packit 875988
  MHD_stop_daemon (d);
Packit 875988
  pthread_join (p, NULL);
Packit 875988
  return 0;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
static int
Packit 875988
testMultithreadedPoolGet (int port,
Packit 875988
                          int poll_flag)
Packit 875988
{
Packit 875988
  struct MHD_Daemon *d;
Packit 875988
  pthread_t p;
Packit 875988
Packit 875988
  d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | poll_flag,
Packit 875988
                        port,
Packit 875988
                        NULL, NULL,
Packit 875988
                        &ahc_echo, "GET",
Packit 875988
                        MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
Packit 875988
                        MHD_OPTION_END);
Packit 875988
  if (d == NULL)
Packit 875988
    return 16;
Packit 875988
  if (0 == port)
Packit 875988
    {
Packit 875988
      const union MHD_DaemonInfo *dinfo;
Packit 875988
      dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
Packit 875988
      if (NULL == dinfo || 0 == dinfo->port)
Packit 875988
        { MHD_stop_daemon (d); return 32; }
Packit 875988
      port = (int)dinfo->port;
Packit 875988
    }
Packit 875988
  p = start_gets (port);
Packit 875988
  (void)sleep (1);
Packit 875988
  MHD_stop_daemon (d);
Packit 875988
  pthread_join (p, NULL);
Packit 875988
  return 0;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
int
Packit 875988
main (int argc, char *const *argv)
Packit 875988
{
Packit 875988
  unsigned int errorCount = 0;
Packit 875988
  int port;
Packit 875988
  (void)argc;   /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
Packit 875988
    port = 0;
Packit 875988
  else
Packit 875988
    port = 1142;
Packit 875988
Packit 875988
  oneone = (NULL != strrchr (argv[0], (int) '/')) ?
Packit 875988
    (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
Packit 875988
  if (0 != port && oneone)
Packit 875988
    port += 5;
Packit 875988
  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
Packit 875988
    return 2;
Packit 875988
  response = MHD_create_response_from_buffer (strlen ("/hello_world"),
Packit 875988
					      "/hello_world",
Packit 875988
					      MHD_RESPMEM_MUST_COPY);
Packit 875988
  errorCount += testMultithreadedGet (port, 0);
Packit 875988
  if (0 != port) port++;
Packit 875988
  errorCount += testMultithreadedPoolGet (port, 0);
Packit 875988
  MHD_destroy_response (response);
Packit 875988
  if (errorCount != 0)
Packit 875988
    fprintf (stderr, "Error (code: %u)\n", errorCount);
Packit 875988
  curl_global_cleanup ();
Packit 875988
  return errorCount != 0;       /* 0 == pass */
Packit 875988
}