HomePort
big_data_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 static char *big_data;
37 
38 static int started = 0;
39 static hpd_ws_t *ws = NULL;
40 static struct ev_loop *loop;
41 static struct ev_async exit_watcher;
42 
43 static size_t data_from_curl(char *buffer, size_t buffer_size, size_t nmemb, char **userdata)
44 {
45  *userdata = realloc(*userdata, strlen(*userdata) + buffer_size*nmemb + 1);
46  char *data = &(*userdata)[strlen(*userdata)];
47  memcpy(data, buffer, buffer_size*nmemb);
48  data[buffer_size*nmemb] = '\0';
49 
50  return buffer_size*nmemb;
51 }
52 
53 static size_t data_to_curl(void *ptr, size_t size, size_t nmemb,
54  void *userdata)
55 {
56  size_t *sent = userdata;
57  char *data = &big_data[*sent];
58  char *buf = ptr;
59  size_t copied;
60 
61  // Copy data
62  strncpy(buf, data, size*nmemb);
63 
64  // Calculate how much was copied
65  if (strlen(data) < size*nmemb) {
66  copied = strlen(buf);
67  } else {
68  copied = size*nmemb;
69  }
70 
71  *sent += copied;
72 
73  return copied;
74 }
75 
76 static char* simple_get_request(char* url)
77 {
78  CURL *handle = curl_easy_init();
79  CURLcode c;
80  char* userdata = malloc(sizeof(char));
81  userdata[0] = '\0';
82  size_t sent = 0;
83 
84  if(handle != NULL)
85  {
86  curl_easy_setopt(handle, CURLOPT_URL, url);
87  curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
88  curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, data_from_curl);
89  curl_easy_setopt(handle, CURLOPT_WRITEDATA, &userdata);
90  curl_easy_setopt(handle, CURLOPT_READFUNCTION, data_to_curl);
91  curl_easy_setopt(handle, CURLOPT_READDATA, &sent);
92 #ifdef DEBUG
93  //curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
94 #endif
95  struct curl_slist *chunk = NULL;
96  chunk = curl_slist_append(chunk, "Transfer-Encoding:");
97  curl_easy_setopt(handle, CURLOPT_HTTPHEADER, chunk);
98 
99  if((c = curl_easy_perform(handle)) != CURLE_OK)
100  {
101  fprintf(stderr, "curl_easy_perform failed: %s\n", curl_easy_strerror(c));
102  return "";
103  }
104 
105  curl_slist_free_all(chunk);
106  curl_easy_cleanup(handle);
107  return userdata;
108  }
109  else
110  {
111  perror("Could not initialize curl: ");
112  return "";
113  }
114 }
115 
116 static int basic_get_test(char* url)
117 {
118  char *received = simple_get_request(url);
119  int result = 0;
120 
121  if(strstr(received, big_data) != NULL) {
122  result = 1;
123  } else {
124  printf("The following bad string was received: %s\n", received);
125  }
126  free(received);
127 
128  return result;
129 }
130 
132 static int test_thread()
133 {
134  int testresult;
135  int ret = 0;
136 
137  // Init
138  curl_global_init(CURL_GLOBAL_ALL);
139 
140  // Run test
141  printf("Running tcpd tests\n");
142  testresult = basic_get_test("http://localhost:8080");
143 
144  // Check result
145  if (testresult == 1) {
146  printf("Test succeeded\n");
147  } else {
148  printf("Test failed\n");
149  ret++;
150  }
151 
152  // Clean up
153  curl_global_cleanup();
154 
155  return ret;
156 }
157 
159 static int on_connect(hpd_ws_t *instance,
160  hpd_ws_conn_t *conn, void *ws_ctx, void **data)
161 {
162  char *body = malloc(sizeof(char));
163  body[0] = '\0';
164  *data = body;
165 
166  return 0;
167 }
168 
170 static int on_receive(hpd_ws_t *instance,
171  hpd_ws_conn_t *conn, void *ctx, void **data,
172  const char *buf, size_t len)
173 {
174  char *body = *data, *new;
175  size_t new_len;
176 
177  new_len = strlen(body)+len+1;
178  new = realloc(body, sizeof(char)*new_len);
179  if (new != NULL) {
180  body = new;
181  strncat(body, buf, len);
182  body[new_len-1] = '\0';
183  *data = body;
184  } else {
185  fprintf(stderr, "Reallocation failed\n");
186  }
187 
188  if (strstr(body, "EOF") != NULL) {
189  ws_conn_sendf(conn, "HTTP/1.1 200 OK\r\n\r\n%s", body);
190  ws_conn_close(conn);
191  }
192 
193  return 0;
194 }
195 
197 static int on_disconnect(hpd_ws_t *instance,
198  hpd_ws_conn_t *conn, void *ws_ctx, void **data)
199 {
200  free(*data);
201  return 0;
202 }
203 
205 static void exit_handler(int sig)
206 {
207  fprintf(stderr, "Sending stop signal\n");
208  ev_async_send(loop, &exit_watcher);
209 }
210 
212 static void exit_cb(EV_P_ ev_async *watcher, int revents)
213 {
214  fprintf(stderr, "Stopping tcpd\n");
215  // Stop tcpd
216  if (ws != NULL) {
217  ws_stop(ws);
218  ws_destroy(ws);
219  }
220 
221  ev_break(loop, EVBREAK_ALL);
222 }
223 
225 static void *webserver_thread(void *arg)
226 {
227  // The event loop for the tcpd to run on
228  loop = EV_DEFAULT;
229 
230  // Add a watcher to stop it again
231  ev_async_init(&exit_watcher, exit_cb);
232  ev_async_start(loop, &exit_watcher);
233 
234  // Settings for the tcpd
235  struct ws_settings settings = WS_SETTINGS_DEFAULT;
236  settings.port = HPD_TCPD_P_HTTP_ALT;
237  settings.on_connect = on_connect;
238  settings.on_receive = on_receive;
239  settings.on_disconnect = on_disconnect;
240 
241  // Inform if we have been built with debug flag
242 #ifdef DEBUG
243  printf("Debugging is set\n");
244 #endif
245 
246  // Register signals for correctly exiting
247  signal(SIGINT, exit_handler);
248  signal(SIGTERM, exit_handler);
249 
250  // Create tcpd
251  ws = ws_create(&settings, loop);
252  ws_start(ws);
253 
254  // Start the event loop and tcpd
255  started = 1;
256  ev_run(loop, 0);
257 
258  return NULL;
259 }
260 
262 int main(int argc, char *argv[])
263 {
264  int stat;
265  pthread_t server_thread;
266 
267  unsigned int i, size = 1024*1024;
268  big_data = malloc(sizeof(char)*size);
269  for (i = 0; i < size; i++) {
270  char c = rand() % ('z' - 'a' + 1) + 'a';
271  big_data[i] = c;
272  }
273  big_data[size-4] = 'E';
274  big_data[size-3] = 'O';
275  big_data[size-2] = 'F';
276  big_data[size-1] = '\0';
277 
278  // Start tcpd and wait for it to start
279  pthread_create(&server_thread, NULL, webserver_thread, NULL);
280  // TODO Someone needs too add a timeout here...
281  while (!started);
282 
283  // Run test
284  stat = test_thread();
285 
286  // Stop tcpd properly
287  exit_handler(0);
288  pthread_join(server_thread, NULL);
289 
290  // Return result of test
291  return stat;
292 }
struct up * instance
static void exit_handler(int sig)
Handle correct exiting.
static struct ev_async exit_watcher
Definition: big_data_test.c:41
static char * big_data
Definition: big_data_test.c:36
static void * webserver_thread(void *arg)
Webserver thread.
static int on_connect(hpd_ws_t *instance, hpd_ws_conn_t *conn, void *ws_ctx, void **data)
On connect callback for tcpd.
char * url
free(data.url)
static int basic_get_test(char *url)
static int on_disconnect(hpd_ws_t *instance, hpd_ws_conn_t *conn, void *ws_ctx, void **data)
On disconnect callback for tcpd.
static hpd_ws_t * ws
Definition: big_data_test.c:39
static int on_receive(hpd_ws_t *instance, hpd_ws_conn_t *conn, void *ctx, void **data, const char *buf, size_t len)
On receive callback for tcpd.
static char * simple_get_request(char *url)
Definition: big_data_test.c:76
int main(int argc, char *argv[])
Main function.
struct data data
static int started
Definition: big_data_test.c:38
static struct ev_loop * loop
Definition: big_data_test.c:40
static size_t data_from_curl(char *buffer, size_t buffer_size, size_t nmemb, char **userdata)
Definition: big_data_test.c:43
static void exit_cb(EV_P_ ev_async *watcher, int revents)
Exit callback for async watcher (Webserver)
static size_t data_to_curl(void *ptr, size_t size, size_t nmemb, void *userdata)
Definition: big_data_test.c:53
static int test_thread()
Test thread.