libasyncd
ad_server.c
Go to the documentation of this file.
1 /******************************************************************************
2  * libasyncd
3  *
4  * Copyright (c) 2014 Seungyoung Kim.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *****************************************************************************/
28 
29 /**
30  * Main core logic of the server implementation.
31  *
32  * @file ad_server.c
33  */
34 
35 #include <stdbool.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <arpa/inet.h>
39 #include <netinet/in.h>
40 #include <errno.h>
41 #include <assert.h>
42 #include <sys/un.h>
43 #include <sys/socket.h>
44 #include <event2/event.h>
45 #include <event2/bufferevent.h>
46 #include <event2/bufferevent_ssl.h>
47 #include <event2/thread.h>
48 #include <event2/listener.h>
49 #include <openssl/ssl.h>
50 #include <openssl/rand.h>
51 #include <openssl/conf.h>
52 #include <openssl/engine.h>
53 #include <openssl/err.h>
54 #include "macro.h"
55 #include "qlibc/qlibc.h"
56 #include "ad_server.h"
57 
58 #ifdef __linux__
59 #include <sys/eventfd.h>
60 #else
61 #include <sys/event.h>
62 #endif
63 
64 #ifndef _DOXYGEN_SKIP
65 /*
66  * User callback hook container.
67  */
68 typedef struct ad_hook_s ad_hook_t;
69 struct ad_hook_s {
70  char *method;
71  ad_callback cb;
72  void *userdata;
73 };
74 
75 /*
76  * Local functions.
77  */
78 static int notify_loopexit(ad_server_t *server);
79 static void notify_cb(struct bufferevent *buffer, void *userdata);
80 static void *server_loop(void *instance);
81 static void close_server(ad_server_t *server);
82 static void libevent_log_cb(int severity, const char *msg);
83 static int set_undefined_options(ad_server_t *server);
84 static SSL_CTX *init_ssl(const char *cert_path, const char *pkey_path);
85 static void listener_cb(struct evconnlistener *listener,
86  evutil_socket_t evsocket, struct sockaddr *sockaddr,
87  int socklen, void *userdata);
88 static ad_conn_t *conn_new(ad_server_t *server, struct bufferevent *buffer);
89 static void conn_reset(ad_conn_t *conn);
90 static void conn_free(ad_conn_t *conn);
91 static void conn_read_cb(struct bufferevent *buffer, void *userdata) ;
92 static void conn_write_cb(struct bufferevent *buffer, void *userdata);
93 static void conn_event_cb(struct bufferevent *buffer, short what, void *userdata);
94 static void conn_cb(ad_conn_t *conn, int event);
95 static int call_hooks(short event, ad_conn_t *conn);
96 static void *set_userdata(ad_conn_t *conn, int index, const void *userdata, ad_userdata_free_cb free_cb);
97 static void *get_userdata(ad_conn_t *conn, int index);
98 
99 /*
100  * Local variables.
101  */
102 static bool initialized = false;
103 #endif
104 
105 /*
106  * Global variables.
107  */
109 
110 /**
111  * Set debug output level.
112  *
113  * @param debug_level debug output level. 0 to disable.
114  *
115  * @return previous debug level.
116  *
117  * @note
118  * debug_level:
119  * AD_LOG_DISABLE
120  * AD_LOG_ERROR
121  * AD_LOG_WARN (default)
122  * AD_LOG_INFO
123  * AD_LOG_DEBUG
124  * AD_LOG_DEBUG2
125  */
126 enum ad_log_e ad_log_level(enum ad_log_e log_level) {
127  int prev = _ad_log_level;
128  _ad_log_level = log_level;
129  return prev;
130 }
131 
132 /**
133  * Create a server object.
134  */
136  if (initialized) {
137  initialized = true;
138  //evthread_use_pthreads();
139  }
140 
141  ad_server_t *server = NEW_OBJECT(ad_server_t);
142  if (server == NULL) {
143  return NULL;
144  }
145 
146  // Initialize instance.
147  server->options = qhashtbl(0, 0);
148  server->stats = qhashtbl(100, QHASHTBL_THREADSAFE);
149  server->hooks = qlist(0);
150  if (server->options == NULL || server->stats == NULL || server->hooks == NULL) {
151  ad_server_free(server);
152  return NULL;
153  }
154 
155  DEBUG("Created a server object.");
156  return server;
157 }
158 
159 /**
160  * Start server.
161  *
162  * @return 0 if successful, otherwise -1.
163  */
165  DEBUG("Starting a server.");
166 
167  // Set default options that were not set by user..
168  set_undefined_options(server);
169 
170  // Hookup libevent's log message.
171  if (_ad_log_level >= AD_LOG_DEBUG) {
172  event_set_log_callback(libevent_log_cb);
173  if (_ad_log_level >= AD_LOG_DEBUG2) {
174  event_enable_debug_mode();
175  }
176  }
177 
178  // Parse addr
179  int port = ad_server_get_option_int(server, "server.port");
180  char *addr = ad_server_get_option(server, "server.addr");
181  struct sockaddr *sockaddr = NULL;
182  size_t sockaddr_len = 0;
183  if (addr[0] == '/') { // Unix socket.
184  struct sockaddr_un unixaddr;
185  bzero((void *) &unixaddr, sizeof(struct sockaddr_un));
186  if (strlen(addr) >= sizeof(unixaddr.sun_path)) {
187  errno = EINVAL;
188  DEBUG("Too long unix socket name. '%s'", addr);
189  return -1;
190  }
191  unixaddr.sun_family = AF_UNIX;
192  strcpy(unixaddr.sun_path, addr); // no need of strncpy()
193  sockaddr = (struct sockaddr *) &unixaddr;
194  sockaddr_len = sizeof(unixaddr);
195  } else if (strstr(addr, ":")) { // IPv6
196  struct sockaddr_in6 ipv6addr;
197  bzero((void *) &ipv6addr, sizeof(struct sockaddr_in6));
198  ipv6addr.sin6_family = AF_INET6;
199  ipv6addr.sin6_port = htons(port);
200  evutil_inet_pton(AF_INET6, addr, &ipv6addr.sin6_addr);
201  sockaddr = (struct sockaddr *) &ipv6addr;
202  sockaddr_len = sizeof(ipv6addr);
203  } else { // IPv4
204  struct sockaddr_in ipv4addr;
205  bzero((void *) &ipv4addr, sizeof(struct sockaddr_in));
206  ipv4addr.sin_family = AF_INET;
207  ipv4addr.sin_port = htons(port);
208  ipv4addr.sin_addr.s_addr =
209  (IS_EMPTY_STR(addr)) ? INADDR_ANY : inet_addr(addr);
210  sockaddr = (struct sockaddr *) &ipv4addr;
211  sockaddr_len = sizeof(ipv4addr);
212  }
213 
214  // SSL
215  if (!server->sslctx && ad_server_get_option_int(server, "server.enable_ssl")) {
216  char *cert_path = ad_server_get_option(server, "server.ssl_cert");
217  char *pkey_path = ad_server_get_option(server, "server.ssl_pkey");
218  server->sslctx = init_ssl(cert_path, pkey_path);
219  if (server->sslctx == NULL) {
220  ERROR("Couldn't load certificate file(%s) or private key file(%s).",
221  cert_path, pkey_path);
222  return -1;
223  }
224  DEBUG("SSL Initialized.");
225  }
226 
227  // Bind
228  if (! server->evbase) {
229  server->evbase = event_base_new();
230  if (! server->evbase) {
231  ERROR("Failed to create a new event base.");
232  return -1;
233  }
234  }
235 
236  // Create a eventfd for notification channel.
237 #ifdef __linux__
238  int notifyfd = eventfd(0, 0);
239 #else
240  int notifyfd = kqueue();
241 #endif
242  server->notify_buffer = bufferevent_socket_new(server->evbase, notifyfd, BEV_OPT_CLOSE_ON_FREE);
243  bufferevent_setcb(server->notify_buffer, NULL, notify_cb, NULL, server);
244 
245  if (! server->listener) {
246  server->listener = evconnlistener_new_bind(
247  server->evbase, listener_cb, (void *)server,
248  LEV_OPT_THREADSAFE | LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
249  ad_server_get_option_int(server, "server.backlog"),
250  sockaddr, sockaddr_len);
251  if (! server->listener) {
252  ERROR("Failed to bind on %s:%d", addr, port);
253  return -1;
254  }
255  }
256 
257  // Listen
258  INFO("Listening on %s:%d%s", addr, port, ((server->sslctx) ? " (SSL)" : ""));
259 
260  int exitstatus = 0;
261  if (ad_server_get_option_int(server, "server.thread")) {
262  DEBUG("Launching server as a thread.")
263  server->thread = NEW_OBJECT(pthread_t);
264  pthread_create(server->thread, NULL, &server_loop, (void *)server);
265  //pthread_detach(server->thread);
266  } else {
267  int *retval = server_loop(server);
268  exitstatus = *retval;
269  free(retval);
270 
271  close_server(server);
272  if (ad_server_get_option_int(server, "server.free_on_stop")) {
273  ad_server_free(server);
274  }
275  }
276 
277  return exitstatus;
278 }
279 
280 /**
281  * Stop server.
282  *
283  * This call is be used to stop a server from different thread.
284  *
285  * @return 0 if successful, otherwise -1.
286  */
288  DEBUG("Send loopexit notification.");
289  notify_loopexit(server);
290  sleep(1);
291 
292  if (ad_server_get_option_int(server, "server.thread")) {
293  close_server(server);
294  if (ad_server_get_option_int(server, "server.free_on_stop")) {
295  ad_server_free(server);
296  }
297  }
298 }
299 
300 /**
301  * Release server object and all the resources.
302  */
304  if (server == NULL) return;
305 
306  int thread = ad_server_get_option_int(server, "server.thread");
307  if (thread && server->thread) {
308  notify_loopexit(server);
309  sleep(1);
310  close_server(server);
311  }
312 
313  if (server->evbase) {
314  event_base_free(server->evbase);
315  }
316 
317  if (server->sslctx) {
318  SSL_CTX_free(server->sslctx);
319  ERR_clear_error();
320  ERR_remove_state(0);
321  }
322 
323  if (server->options) {
324  server->options->free(server->options);
325  }
326  if (server->stats) {
327  server->stats->free(server->stats);
328  }
329  if (server->hooks) {
330  qlist_t *tbl = server->hooks;
331  ad_hook_t *hook;
332  while ((hook = tbl->popfirst(tbl, NULL))) {
333  if (hook->method) free(hook->method);
334  free(hook);
335  }
336  server->hooks->free(server->hooks);
337  }
338  free(server);
339  DEBUG("Server terminated.");
340 }
341 
342 /**
343  * Clean up all the global objects.
344  *
345  * This will make memory-leak checkers happy.
346  * There are globally shared resources in libevent and openssl and
347  * it's usually not a problem since they don't grow but having these
348  * can confuse some debugging tools into thinking as memory leak.
349  * If you need to make sure that libasyncd has released all internal
350  * library-global data structures, call this.
351  */
353  // Libevent related.
354  //libevent_global_shutdown(); // From libevent v2.1
355 
356  // OpenSSL related.
357  ENGINE_cleanup();
358  CONF_modules_free();
359  ERR_free_strings();
360  EVP_cleanup();
361  CRYPTO_cleanup_all_ex_data();
362  sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
363 }
364 
365 /**
366  * Set server option.
367  *
368  * @see AD_SERVER_OPTIONS
369  */
370 void ad_server_set_option(ad_server_t *server, const char *key, const char *value) {
371  server->options->putstr(server->options, key, value);
372 }
373 
374 /**
375  * Retrieve server option.
376  */
377 char *ad_server_get_option(ad_server_t *server, const char *key) {
378  return server->options->getstr(server->options, key, false);
379 }
380 
381 /**
382  * Retrieve server option in integer format.
383  */
384 int ad_server_get_option_int(ad_server_t *server, const char *key) {
385  char *value = ad_server_get_option(server, key);
386  return (value) ? atoi(value) : 0;
387 }
388 
389 /**
390  * Helper method for creating minimal OpenSSL SSL_CTX object.
391  *
392  * @param cert_path path to a PEM encoded certificate file
393  * @param pkey_path path to a PEM encoded private key file
394  *
395  * @return newly allocated SSL_CTX object or NULL on failure
396  *
397  * @note
398  * This function initializes SSL_CTX with minimum default with
399  * "SSLv23_server_method" which will make the server understand
400  * SSLv2, SSLv3, and TLSv1 protocol.
401  *
402  * @see ad_server_set_ssl_ctx()
403  */
404 SSL_CTX *ad_server_ssl_ctx_create_simple(const char *cert_path,
405  const char *pkey_path) {
406 
407  SSL_CTX *sslctx = SSL_CTX_new(SSLv23_server_method());
408  if (! SSL_CTX_use_certificate_file(sslctx, cert_path, SSL_FILETYPE_PEM) ||
409  ! SSL_CTX_use_PrivateKey_file(sslctx, pkey_path, SSL_FILETYPE_PEM)) {
410 
411  ERROR("Couldn't load certificate file(%s) or private key file(%s).",
412  cert_path, pkey_path);
413 
414  return NULL;
415  }
416 
417  return sslctx;
418 }
419 
420 /**
421  * Attach OpenSSL SSL_CTX to the server.
422  *
423  * @param server a valid server instance
424  * @param sslctx allocated and configured SSL_CTX object
425  *
426  * @note
427  * This function attached SSL_CTX object to the server causing it to
428  * communicate over SSL. Use ad_server_ssl_ctx_create_simple() to
429  * quickly create a simple SSL_CTX object or make your own with OpenSSL
430  * directly. This function must never be called when ad_server is running.
431  *
432  * @see ad_server_ssl_ctx_create_simple()
433  */
434 void ad_server_set_ssl_ctx(ad_server_t *server, SSL_CTX *sslctx) {
435 
436  if (server->sslctx) {
437  SSL_CTX_free(server->sslctx);
438  }
439 
440  server->sslctx = sslctx;
441 }
442 
443 /**
444  * Get OpenSSL SSL_CTX object.
445  *
446  * @param server a valid server instance
447  * @return SSL_CTX object, NULL if not enabled.
448  *
449  * @note
450  * As a general rule the returned SSL_CTX object must not be modified
451  * while server is running as it may cause unpredictable results.
452  * However, it is safe to use it for reading SSL statistics.
453  */
455  return server->sslctx;
456 }
457 
458 /**
459  * Return internal statistic counter map.
460  */
461 qhashtbl_t *ad_server_get_stats(ad_server_t *server, const char *key) {
462  return server->stats;
463 }
464 
465 /**
466  * Register user hook.
467  */
468 void ad_server_register_hook(ad_server_t *server, ad_callback cb, void *userdata) {
469  ad_server_register_hook_on_method(server, NULL, cb, userdata);
470 }
471 
472 /**
473  * Register user hook on method name.
474  */
475 void ad_server_register_hook_on_method(ad_server_t *server, const char *method, ad_callback cb, void *userdata) {
476  ad_hook_t hook;
477  bzero((void *)&hook, sizeof(ad_hook_t));
478  hook.method = (method) ? strdup(method) : NULL;
479  hook.cb = cb;
480  hook.userdata = userdata;
481 
482  server->hooks->addlast(server->hooks, (void *)&hook, sizeof(ad_hook_t));
483 }
484 
485 /**
486  * Attach userdata into the connection.
487  *
488  * @return previous userdata;
489  */
490 void *ad_conn_set_userdata(ad_conn_t *conn, const void *userdata, ad_userdata_free_cb free_cb) {
491  return set_userdata(conn, 0, userdata, free_cb);
492 }
493 
494 /**
495  * Get userdata attached in the connection.
496  *
497  * @return previous userdata;
498  */
500  return get_userdata(conn, 0);
501 }
502 
503 /**
504  * Set extra userdata into the connection.
505  *
506  * @return previous userdata;
507  *
508  * @note
509  * Extra userdata is for default protocol handler such as ad_http_handler to
510  * provide higher abstraction. End users should always use only ad_conn_set_userdata()
511  * to avoid any conflict with default handlers.
512  */
513 void *ad_conn_set_extra(ad_conn_t *conn, const void *extra, ad_userdata_free_cb free_cb) {
514  return set_userdata(conn, 1, extra, free_cb);
515 }
516 
517 /**
518  * Get extra userdata attached in this connection.
519  */
521  return get_userdata(conn, 1);
522 }
523 
524 /**
525  * Set method name on this connection.
526  *
527  * Once the method name is set, hooks registered by ad_server_register_hook_on_method()
528  * will be called if method name matches with the registered name.
529  *
530  * @see ad_server_register_hook_on_method()
531  */
532 void ad_conn_set_method(ad_conn_t *conn, char *method) {
533  char *prev = conn->method;
534  conn->method = (method != NULL) ? strdup(method) : NULL;
535  if (prev) {
536  free(prev);
537  }
538 }
539 
540 /**
541  * Return socket file descriptor associated with a connection.
542  */
544  return bufferevent_getfd(conn->buffer);
545 }
546 
547 /******************************************************************************
548  * Private internal functions.
549  *****************************************************************************/
550 #ifndef _DOXYGEN_SKIP
551 
552 /**
553  * If there's no event, loopbreak or loopexit call won't work until one more
554  * event arrived. So we use eventfd as a internal notification channel to let
555  * server get out of the loop without waiting for an event.
556  */
557 static int notify_loopexit(ad_server_t *server) {
558  uint64_t x = 0;
559  return bufferevent_write(server->notify_buffer, &x, sizeof(uint64_t));
560 }
561 
562 static void notify_cb(struct bufferevent *buffer, void *userdata) {
563  ad_server_t *server = (ad_server_t *)userdata;
564  event_base_loopexit(server->evbase, NULL);
565  DEBUG("Existing loop.");
566 }
567 
568 static void *server_loop(void *instance) {
569  ad_server_t *server = (ad_server_t *)instance;
570 
571  int *retval = NEW_OBJECT(int);
572  DEBUG("Loop start");
573  event_base_loop(server->evbase, 0);
574  DEBUG("Loop finished");
575  *retval = (event_base_got_break(server->evbase)) ? -1 : 0;
576 
577  return retval;
578 }
579 
580 static void close_server(ad_server_t *server) {
581  DEBUG("Closing server.");
582 
583  if (server->notify_buffer) {
584  bufferevent_free(server->notify_buffer);
585  server->notify_buffer = NULL;
586  }
587 
588  if (server->listener) {
589  evconnlistener_free(server->listener);
590  server->listener = NULL;
591  }
592 
593  if (server->thread) {
594  void *retval = NULL;
595  DEBUG("Waiting server's last loop to finish.");
596  pthread_join(*(server->thread), &retval);
597  free(retval);
598  free(server->thread);
599  server->thread = NULL;
600  }
601  INFO("Server closed.");
602 }
603 
604 static void libevent_log_cb(int severity, const char *msg) {
605  switch(severity) {
606  case _EVENT_LOG_MSG : {
607  INFO("%s", msg);
608  break;
609  }
610  case _EVENT_LOG_WARN : {
611  WARN("%s", msg);
612  break;
613  }
614  case _EVENT_LOG_ERR : {
615  ERROR("%s", msg);
616  break;
617  }
618  default : {
619  DEBUG("%s", msg);
620  break;
621  }
622  }
623 }
624 
625 // Set default options that were not set by user..
626 static int set_undefined_options(ad_server_t *server) {
627  int newentries = 0;
628  char *default_options[][2] = AD_SERVER_OPTIONS;
629  for (int i = 0; ! IS_EMPTY_STR(default_options[i][0]); i++) {
630  if (! ad_server_get_option(server, default_options[i][0])) {
631  ad_server_set_option(server, default_options[i][0], default_options[i][1]);
632  newentries++;
633  }
634  DEBUG("%s=%s", default_options[i][0], ad_server_get_option(server, default_options[i][0]));
635  }
636  return newentries;
637 }
638 
639 static SSL_CTX *init_ssl(const char *cert_path, const char *pkey_path) {
640  SSL_CTX *sslctx = SSL_CTX_new(SSLv23_server_method());
641  if (! SSL_CTX_use_certificate_file(sslctx, cert_path, SSL_FILETYPE_PEM) ||
642  ! SSL_CTX_use_PrivateKey_file(sslctx, pkey_path, SSL_FILETYPE_PEM)) {
643  return NULL;
644  }
645  return sslctx;
646 }
647 
648 static void listener_cb(struct evconnlistener *listener, evutil_socket_t socket,
649  struct sockaddr *sockaddr, int socklen, void *userdata) {
650  DEBUG("New connection.");
651  ad_server_t *server = (ad_server_t *)userdata;
652 
653  // Create a new buffer.
654  struct bufferevent *buffer = NULL;
655  if (server->sslctx) {
656  buffer = bufferevent_openssl_socket_new(server->evbase, socket,
657  SSL_new(server->sslctx),
658  BUFFEREVENT_SSL_ACCEPTING,
659  BEV_OPT_CLOSE_ON_FREE);
660  } else {
661  buffer = bufferevent_socket_new(server->evbase, socket, BEV_OPT_CLOSE_ON_FREE);
662  }
663  if (buffer == NULL) goto error;
664 
665  // Set read timeout.
666  int timeout = ad_server_get_option_int(server, "server.timeout");
667  if (timeout > 0) {
668  struct timeval tm;
669  bzero((void *)&tm, sizeof(struct timeval));
670  tm.tv_sec = timeout;
671  bufferevent_set_timeouts(buffer, &tm, NULL);
672  }
673 
674  // Create a connection.
675  void *conn = conn_new(server, buffer);
676  if (! conn) goto error;
677 
678  return;
679 
680  error:
681  if (buffer) bufferevent_free(buffer);
682  ERROR("Failed to create a connection handler.");
683  event_base_loopbreak(server->evbase);
684  server->errcode = ENOMEM;
685 }
686 
687 static ad_conn_t *conn_new(ad_server_t *server, struct bufferevent *buffer) {
688  if (server == NULL || buffer == NULL) {
689  return NULL;
690  }
691 
692  // Create a new connection container.
693  ad_conn_t *conn = NEW_OBJECT(ad_conn_t);
694  if (conn == NULL) return NULL;
695 
696  // Initialize with default values.
697  conn->server = server;
698  conn->buffer = buffer;
699  conn->in = bufferevent_get_input(buffer);
700  conn->out = bufferevent_get_output(buffer);
701  conn_reset(conn);
702 
703  // Bind callback
704  bufferevent_setcb(buffer, conn_read_cb, conn_write_cb, conn_event_cb, (void *)conn);
705  bufferevent_setwatermark(buffer, EV_WRITE, 0, 0);
706  bufferevent_enable(buffer, EV_WRITE);
707  bufferevent_enable(buffer, EV_READ);
708 
709  // Run callbacks with AD_EVENT_INIT event.
710  conn->status = call_hooks(AD_EVENT_INIT | AD_EVENT_WRITE, conn);
711 
712  return conn;
713 }
714 
715 static void conn_reset(ad_conn_t *conn) {
716  conn->status = AD_OK;
717 
718  for(int i = 0; i < AD_NUM_USERDATA; i++) {
719  if (conn->userdata[i]) {
720  if (conn->userdata_free_cb[i] != NULL) {
721  conn->userdata_free_cb[i](conn, conn->userdata[i]);
722  } else {
723  WARN("Found unreleased userdata.");
724  }
725  conn->userdata[i] = NULL;
726  }
727  }
728 
729  if (conn->method) {
730  free(conn->method);
731  conn->method = NULL;
732  }
733 }
734 
735 static void conn_free(ad_conn_t *conn) {
736  if (conn) {
737  if (conn->status != AD_CLOSE) {
738  call_hooks(AD_EVENT_CLOSE | AD_EVENT_SHUTDOWN , conn);
739  }
740  conn_reset(conn);
741  if (conn->buffer) {
742  if (conn->server->sslctx) {
743  int sslerr = bufferevent_get_openssl_error(conn->buffer);
744  if (sslerr) {
745  char errmsg[256];
746  ERR_error_string_n(sslerr, errmsg, sizeof(errmsg));
747  ERROR("SSL %s (err:%d)", errmsg, sslerr);
748  }
749  }
750  bufferevent_free(conn->buffer);
751  }
752  free(conn);
753  }
754 }
755 
756 #define DRAIN_EVBUFFER(b) evbuffer_drain(b, evbuffer_get_length(b))
757 static void conn_read_cb(struct bufferevent *buffer, void *userdata) {
758  DEBUG("read_cb");
759  ad_conn_t *conn = userdata;
760  conn_cb(conn, AD_EVENT_READ);
761 }
762 
763 static void conn_write_cb(struct bufferevent *buffer, void *userdata) {
764  DEBUG("write_cb");
765  ad_conn_t *conn = userdata;
766  conn_cb(conn, AD_EVENT_WRITE);
767 }
768 
769 static void conn_event_cb(struct bufferevent *buffer, short what, void *userdata) {
770  DEBUG("event_cb 0x%x", what);
771  ad_conn_t *conn = userdata;
772 
773  if (what & BEV_EVENT_EOF || what & BEV_EVENT_ERROR || what & BEV_EVENT_TIMEOUT) {
774  conn->status = AD_CLOSE;
775  conn_cb(conn, AD_EVENT_CLOSE | ((what & BEV_EVENT_TIMEOUT) ? AD_EVENT_TIMEOUT : 0));
776  }
777 }
778 
779 static void conn_cb(ad_conn_t *conn, int event) {
780  DEBUG("conn_cb: status:0x%x, event:0x%x", conn->status, event)
781  if(conn->status == AD_OK || conn->status == AD_TAKEOVER) {
782  int status = call_hooks(event, conn);
783  // Update status only when it's higher then before.
784  if (! (conn->status == AD_CLOSE || (conn->status == AD_DONE && conn->status >= status))) {
785  conn->status = status;
786  }
787  }
788 
789  if(conn->status == AD_DONE) {
790  if (ad_server_get_option_int(conn->server, "server.request_pipelining")) {
791  call_hooks(AD_EVENT_CLOSE , conn);
792  conn_reset(conn);
793  call_hooks(AD_EVENT_INIT , conn);
794  } else {
795  // Do nothing but drain input buffer.
796  if (event == AD_EVENT_READ) {
797  DEBUG("Draining in-buffer. %d", conn->status);
798  DRAIN_EVBUFFER(conn->in);
799  }
800  }
801  return;
802  } else if(conn->status == AD_CLOSE) {
803  if (evbuffer_get_length(conn->out) <= 0) {
804  int newevent = (event & AD_EVENT_CLOSE) ? event : AD_EVENT_CLOSE;
805  call_hooks(newevent, conn);
806  conn_free(conn);
807  DEBUG("Connection closed.");
808  return;
809  }
810  }
811 }
812 
813 static int call_hooks(short event, ad_conn_t *conn) {
814  DEBUG("call_hooks: event 0x%x", event);
815  qlist_t *hooks = conn->server->hooks;
816 
817  qlist_obj_t obj;
818  bzero((void *)&obj, sizeof(qlist_obj_t));
819  while (hooks->getnext(hooks, &obj, false) == true) {
820  ad_hook_t *hook = (ad_hook_t *)obj.data;
821  if (hook->cb) {
822  if (hook->method && conn->method && strcmp(hook->method, conn->method)) {
823  continue;
824  }
825  int status = hook->cb(event, conn, hook->userdata);
826  if (status != AD_OK) {
827  return status;
828  }
829  }
830  }
831  return AD_OK;
832 }
833 
834 static void *set_userdata(ad_conn_t *conn, int index, const void *userdata, ad_userdata_free_cb free_cb) {
835  void *prev = conn->userdata;
836  conn->userdata[index] = (void *)userdata;
837  conn->userdata_free_cb[index] = free_cb;
838  return prev;
839 }
840 
841 static void *get_userdata(ad_conn_t *conn, int index) {
842  return conn->userdata[index];
843 }
844 
845 #endif // _DOXYGEN_SKIP
void ad_server_register_hook(ad_server_t *server, ad_callback cb, void *userdata)
Register user hook.
Definition: ad_server.c:468
void ad_conn_set_method(ad_conn_t *conn, char *method)
Set method name on this connection.
Definition: ad_server.c:532
struct bufferevent * notify_buffer
Definition: ad_server.h:153
int ad_server_start(ad_server_t *server)
Start server.
Definition: ad_server.c:164
SSL_CTX * ad_server_get_ssl_ctx(ad_server_t *server)
Get OpenSSL SSL_CTX object.
Definition: ad_server.c:454
SSL_CTX * ad_server_ssl_ctx_create_simple(const char *cert_path, const char *pkey_path)
Helper method for creating minimal OpenSSL SSL_CTX object.
Definition: ad_server.c:404
int status
Definition: ad_server.h:164
void ad_server_free(ad_server_t *server)
Release server object and all the resources.
Definition: ad_server.c:303
qhashtbl_t * stats
Definition: ad_server.h:147
struct bufferevent * buffer
Definition: ad_server.h:161
#define AD_EVENT_WRITE
Definition: ad_server.h:125
SSL_CTX * sslctx
Definition: ad_server.h:151
#define AD_EVENT_TIMEOUT
Definition: ad_server.h:127
#define AD_NUM_USERDATA
Defaults.
Definition: ad_server.h:133
#define AD_EVENT_SHUTDOWN
Definition: ad_server.h:128
char * ad_server_get_option(ad_server_t *server, const char *key)
Retrieve server option.
Definition: ad_server.c:377
#define AD_CLOSE
Definition: ad_server.h:60
struct evbuffer * out
Definition: ad_server.h:163
#define AD_EVENT_CLOSE
Definition: ad_server.h:126
#define AD_SERVER_OPTIONS
Server option names and default values.
Definition: ad_server.h:81
struct evbuffer * in
Definition: ad_server.h:162
ad_log_e
Definition: ad_server.h:65
void ad_server_set_option(ad_server_t *server, const char *key, const char *value)
Set server option.
Definition: ad_server.c:370
ad_server_t * server
Definition: ad_server.h:160
struct evconnlistener * listener
Definition: ad_server.h:149
int ad_server_get_option_int(ad_server_t *server, const char *key)
Retrieve server option in integer format.
Definition: ad_server.c:384
char * method
Definition: ad_server.h:168
ad_userdata_free_cb userdata_free_cb[2]
Definition: ad_server.h:167
qhashtbl_t * options
Definition: ad_server.h:146
ad_server_t * ad_server_new(void)
Create a server object.
Definition: ad_server.c:135
void(* ad_userdata_free_cb)(ad_conn_t *conn, void *userdata)
Definition: ad_server.h:118
Connection structure.
Definition: ad_server.h:159
#define AD_EVENT_INIT
Event types.
Definition: ad_server.h:123
#define AD_EVENT_READ
Definition: ad_server.h:124
int _ad_log_level
Definition: ad_server.c:108
void * ad_conn_set_userdata(ad_conn_t *conn, const void *userdata, ad_userdata_free_cb free_cb)
Attach userdata into the connection.
Definition: ad_server.c:490
void * userdata[2]
Definition: ad_server.h:166
#define AD_TAKEOVER
Definition: ad_server.h:58
ad_server header file
void * ad_conn_set_extra(ad_conn_t *conn, const void *extra, ad_userdata_free_cb free_cb)
Set extra userdata into the connection.
Definition: ad_server.c:513
void ad_server_register_hook_on_method(ad_server_t *server, const char *method, ad_callback cb, void *userdata)
Register user hook on method name.
Definition: ad_server.c:475
void ad_server_set_ssl_ctx(ad_server_t *server, SSL_CTX *sslctx)
Attach OpenSSL SSL_CTX to the server.
Definition: ad_server.c:434
qhashtbl_t * ad_server_get_stats(ad_server_t *server, const char *key)
Return internal statistic counter map.
Definition: ad_server.c:461
int ad_conn_get_socket(ad_conn_t *conn)
Return socket file descriptor associated with a connection.
Definition: ad_server.c:543
enum ad_log_e ad_log_level(enum ad_log_e log_level)
Set debug output level.
Definition: ad_server.c:126
int(* ad_callback)(short event, ad_conn_t *conn, void *userdata)
User callback(hook) prototype.
Definition: ad_server.h:117
qlist_t * hooks
Definition: ad_server.h:148
#define AD_OK
Definition: ad_server.h:57
void * ad_conn_get_extra(ad_conn_t *conn)
Get extra userdata attached in this connection.
Definition: ad_server.c:520
pthread_t * thread
Definition: ad_server.h:144
Server info container.
Definition: ad_server.h:142
#define AD_DONE
Definition: ad_server.h:59
struct event_base * evbase
Definition: ad_server.h:150
void ad_server_global_free(void)
Clean up all the global objects.
Definition: ad_server.c:352
void ad_server_stop(ad_server_t *server)
Stop server.
Definition: ad_server.c:287
void * ad_conn_get_userdata(ad_conn_t *conn)
Get userdata attached in the connection.
Definition: ad_server.c:499