1748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/*
2748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  This file is part of libmicrohttpd
3748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  Copyright (C) 2007 Christian Grothoff
4748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
5748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  libmicrohttpd is free software; you can redistribute it and/or modify
6748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  it under the terms of the GNU General Public License as published
7748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  by the Free Software Foundation; either version 2, or (at your
8748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  option) any later version.
9748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
10748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  libmicrohttpd is distributed in the hope that it will be useful, but
11748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  WITHOUT ANY WARRANTY; without even the implied warranty of
12748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  General Public License for more details.
14748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
15748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  You should have received a copy of the GNU General Public License
16748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  along with libmicrohttpd; see the file COPYING.  If not, write to the
17748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  Boston, MA 02111-1307, USA.
19748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat*/
20748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
21748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/**
22748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @file test_https_get_parallel.c
23748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @brief  Testcase for libmicrohttpd HTTPS GET operations
24748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @author Sagie Amir
25748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @author Christian Grothoff
26748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */
27748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
28748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "platform.h"
29748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "microhttpd.h"
30748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <sys/stat.h>
31748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <limits.h>
32748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <curl/curl.h>
33748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <pthread.h>
34748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <gcrypt.h>
35748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "tls_test_common.h"
36748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
37748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#if defined(CPU_COUNT) && (CPU_COUNT+0) < 4
38748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#undef CPU_COUNT
39748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#endif
40748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#if !defined(CPU_COUNT)
41748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#define CPU_COUNT 4
42748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#endif
43748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
44748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratextern const char srv_key_pem[];
45748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratextern const char srv_self_signed_cert_pem[];
46748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
47748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint curl_check_version (const char *req_version, ...);
48748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
49748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
50748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/**
51748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * used when spawning multiple threads executing curl server requests
52748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
53748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */
54748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void *
55748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erathttps_transfer_thread_adapter (void *args)
56748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
57748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  static int nonnull;
58748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  struct https_test_data *cargs = args;
59748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  int ret;
60748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
61748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  /* time spread incomming requests */
62748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  usleep ((useconds_t) 10.0 * ((double) rand ()) / ((double) RAND_MAX));
63748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  ret = test_https_transfer (NULL,
64748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat                             cargs->cipher_suite, cargs->proto_version);
65748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  if (ret == 0)
66748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    return NULL;
67748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  return &nonnull;
68748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
69748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
70748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
71748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/**
72748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Test non-parallel requests.
73748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
74748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @return: 0 upon all client requests returning '0', -1 otherwise.
75748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
76748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * TODO : make client_count a parameter - number of curl client threads to spawn
77748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */
78748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic int
79748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erattest_single_client (void *cls, const char *cipher_suite,
80748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat                    int curl_proto_version)
81748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
82748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  void *client_thread_ret;
83748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  struct https_test_data client_args =
84748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    { NULL, cipher_suite, curl_proto_version };
85748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
86748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  client_thread_ret = https_transfer_thread_adapter (&client_args);
87748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  if (client_thread_ret != NULL)
88748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    return -1;
89748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  return 0;
90748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
91748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
92748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
93748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/**
94748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Test parallel request handling.
95748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
96748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @return: 0 upon all client requests returning '0', -1 otherwise.
97748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
98748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * TODO : make client_count a parameter - numver of curl client threads to spawn
99748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */
100748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic int
101748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erattest_parallel_clients (void * cls, const char *cipher_suite,
102748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat                       int curl_proto_version)
103748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
104748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  int i;
105748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  int client_count = (CPU_COUNT - 1);
106748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  void *client_thread_ret;
107748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  pthread_t client_arr[client_count];
108748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  struct https_test_data client_args =
109748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    { NULL, cipher_suite, curl_proto_version };
110748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
111748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  for (i = 0; i < client_count; ++i)
112748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    {
113748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      if (pthread_create (&client_arr[i], NULL,
114748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat                          &https_transfer_thread_adapter, &client_args) != 0)
115748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        {
116748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat          fprintf (stderr, "Error: failed to spawn test client threads.\n");
117748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat          return -1;
118748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        }
119748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    }
120748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
121748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  /* check all client requests fulfilled correctly */
122748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  for (i = 0; i < client_count; ++i)
123748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    {
124748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      if ((pthread_join (client_arr[i], &client_thread_ret) != 0) ||
125748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat          (client_thread_ret != NULL))
126748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        return -1;
127748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    }
128748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
129748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  return 0;
130748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
131748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
132748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
133748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint
134748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratmain (int argc, char *const *argv)
135748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
136748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  unsigned int errorCount = 0;
137748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  const char *aes256_sha = "AES256-SHA";
138748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
139748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  /* initialize random seed used by curl clients */
140748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  unsigned int iseed = (unsigned int) time (NULL);
141748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  srand (iseed);
142748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  if (0 != curl_global_init (CURL_GLOBAL_ALL))
143748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    {
144748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      fprintf (stderr, "Error: %s\n", strerror (errno));
145748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      return -1;
146748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    }
147748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
148748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  if (curl_uses_nss_ssl() == 0)
149748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    aes256_sha = "rsa_aes_256_sha";
150748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#if EPOLL_SUPPORT
151748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  errorCount +=
152748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    test_wrap ("single threaded daemon, single client, epoll", &test_single_client,
153748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               NULL,
154748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG | MHD_USE_EPOLL_LINUX_ONLY,
155748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
156748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
157748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               srv_self_signed_cert_pem, MHD_OPTION_END);
158748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#endif
159748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  errorCount +=
160748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    test_wrap ("single threaded daemon, single client", &test_single_client,
161748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               NULL,
162748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG,
163748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
164748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
165748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               srv_self_signed_cert_pem, MHD_OPTION_END);
166748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#if EPOLL_SUPPORT
167748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  errorCount +=
168748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    test_wrap ("single threaded daemon, parallel clients, epoll",
169748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               &test_parallel_clients, NULL,
170748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG | MHD_USE_EPOLL_LINUX_ONLY,
171748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
172748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
173748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               srv_self_signed_cert_pem, MHD_OPTION_END);
174748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#endif
175748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  errorCount +=
176748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    test_wrap ("single threaded daemon, parallel clients",
177748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               &test_parallel_clients, NULL,
178748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG,
179748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               aes256_sha, CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY,
180748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT,
181748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat               srv_self_signed_cert_pem, MHD_OPTION_END);
182748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
183748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  curl_global_cleanup ();
184748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  return errorCount != 0;
185748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
186