Rework WIP.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
NADAL Jean-Baptiste
2020-02-17 14:12:15 +01:00
parent 8dc00f5fc6
commit cf9decf7b8
3 changed files with 203 additions and 9 deletions

View File

@@ -1,7 +1,5 @@
/*! /*!
* restd.h * restd.c
* *
* Copyright (c) 2015-2020, NADAL Jean-Baptiste. All rights reserved. * Copyright (c) 2015-2020, NADAL Jean-Baptiste. All rights reserved.
* *
@@ -27,9 +25,17 @@
/*------------------------------- INCLUDES ----------------------------------*/ /*------------------------------- INCLUDES ----------------------------------*/
#include <string.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <event2/buffer.h> #include <event2/buffer.h>
#include <event2/bufferevent.h> #include <event2/bufferevent.h>
#include <event2/event.h> #include <event2/event.h>
#include <evhttp.h>
#include <event2/listener.h> #include <event2/listener.h>
#include "macro.h" #include "macro.h"
@@ -45,10 +51,41 @@ static bool initialized = false;
*/ */
int _restd_log_level = RESTD_LOG_WARN; int _restd_log_level = RESTD_LOG_WARN;
/**
* Server option names and default values.
*/
#define RESTD_SERVER_OPTIONS { \
{"server.port", "8888"}, \
\
{"server.root_path", ""}, \
\
/* Addr format IPv4="1.2.3.4", IPv6="1:2:3:4:5:6", Unix="/path" */ \
{"server.addr", "0.0.0.0"}, \
\
{"server.backlog", "128"}, \
\
/* Set read timeout seconds. 0 means no timeout. */ \
{"server.timeout", "0"}, \
\
/* Enable or disable request pipelining, this change AD_DONE's behavior */ \
{"server.request_pipelining", "1"}, \
\
/* Run server in a separate thread */ \
{"server.thread", "0"}, \
\
/* Collect resources after stop */ \
{"server.free_on_stop", "1"}, \
\
/* End of array marker. Do not remove */ \
{"", "_END_"}};
/*------------------------------- FUNCTIONS ----------------------------------*/
static int set_undefined_options(restd_server_t *server);
char *restd_server_get_option(restd_server_t *server, const char *key); char *restd_server_get_option(restd_server_t *server, const char *key);
int restd_server_get_option_int(restd_server_t *server, const char *key); int restd_server_get_option_int(restd_server_t *server, const char *key);
static void close_server(restd_server_t *server); static void close_server(restd_server_t *server);
static void libevent_log_cb(int severity, const char *msg);
static int notify_loopexit(restd_server_t *server); static int notify_loopexit(restd_server_t *server);
/*--------------------------- PUBLIC FUNCTIONS -------------------------------*/ /*--------------------------- PUBLIC FUNCTIONS -------------------------------*/
@@ -128,6 +165,11 @@ void restd_server_free(restd_server_t *server)
event_base_free(server->evbase); event_base_free(server->evbase);
} }
if (server->evhttp)
{
evhttp_free(server->evhttp);
}
if (server->options) if (server->options)
{ {
server->options->free(server->options); server->options->free(server->options);
@@ -162,6 +204,95 @@ void restd_server_free(restd_server_t *server)
*/ */
int restd_server_start(restd_server_t *server) int restd_server_start(restd_server_t *server)
{ {
int ret;
DEBUG("Starting a server.");
if (server == NULL)
return -1;
// Set default options that were not set by user..
set_undefined_options(server);
// Hookup libevent's log message.
if (_restd_log_level >= RESTD_LOG_DEBUG)
{
event_set_log_callback(libevent_log_cb);
if (_restd_log_level >= RESTD_LOG_DEBUG2)
{
event_enable_debug_mode();
}
}
// Parse addr
int port = restd_server_get_option_int(server, "server.port");
char *addr = restd_server_get_option(server, "server.addr");
struct sockaddr *sockaddr = NULL;
size_t sockaddr_len = 0;
if (addr[0] == '/')
{ // Unix socket.
struct sockaddr_un unixaddr;
bzero((void *)&unixaddr, sizeof(struct sockaddr_un));
if (strlen(addr) >= sizeof(unixaddr.sun_path))
{
errno = EINVAL;
DEBUG("Too long unix socket name. '%s'", addr);
return -1;
}
unixaddr.sun_family = AF_UNIX;
strcpy(unixaddr.sun_path, addr); // no need of strncpy()
sockaddr = (struct sockaddr *)&unixaddr;
sockaddr_len = sizeof(unixaddr);
}
else if (strstr(addr, ":"))
{ // IPv6
struct sockaddr_in6 ipv6addr;
bzero((void *)&ipv6addr, sizeof(struct sockaddr_in6));
ipv6addr.sin6_family = AF_INET6;
ipv6addr.sin6_port = htons(port);
evutil_inet_pton(AF_INET6, addr, &ipv6addr.sin6_addr);
sockaddr = (struct sockaddr *)&ipv6addr;
sockaddr_len = sizeof(ipv6addr);
}
else
{ // IPv4
struct sockaddr_in ipv4addr;
bzero((void *)&ipv4addr, sizeof(struct sockaddr_in));
ipv4addr.sin_family = AF_INET;
ipv4addr.sin_port = htons(port);
ipv4addr.sin_addr.s_addr =
(IS_EMPTY_STR(addr)) ? INADDR_ANY : inet_addr(addr);
sockaddr = (struct sockaddr *)&ipv4addr;
sockaddr_len = sizeof(ipv4addr);
}
// Bind
if (!server->evbase)
{
server->evbase = event_base_new();
if (!server->evbase)
{
ERROR("Failed to create a new event base.");
return -1;
}
}
server->evhttp = evhttp_new(server->evbase);
if (!server->evhttp)
{
ERROR("Event http initialize failed!\n");
return -2;
}
#if 0
ret = evhttp_bind_socket(server->evhttp, addr, port);
if (ret != 0)
{
ERROR("Http bind server addr:%s & port:%d failed!\n", addr, port);
return -3;
}
#endif
return 0;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -179,15 +310,45 @@ int restd_server_attach_event_loop(restd_server_t *server, struct event_base *ev
void restd_server_set_option(restd_server_t *server, const char *key, const char *value) void restd_server_set_option(restd_server_t *server, const char *key, const char *value)
{ {
server->options->putstr(server->options, key, value);
} }
/*--------------------------------------------------------------------------*/
void restd_server_register_hook_on_path(restd_server_t *server, const char *method, const char *path, void restd_server_register_hook_on_path(restd_server_t *server, const char *method, const char *path,
restd_callback cb, void *userdata) restd_callback cb, void *userdata)
{ {
restd_hook_t hook;
bzero((void *)&hook, sizeof(restd_hook_t));
hook.method = (method) ? strdup(method) : NULL;
hook.path = (path) ? strdup(path) : NULL;
hook.cb = cb;
hook.userdata = userdata;
server->hooks->addlast(server->hooks, (void *)&hook, sizeof(restd_hook_t));
} }
/*--------------------------- LOCAL FUNCTIONS -------------------------------*/ /*--------------------------- LOCAL FUNCTIONS -------------------------------*/
/*--------------------------------------------------------------------------*/
// Set default options that were not set by user..
static int set_undefined_options(restd_server_t *server)
{
int newentries = 0;
char *default_options[][2] = RESTD_SERVER_OPTIONS;
for (int i = 0; !IS_EMPTY_STR(default_options[i][0]); i++)
{
if (!restd_server_get_option(server, default_options[i][0]))
{
restd_server_set_option(server, default_options[i][0], default_options[i][1]);
newentries++;
}
DEBUG("%s=%s", default_options[i][0], restd_server_get_option(server, default_options[i][0]));
}
return newentries;
}
/** /**
* Retrieve server option. * Retrieve server option.
*/ */
@@ -235,6 +396,35 @@ static void close_server(restd_server_t *server)
INFO("Server closed."); INFO("Server closed.");
} }
/*--------------------------------------------------------------------------*/
static void libevent_log_cb(int severity, const char *msg)
{
switch (severity)
{
case _EVENT_LOG_MSG:
{
INFO("%s", msg);
break;
}
case _EVENT_LOG_WARN:
{
WARN("%s", msg);
break;
}
case _EVENT_LOG_ERR:
{
ERROR("%s", msg);
break;
}
default:
{
DEBUG("%s", msg);
break;
}
}
}
/** /**
* If there's no event, loopbreak or loopexit call won't work until one more * If there's no event, loopbreak or loopexit call won't work until one more
* event arrived. So we use eventfd as a internal notification channel to let * event arrived. So we use eventfd as a internal notification channel to let

View File

@@ -93,6 +93,7 @@ struct restd_server_s
qlist_t *hooks; /*!< list of registered hooks */ qlist_t *hooks; /*!< list of registered hooks */
struct evconnlistener *listener; /*!< listener */ struct evconnlistener *listener; /*!< listener */
struct event_base *evbase; /*!< event base */ struct event_base *evbase; /*!< event base */
struct evhttp *evhttp;
struct bufferevent *notify_buffer; /*!< internal notification channel */ struct bufferevent *notify_buffer; /*!< internal notification channel */

View File

@@ -46,17 +46,21 @@ int my_error_handler(short event, restd_conn_t *conn, void *userdata)
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
#if 0
int my_success_http_handler(short event, restd_conn_t *conn, void *userdata) int my_success_http_handler(short event, restd_conn_t *conn, void *userdata)
{ {
#if 0
if (event & RESTD_EVENT_READ) if (event & RESTD_EVENT_READ)
{ {
restd_http_response(conn, 200, "application/json", ksuccess_get_body, strlen(ksuccess_get_body)); restd_http_response(conn, 200, "application/json", ksuccess_get_body, strlen(ksuccess_get_body));
return RESTD_CLOSE; // Close connection. return RESTD_CLOSE; // Close connection.
} }
return RESTD_OK; return RESTD_OK;
#endif
} }
#if 0
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
int my_success_rest_get_handler(short event, restd_conn_t *conn, void *userdata) int my_success_rest_get_handler(short event, restd_conn_t *conn, void *userdata)
@@ -189,7 +193,7 @@ exit:
return ret; return ret;
} }
#endif
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
bool found_route(restd_server_t *server, const char *method, const char *path) bool found_route(restd_server_t *server, const char *method, const char *path)
@@ -277,7 +281,7 @@ bool found_special_route(restd_server_t *server, const char *method, const char
return false; return false;
} }
#endif
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
TEST("Rest - create free\t") TEST("Rest - create free\t")
@@ -295,7 +299,7 @@ TEST("Rest - create free\t")
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
#if 0
TEST("Rest - create access regular route free\t") TEST("Rest - create access regular route free\t")
{ {
restd_server_t *rest_server; restd_server_t *rest_server;
@@ -323,7 +327,6 @@ TEST("Rest - create access regular route free\t")
restd_server_free(rest_server); restd_server_free(rest_server);
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
TEST("Rest - create access route with param free\t") TEST("Rest - create access route with param free\t")
@@ -367,7 +370,7 @@ TEST("Rest - create start free\t")
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
#if 0
TEST("Rest - create start access http hook free\t") TEST("Rest - create start access http hook free\t")
{ {
int ret; int ret;