HomePort
load_test.c
Go to the documentation of this file.
1 /*
2  * Copyright 2011 Aalborg University. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  * conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  * of conditions and the following disclaimer in the documentation and/or other materials
12  * provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY Aalborg University ''AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Aalborg University OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those of the
25  * authors and should not be interpreted as representing official policies, either expressed
26  */
27 
28 #include "webserver.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ev.h>
33 #include <curl/curl.h>
34 #include <pthread.h>
35 
36 #define NTHREADS 16
37 
38 struct mt_args {
39  char *url;
40  char* contains;
41  unsigned long assaults;
42 };
43 
45 static pthread_mutex_t lock;
46 static pthread_t threadID[NTHREADS];
47 static int started = 0;
48 static hpd_ws_t *ws = NULL;
49 
50 static void init_libcurl()
51 {
52  curl_global_init(CURL_GLOBAL_ALL);
53 }
54 
55 static void cleanup_libcurl()
56 {
57  curl_global_cleanup();
58 }
59 
60 static size_t data_from_curl(char *buffer, size_t buffer_size, size_t nmemb, char **userdata)
61 {
62  *userdata = malloc(buffer_size*nmemb + 1);
63  memcpy(*userdata, buffer, buffer_size*nmemb);
64  (*userdata)[buffer_size*nmemb] = '\0';
65 
66  return buffer_size*nmemb;
67 }
68 
69 static char* simple_get_request(char* url)
70 {
71  CURL *handle = curl_easy_init();
72  CURLcode c;
73  char* userdata = "";
74 
75  if(handle != NULL)
76  {
77  curl_easy_setopt(handle, CURLOPT_URL, url);
78  curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &data_from_curl);
79  curl_easy_setopt(handle, CURLOPT_WRITEDATA, &userdata);
80 
81  if((c = curl_easy_perform(handle)) != CURLE_OK)
82  {
83  fprintf(stderr, "curl_easy_perform failed: %s\n", curl_easy_strerror(c));
84  return "";
85  }
86 
87  curl_easy_cleanup(handle);
88  return userdata;
89  }
90  else
91  {
92  perror("Could not initialize curl: ");
93  return "";
94  }
95 }
96 
97 static void init_tests()
98 {
99  init_libcurl();
100 }
101 
102 static void cleanup_tests()
103 {
104  cleanup_libcurl();
105 }
106 
107 static int basic_get_contains_test(char* url, char* contains)
108 {
109  char *received = simple_get_request(url);
110  int result = 0;
111 
112  if(strstr(received, contains) != NULL)
113  {
114  result = 1;
115  }
116  else
117  {
118  printf("The following bad string was received: %s\n", received);
119  }
120  free(received);
121 
122  return result;
123 }
124 
126 {
127  pthread_mutex_lock(&lock);
129  pthread_mutex_unlock(&lock);
130 }
131 
132 static void *get_mt_loop(void *args)
133 {
134  struct mt_args *arguments = (struct mt_args *)args;
135  unsigned long i;
136  for(i = 0; i<arguments->assaults; i++)
137  {
138  if(basic_get_contains_test(arguments->url,arguments->contains) == 0)
139  {
141  break;
142  }
143  }
144 
145  return NULL;
146 }
147 
149 {
150  int threads = 0;
151  int err = 0;
153 
154  struct mt_args *args = malloc(sizeof(struct mt_args));
155  args->url = url;
156  args->contains = contains;
157  args->assaults = 500;
158 
159  while(threads < NTHREADS)
160  {
161  err=pthread_create(&(threadID[threads]), NULL, &get_mt_loop, (void*)args);
162  if(err != 0)
163  printf("\nError creating thread: %i %i %s",threads, err,strerror(err));
164  threads++;
165  }
166 
167  threads = 0;
168  while(threads < NTHREADS)
169  {
170  pthread_join((threadID[threads]), NULL);
171  threads++;
172  }
173 
174  free(args);
175  return multithreaded_results;
176 }
177 
178 static int test_thread()
179 {
180  int testresult;
181  int ret =1;
182  init_tests();
183 
184  printf("Running tcpd tests:\n");
185 
186  printf("\tBasic connection test: ");
187  testresult = basic_get_contains_test("http://localhost:8080", "Hello");
188  if(testresult == 1)
189  printf("Success\n");
190  else
191  printf("Failed\n");
192  ret += testresult;
193 
194 
195  printf("\tBasic multithreaded stress test: ");
196  testresult = basic_get_multithreaded_stress_test("http://localhost:8080", "Hello");
197  if(testresult == 1)
198  printf("Sucess\n");
199  else
200  printf("Failed\n");
201  ret += testresult;
202 
203 
204  cleanup_tests();
205  printf("\nDone.\n");
206 
207  return ret;
208 }
209 
210 static int on_receive(hpd_ws_t *instance, hpd_ws_conn_t *conn, void *ctx, void **data,
211  const char *buf, size_t len)
212 {
213  ws_conn_sendf(conn, "HTTP/1.1 200 OK\r\n\r\nHello");
214  ws_conn_close(conn);
215  return 0;
216 }
217 
218 // TODO Move this up to top of file
219 static struct ev_loop *loop;
220 static struct ev_async exit_watcher;
221 
222 // Handle correct exiting
223 static void exit_handler(int sig)
224 {
225  fprintf(stderr, "Sending stop signal\n");
226  ev_async_send(loop, &exit_watcher);
227 }
228 
229 static void exit_cb(EV_P_ ev_async *watcher, int revents)
230 {
231  fprintf(stderr, "Stopping tcpd\n");
232  // Stop tcpd
233  if (ws != NULL) {
234  ws_stop(ws);
235  ws_destroy(ws);
236  }
237 
238  ev_break(loop, EVBREAK_ALL);
239 }
240 
241 static void *webserver_thread(void *arg)
242 {
243  // The event loop for the tcpd to run on
244  loop = EV_DEFAULT;
245 
246  // Add a watcher to stop it again
247  ev_async_init(&exit_watcher, exit_cb);
248  ev_async_start(loop, &exit_watcher);
249 
250  // Settings for the tcpd
251  struct ws_settings settings = WS_SETTINGS_DEFAULT;
252  settings.port = HPD_TCPD_P_HTTP_ALT;
253  settings.on_receive = on_receive;
254 
255  // Inform if we have been built with debug flag
256 #ifdef DEBUG
257  printf("Debugging is set\n");
258 #endif
259 
260  // Register signals for correctly exiting
261  signal(SIGINT, exit_handler);
262  signal(SIGTERM, exit_handler);
263 
264  // Create tcpd
265  ws = ws_create(&settings, loop);
266  ws_start(ws);
267 
268  // Start the event loop and tcpd
269  started = 1;
270  ev_run(loop, 0);
271 
272  return NULL;
273 }
274 
275 int main(int argc, char *argv[])
276 {
277  int stat;
278  pthread_t server_thread;
279  pthread_create(&server_thread, NULL, webserver_thread, NULL);
280 
281  // TODO Someone needs too add a timeout here...
282  while (!started);
283 
284  stat = test_thread();
285  exit_handler(0);
286 
287  pthread_join(server_thread, NULL);
288 
289  if (stat == 0) return 1;
290  else return 0;
291 }
static size_t data_from_curl(char *buffer, size_t buffer_size, size_t nmemb, char **userdata)
Definition: load_test.c:60
#define NTHREADS
Definition: load_test.c:36
struct up * instance
int main(int argc, char *argv[])
Definition: load_test.c:275
static int test_thread()
Definition: load_test.c:178
char * url
free(data.url)
static void init_tests()
Definition: load_test.c:97
static void * get_mt_loop(void *args)
Definition: load_test.c:132
unsigned long assaults
Definition: load_test.c:41
static void cleanup_libcurl()
Definition: load_test.c:55
static int on_receive(hpd_ws_t *instance, hpd_ws_conn_t *conn, void *ctx, void **data, const char *buf, size_t len)
Definition: load_test.c:210
static int started
Definition: load_test.c:47
static int multithreaded_results
Definition: load_test.c:44
static char * simple_get_request(char *url)
Definition: load_test.c:69
char * url
Definition: load_test.c:39
static int basic_get_multithreaded_stress_test(char *url, char *contains)
Definition: load_test.c:148
static int basic_get_contains_test(char *url, char *contains)
Definition: load_test.c:107
static void init_libcurl()
Definition: load_test.c:50
static void cleanup_tests()
Definition: load_test.c:102
static void set_bad_multithreaded_result()
Definition: load_test.c:125
static struct ev_async exit_watcher
Definition: load_test.c:220
static void * webserver_thread(void *arg)
Definition: load_test.c:241
char * contains
Definition: load_test.c:40
static void exit_cb(EV_P_ ev_async *watcher, int revents)
Definition: load_test.c:229
static pthread_t threadID[NTHREADS]
Definition: load_test.c:46
static void exit_handler(int sig)
Definition: load_test.c:223
static struct ev_loop * loop
Definition: load_test.c:219
static hpd_ws_t * ws
Definition: load_test.c:48
static pthread_mutex_t lock
Definition: load_test.c:45