38 #include <arpa/inet.h>
39 #include <netinet/in.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>
55 #include "qlibc/qlibc.h"
59 #include <sys/eventfd.h>
61 #include <sys/event.h>
68 typedef struct ad_hook_s ad_hook_t;
79 static void notify_cb(
struct bufferevent *buffer,
void *userdata);
80 static void *server_loop(
void *instance);
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);
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);
97 static void *get_userdata(
ad_conn_t *conn,
int index);
102 static bool initialized =
false;
142 if (server == NULL) {
147 server->
options = qhashtbl(0, 0);
148 server->
stats = qhashtbl(100, QHASHTBL_THREADSAFE);
149 server->
hooks = qlist(0);
155 DEBUG(
"Created a server object.");
165 DEBUG(
"Starting a server.");
168 set_undefined_options(server);
172 event_set_log_callback(libevent_log_cb);
174 event_enable_debug_mode();
181 struct sockaddr *sockaddr = NULL;
182 size_t sockaddr_len = 0;
183 if (addr[0] ==
'/') {
184 struct sockaddr_un unixaddr;
185 bzero((
void *) &unixaddr,
sizeof(
struct sockaddr_un));
186 if (strlen(addr) >=
sizeof(unixaddr.sun_path)) {
188 DEBUG(
"Too long unix socket name. '%s'", addr);
191 unixaddr.sun_family = AF_UNIX;
192 strcpy(unixaddr.sun_path, addr);
193 sockaddr = (
struct sockaddr *) &unixaddr;
194 sockaddr_len =
sizeof(unixaddr);
195 }
else if (strstr(addr,
":")) {
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);
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);
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);
224 DEBUG(
"SSL Initialized.");
229 server->
evbase = event_base_new();
231 ERROR(
"Failed to create a new event base.");
238 int notifyfd = eventfd(0, 0);
240 int notifyfd = kqueue();
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);
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,
250 sockaddr, sockaddr_len);
252 ERROR(
"Failed to bind on %s:%d", addr, port);
258 INFO(
"Listening on %s:%d%s", addr, port, ((server->
sslctx) ?
" (SSL)" :
""));
262 DEBUG(
"Launching server as a thread.")
263 server->
thread = NEW_OBJECT(pthread_t);
264 pthread_create(server->
thread, NULL, &server_loop, (
void *)server);
267 int *retval = server_loop(server);
268 exitstatus = *retval;
271 close_server(server);
288 DEBUG(
"Send loopexit notification.");
289 notify_loopexit(server);
293 close_server(server);
304 if (server == NULL)
return;
307 if (thread && server->
thread) {
308 notify_loopexit(server);
310 close_server(server);
314 event_base_free(server->
evbase);
318 SSL_CTX_free(server->
sslctx);
330 qlist_t *tbl = server->
hooks;
332 while ((hook = tbl->popfirst(tbl, NULL))) {
333 if (hook->method) free(hook->method);
339 DEBUG(
"Server terminated.");
361 CRYPTO_cleanup_all_ex_data();
362 sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
386 return (value) ? atoi(value) : 0;
405 const char *pkey_path) {
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)) {
411 ERROR(
"Couldn't load certificate file(%s) or private key file(%s).",
412 cert_path, pkey_path);
437 SSL_CTX_free(server->
sslctx);
462 return server->
stats;
477 bzero((
void *)&hook,
sizeof(ad_hook_t));
478 hook.method = (method) ? strdup(method) : NULL;
480 hook.userdata = userdata;
482 server->
hooks->addlast(server->
hooks, (
void *)&hook,
sizeof(ad_hook_t));
491 return set_userdata(conn, 0, userdata, free_cb);
500 return get_userdata(conn, 0);
514 return set_userdata(conn, 1, extra, free_cb);
521 return get_userdata(conn, 1);
533 char *prev = conn->
method;
534 conn->
method = (method != NULL) ? strdup(method) : NULL;
544 return bufferevent_getfd(conn->
buffer);
550 #ifndef _DOXYGEN_SKIP
559 return bufferevent_write(server->
notify_buffer, &x,
sizeof(uint64_t));
562 static void notify_cb(
struct bufferevent *buffer,
void *userdata) {
564 event_base_loopexit(server->
evbase, NULL);
565 DEBUG(
"Existing loop.");
568 static void *server_loop(
void *instance) {
571 int *retval = NEW_OBJECT(
int);
573 event_base_loop(server->
evbase, 0);
574 DEBUG(
"Loop finished");
575 *retval = (event_base_got_break(server->
evbase)) ? -1 : 0;
581 DEBUG(
"Closing server.");
589 evconnlistener_free(server->
listener);
595 DEBUG(
"Waiting server's last loop to finish.");
596 pthread_join(*(server->
thread), &retval);
601 INFO(
"Server closed.");
604 static void libevent_log_cb(
int severity,
const char *msg) {
606 case _EVENT_LOG_MSG : {
610 case _EVENT_LOG_WARN : {
614 case _EVENT_LOG_ERR : {
626 static int set_undefined_options(
ad_server_t *server) {
629 for (
int i = 0; ! IS_EMPTY_STR(default_options[i][0]); i++) {
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)) {
648 static void listener_cb(
struct evconnlistener *listener, evutil_socket_t socket,
649 struct sockaddr *sockaddr,
int socklen,
void *userdata) {
650 DEBUG(
"New connection.");
654 struct bufferevent *buffer = NULL;
656 buffer = bufferevent_openssl_socket_new(server->
evbase, socket,
658 BUFFEREVENT_SSL_ACCEPTING,
659 BEV_OPT_CLOSE_ON_FREE);
661 buffer = bufferevent_socket_new(server->
evbase, socket, BEV_OPT_CLOSE_ON_FREE);
663 if (buffer == NULL)
goto error;
669 bzero((
void *)&tm,
sizeof(
struct timeval));
671 bufferevent_set_timeouts(buffer, &tm, NULL);
675 void *conn = conn_new(server, buffer);
676 if (! conn)
goto error;
681 if (buffer) bufferevent_free(buffer);
682 ERROR(
"Failed to create a connection handler.");
683 event_base_loopbreak(server->
evbase);
688 if (server == NULL || buffer == NULL) {
694 if (conn == NULL)
return NULL;
699 conn->
in = bufferevent_get_input(buffer);
700 conn->
out = bufferevent_get_output(buffer);
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);
715 static void conn_reset(
ad_conn_t *conn) {
723 WARN(
"Found unreleased userdata.");
743 int sslerr = bufferevent_get_openssl_error(conn->
buffer);
746 ERR_error_string_n(sslerr, errmsg,
sizeof(errmsg));
747 ERROR(
"SSL %s (err:%d)", errmsg, sslerr);
750 bufferevent_free(conn->
buffer);
756 #define DRAIN_EVBUFFER(b) evbuffer_drain(b, evbuffer_get_length(b))
757 static void conn_read_cb(
struct bufferevent *buffer,
void *userdata) {
763 static void conn_write_cb(
struct bufferevent *buffer,
void *userdata) {
769 static void conn_event_cb(
struct bufferevent *buffer,
short what,
void *userdata) {
770 DEBUG(
"event_cb 0x%x", what);
773 if (what & BEV_EVENT_EOF || what & BEV_EVENT_ERROR || what & BEV_EVENT_TIMEOUT) {
779 static void conn_cb(
ad_conn_t *conn,
int event) {
780 DEBUG(
"conn_cb: status:0x%x, event:0x%x", conn->
status, event)
782 int status = call_hooks(event, conn);
797 DEBUG(
"Draining in-buffer. %d", conn->
status);
798 DRAIN_EVBUFFER(conn->
in);
803 if (evbuffer_get_length(conn->
out) <= 0) {
805 call_hooks(newevent, conn);
807 DEBUG(
"Connection closed.");
813 static int call_hooks(
short event,
ad_conn_t *conn) {
814 DEBUG(
"call_hooks: event 0x%x", event);
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;
822 if (hook->method && conn->
method && strcmp(hook->method, conn->
method)) {
825 int status = hook->cb(event, conn, hook->
userdata);
826 if (status !=
AD_OK) {
836 conn->
userdata[index] = (
void *)userdata;
841 static void *get_userdata(
ad_conn_t *conn,
int index) {
845 #endif // _DOXYGEN_SKIP
void ad_server_register_hook(ad_server_t *server, ad_callback cb, void *userdata)
Register user hook.
void ad_conn_set_method(ad_conn_t *conn, char *method)
Set method name on this connection.
struct bufferevent * notify_buffer
int ad_server_start(ad_server_t *server)
Start server.
SSL_CTX * ad_server_get_ssl_ctx(ad_server_t *server)
Get OpenSSL SSL_CTX object.
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.
void ad_server_free(ad_server_t *server)
Release server object and all the resources.
struct bufferevent * buffer
#define AD_NUM_USERDATA
Defaults.
#define AD_EVENT_SHUTDOWN
char * ad_server_get_option(ad_server_t *server, const char *key)
Retrieve server option.
#define AD_SERVER_OPTIONS
Server option names and default values.
void ad_server_set_option(ad_server_t *server, const char *key, const char *value)
Set server option.
struct evconnlistener * listener
int ad_server_get_option_int(ad_server_t *server, const char *key)
Retrieve server option in integer format.
ad_userdata_free_cb userdata_free_cb[2]
ad_server_t * ad_server_new(void)
Create a server object.
void(* ad_userdata_free_cb)(ad_conn_t *conn, void *userdata)
#define AD_EVENT_INIT
Event types.
void * ad_conn_set_userdata(ad_conn_t *conn, const void *userdata, ad_userdata_free_cb free_cb)
Attach userdata into the connection.
void * ad_conn_set_extra(ad_conn_t *conn, const void *extra, ad_userdata_free_cb free_cb)
Set extra userdata into the connection.
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.
void ad_server_set_ssl_ctx(ad_server_t *server, SSL_CTX *sslctx)
Attach OpenSSL SSL_CTX to the server.
qhashtbl_t * ad_server_get_stats(ad_server_t *server, const char *key)
Return internal statistic counter map.
int ad_conn_get_socket(ad_conn_t *conn)
Return socket file descriptor associated with a connection.
enum ad_log_e ad_log_level(enum ad_log_e log_level)
Set debug output level.
int(* ad_callback)(short event, ad_conn_t *conn, void *userdata)
User callback(hook) prototype.
void * ad_conn_get_extra(ad_conn_t *conn)
Get extra userdata attached in this connection.
struct event_base * evbase
void ad_server_global_free(void)
Clean up all the global objects.
void ad_server_stop(ad_server_t *server)
Stop server.
void * ad_conn_get_userdata(ad_conn_t *conn)
Get userdata attached in the connection.