Switch to initialization by config and new event model

This commit is contained in:
Ilja Kartašov 2019-03-24 21:00:25 +01:00
parent d28f942cf7
commit 345450b35b
18 changed files with 505 additions and 735 deletions

1
.gitignore vendored
View File

@ -17,6 +17,7 @@ tmp/*
*.bz2
pkg/*
doc/html
vgcore.*
include/webstuff_bak

View File

@ -23,11 +23,16 @@
#define DEFAULT_HTTP_PORT 8080 /**< Default HTTP server port */
static bool
hello_world(aisl_stream_t s)
static void
hello_world(aisl_evt_t const evt, void * p_ctx)
{
if (evt->code != AISL_EVENT_STREAM_REQUEST)
return;
aisl_status_t status;
aisl_stream_t s = evt->source;
const char html[] =
"<html>"
"<head>"
@ -51,58 +56,44 @@ hello_world(aisl_stream_t s)
aisl_reject(s);
}
return true; /**< do not propagate event anymore */
(void) p_ctx;
}
int
main(int argc, char ** argv)
{
aisl_t aisl; /**< AISL instance pointer */
aisl_status_t status; /**< AISL status code */
struct aisl_config config = AISL_CONFIG_DEFAULT;
uint16_t port = 0;
aisl_t aisl; /**< AISL instance pointer */
aisl_status_t status; /**< AISL status code */
struct aisl_cfg cfg = AISL_CFG_DEFAULT;
struct aisl_cfg_srv srv = {
.host = "0.0.0.0",
.port = DEFAULT_HTTP_PORT,
.secure = false
};
/* Try to use first argument as a port number */
if (argc > 1)
port = strtoll(argv[1], NULL, 10);
/* Fallback to default if not set or failed */
if (port == 0)
port = DEFAULT_HTTP_PORT;
cfg.srv = &srv;
cfg.srv_cnt = 1;
cfg.callback = hello_world;
/* Initialize instance */
if ( (aisl = aisl_new(&config)) != NULL )
if ( (aisl = aisl_new(&cfg)) != NULL )
{
if (aisl_listen( aisl, "0.0.0.0", port ) != NULL)
/* launch application loop */
fprintf(stdout, "Entering main loop" );
for(;;)
{
/* Set up request callback */
aisl_set_callback( aisl
, AISL_EVENT_STREAM_REQUEST
, AISL_CALLBACK(hello_world) );
status = aisl_run_cycle(aisl);
/* launch application loop */
fprintf(stdout, "Entering main loop" );
for(;;)
{
status = aisl_run_cycle(aisl);
if ( status != AISL_SUCCESS )
aisl_sleep(aisl, 500);
}
aisl_free(aisl);
if ( status != AISL_SUCCESS )
aisl_sleep(aisl, 500);
}
else
fprintf(stderr, "Failed to initialize HTTP server" );
aisl_free(aisl);
}
else
fprintf(stderr, "Failed to initialize AISL");
(void)argc;
(void)argv;
return 0;
}

View File

@ -45,7 +45,7 @@ aisl_client_is_online(aisl_client_t client);
* @param client an #aisl_client_t instance pointer.
*/
void
aisl_client_close(aisl_client_t client);
aisl_client_disconnect(aisl_client_t client);
/**

View File

@ -10,29 +10,61 @@
#ifndef AISL_CONFIG_H_DB67A89B_5CAF_4A5F_AEB1_6DB9F84827D6
#define AISL_CONFIG_H_DB67A89B_5CAF_4A5F_AEB1_6DB9F84827D6
#include <stdint.h>
#include <aisl/types.h>
#define AISL_CONFIG_DEFAULT \
{ \
.server_spool_size = 1 \
#define AISL_CFG_DEFAULT \
{ \
.callback = NULL \
, .p_ctx = NULL \
, .srv = NULL \
, .ssl = NULL \
, .srv_cnt = 0 \
, .ssl_cnt = 0 \
, .client_spool_size = 32 \
, .ssl_spool_size = 1 \
, .initial_buffer_size = 16536 \
, .client_accept_limit = 1024 \
, .client_silence_timeout = 30 \
} \
} \
struct aisl_config
struct aisl_cfg_srv
{
uint32_t server_spool_size;
uint32_t client_spool_size;
uint32_t ssl_spool_size;
uint32_t initial_buffer_size;
uint32_t client_accept_limit;
uint32_t client_silence_timeout;
const char * host;
uint16_t port;
bool secure;
};
typedef struct aisl_config * aisl_config_t;
typedef struct aisl_cfg_srv * aisl_cfg_srv_t;
struct aisl_cfg_ssl
{
const char * host;
const char * key_file;
const char * crt_file;
};
typedef struct aisl_cfg_ssl * aisl_cfg_ssl_t;
struct aisl_cfg
{
/* event handlers */
aisl_callback_t callback;
void * p_ctx;
aisl_cfg_srv_t srv;
aisl_cfg_ssl_t ssl;
int srv_cnt;
int ssl_cnt;
int client_spool_size;
int initial_buffer_size;
int client_accept_limit;
int client_silence_timeout;
};
typedef struct aisl_cfg * aisl_cfg_t;
#endif /* !AISL_CONFIG_H */

View File

@ -20,11 +20,11 @@
/**
* @brief Allocates new AISL instance.
*
* @param config a pointer to #aisl_config structure.
* @param cfg a pointer to #aisl_cfg_t structure.
* @return an #aisl_t instance pointer.
*/
aisl_t
aisl_new( aisl_config_t config );
aisl_new( aisl_cfg_t cfg );
/**
@ -35,56 +35,6 @@ void
aisl_free( aisl_t instance );
/**
* @brief Allocates and registers HTTP server instance.
* @param instance a pointer to #aisl_t instance.
* @param address a null-terminated ip or hostname string.
* @param port a number of port to listen.
* @return a pointer representing HTTP server.
*/
aisl_server_t
aisl_listen( aisl_t instance, const char * address, uint16_t port );
#ifndef AISL_WITHOUT_SSL
/**
* @brief Sets pair of SSL certificate and key for domain name.
* @param instance a pointer to #aisl_t instance.
* @param domain a null-terminated string with domain name.
* @param key_file a null-terminated string with path to private SSL key file.
* @param crt_file a null-terminated string with path to SSL certificate file.
* @return #aisl_status_t code.
*/
aisl_status_t
aisl_set_ssl( aisl_t instance,
const char * domain,
const char * key_file,
const char * crt_file );
#endif
/**
* @brief Registers a callback for event and its source.
* If source is NULL, then callback will be executed for all events of specified
* type.
*
* Typical sources are:
* - #aisl_server_t,
* - #aisl_client_t,
* - #aisl_stream_t;
*
* @param instance a pointer to #aisl_t instance.
* @param event a code of event.
* @param callback a pointer to function that will be triggered on event.
*/
void
aisl_set_callback( aisl_t instance,
aisl_event_t event,
aisl_callback_t callback );
/**
* @brief A core function doing all the library routines.
* Designed to be called inside application main loop
@ -106,12 +56,4 @@ aisl_status_t
aisl_sleep( aisl_t instance, uint32_t usec );
/**
* @brief Get last error message.
* @param instance a pointer to #aisl_t instance.
* @return a null-terminated string with error message.
*/
const char *
aisl_get_error( aisl_t instance );
#endif /* !AISL_INSTANCE_H */

View File

@ -31,17 +31,6 @@ void
aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address);
#ifndef AISL_WITHOUT_SSL
/**
* @brief Function to switch on and off SSL for the #aisl_server_t.
* @param server an #aisl_server_t pointer.
* @param value a boolean value representing SSL enabled/disabled state.
*/
void
aisl_server_set_ssl( aisl_server_t server, bool value );
/**
* @brief Function to get on and off status of SSL for the #aisl_server_t.
* @param server an #aisl_server_t pointer.
@ -50,6 +39,4 @@ aisl_server_set_ssl( aisl_server_t server, bool value );
bool
aisl_server_get_ssl( aisl_server_t server );
#endif
#endif /* !AISL_SERVER_H */

View File

@ -27,9 +27,6 @@
/* AISL Instance */
typedef struct aisl * aisl_t;
/* Event Identifier */
typedef uint32_t aisl_event_t;
/* HTTP(s) Server */
typedef struct aisl_server * aisl_server_t;
@ -39,10 +36,6 @@ typedef struct aisl_client * aisl_client_t;
/* Server<->Client Stream */
typedef struct aisl_stream * aisl_stream_t;
/* void type event callback */
typedef void
(* aisl_callback_t) (void);
/* status return codes */
typedef enum
@ -64,6 +57,7 @@ aisl_status_to_string(aisl_status_t status);
#endif
/* Generic HTTP Enumerations */
typedef enum
@ -156,16 +150,15 @@ const char *
aisl_http_response_to_string( aisl_http_response_t code );
/* Built-in Events IDs */
/* Events */
enum
typedef enum
{
AISL_EVENT_SERVER_OPEN = 100
, AISL_EVENT_SERVER_ERROR = 190
, AISL_EVENT_CLIENT_CONNECT = 200
, AISL_EVENT_CLIENT_DISCONNECT = 210
, AISL_EVENT_CLIENT_TIMEOUT = 220
, AISL_EVENT_STREAM_OPEN = 300
, AISL_EVENT_STREAM_HEADER = 310
@ -175,62 +168,59 @@ enum
, AISL_EVENT_STREAM_CLOSE = 350
, AISL_EVENT_STREAM_ERROR = 390
} aisl_evt_code_t;
struct aisl_evt
{
void * source;
aisl_evt_code_t code;
aisl_status_t status;
};
typedef struct aisl_evt * aisl_evt_t;
/* void type event callback */
typedef void
(* aisl_callback_t) (aisl_evt_t const evt, void * p_ctx);
struct aisl_evt_stream_open
{
struct aisl_evt evt;
const char * path;
const char * query;
aisl_http_method_t http_method;
};
typedef struct aisl_evt_stream_open * aisl_evt_stream_open_t;
struct aisl_evt_stream_header
{
struct aisl_evt evt;
const char * key;
const char * value;
};
typedef struct aisl_evt_stream_header * aisl_evt_stream_header_t;
struct aisl_evt_stream_input
{
struct aisl_evt evt;
const char * data;
int32_t size;
};
typedef struct aisl_evt_stream_input * aisl_evt_stream_input_t;
#ifndef WITHOUT_STRINGIFIERS
const char *
aisl_event_to_string( aisl_event_t event );
aisl_evt_code_to_string( aisl_evt_code_t evt_code );
#endif
/* real type event callbacks */
typedef bool
(*aisl_on_source_event_t)( void * source );
typedef bool
(*aisl_on_server_open_t)( aisl_server_t server );
typedef bool
(*aisl_on_server_error_t)( aisl_server_t server );
typedef bool
(*aisl_on_client_connect_t)( aisl_client_t client );
typedef bool
(*aisl_on_client_disconnect_t)( aisl_client_t client );
typedef bool
(*aisl_on_client_timeout_t)( aisl_client_t client );
typedef bool
(*aisl_on_stream_open_t)( aisl_stream_t stream,
aisl_http_method_t method,
const char * path,
const char * query );
typedef bool
(*aisl_on_stream_header_t)( aisl_stream_t stream,
const char * key,
const char * val );
typedef bool
(*aisl_on_stream_input_t)( aisl_stream_t stream,
const char * data,
int32_t len );
typedef bool
(*aisl_on_stream_request_t)( aisl_stream_t stream );
typedef bool
(*aisl_on_stream_output_t)( aisl_stream_t stream );
typedef bool
(*aisl_on_stream_close_t)( aisl_stream_t stream );
typedef bool
(*aisl_on_stream_error_t)( aisl_stream_t stream );
#endif /* !AISL_TYPES_H */

View File

@ -51,8 +51,8 @@ PROJECT_LIBRARIES = \
# flags
PROJECT_CFLAGS = -D_POSIX_C_SOURCE=200809L
#PROJECT_CFLAGS += -DDEBUG
#PROJECT_CFLAGS += -DAISL_WITHOUT_SSL
PROJECT_CFLAGS += -DDEBUG
PROJECT_CFLAGS += -DAISL_WITHOUT_SSL
#PROJECT_CFLAGS += -DAISL_WITHOUT_STRINGIFIERS

View File

@ -26,13 +26,33 @@
#define BUFFER_SIZE (16*1024)
static void
aisl_client_close(aisl_client_t client, aisl_status_t status)
{
if (client->fd != -1)
{
aisl_raise(
client->server->instance
, (void *)client
, AISL_EVENT_CLIENT_DISCONNECT
, status
);
close(client->fd);
shutdown(client->fd, SHUT_RDWR);
client->fd = -1;
}
}
static aisl_status_t
aisl_client_parse(aisl_client_t client, char * data, int32_t size)
{
aisl_stream_t s;
aisl_status_t result = AISL_SUCCESS;
aisl_stream_t s = client->stream;
http_parser_t p = HTTP_PARSER_SUCCESS;
int32_t bytes_left = size;
switch (client->http_version)
@ -41,7 +61,7 @@ aisl_client_parse(aisl_client_t client, char * data, int32_t size)
case AISL_HTTP_1_0:
case AISL_HTTP_1_1:
s = client->stream;
/* s = client->stream; */
while ( p == HTTP_PARSER_SUCCESS )
{
@ -70,17 +90,7 @@ aisl_client_parse(aisl_client_t client, char * data, int32_t size)
size = bytes_left;
}
if (p == HTTP_PARSER_READY)
{
client->flags &= ~FLAG_CAN_READ;
client->flags |= FLAG_CAN_WRITE;
aisl_raise(
client->server->instance,
client->stream,
AISL_EVENT_STREAM_REQUEST
);
}
break;
@ -89,27 +99,43 @@ aisl_client_parse(aisl_client_t client, char * data, int32_t size)
break;
}
if (p == HTTP_PARSER_ERROR)
switch(p)
{
/* reply Bad Request here */
client->stream->http_response = AISL_HTTP_BAD_REQUEST;
case HTTP_PARSER_READY:
client->flags &= ~FLAG_CAN_READ;
client->flags |= FLAG_CAN_WRITE;
aisl_raise(
client->server->instance,
client->stream,
AISL_EVENT_STREAM_ERROR
);
aisl_raise(
client->server->instance
, (void *) s
, AISL_EVENT_STREAM_REQUEST
, result
);
break;
aisl_client_close(client);
case HTTP_PARSER_ERROR:
/* reply Bad Request here */
client->stream->http_response = AISL_HTTP_BAD_REQUEST;
return AISL_INPUT_ERROR;
aisl_raise(
client->server->instance
, (void *) s
, AISL_EVENT_STREAM_ERROR
, result
);
aisl_client_close(client, result);
return result;
default:
break;
}
if (size)
buffer_shift(&client->in, client->in.used - size); /* reset buffer */
return AISL_SUCCESS;
return result;
}
@ -142,8 +168,8 @@ aisl_client_input(aisl_client_t client)
DPRINTF("SSL handshake fail: %s\n", ERR_error_string(l, NULL) );
aisl_client_close(client);
return AISL_SYSCALL_ERROR;
aisl_client_close(client, AISL_EXTCALL_ERROR);
return AISL_EXTCALL_ERROR;
}
client->flags &= ~FLAG_HANDSHAKE;
@ -186,7 +212,7 @@ aisl_client_input(aisl_client_t client)
/* both: client disconnect + on read error */
/* todo: raise client error here */
aisl_client_close(client);
aisl_client_close(client, AISL_SYSCALL_ERROR);
return AISL_SYSCALL_ERROR;
}
@ -221,12 +247,14 @@ aisl_client_output(aisl_client_t client)
*/
if ( !(l < aisl_stream_get_buffer_size(s) / 2) )
{
aisl_raise(
aisl_server_get_instance(client->server),
s,
AISL_EVENT_STREAM_OUTPUT,
l
client->server->instance
, (void*)s
, AISL_EVENT_STREAM_OUTPUT
, AISL_SUCCESS
);
}
}
data = aisl_stream_get_data(s, &l);
@ -269,7 +297,7 @@ aisl_client_output(aisl_client_t client)
*/
}
aisl_client_close(client);
aisl_client_close(client, AISL_SUCCESS);
}
return AISL_SUCCESS;
@ -289,7 +317,7 @@ aisl_client_output(aisl_client_t client)
return AISL_IDLE;
}
aisl_client_close(client);
aisl_client_close(client, AISL_SYSCALL_ERROR);
return AISL_SYSCALL_ERROR;
}
@ -360,7 +388,7 @@ aisl_client_new( aisl_server_t server,
void
aisl_client_free(aisl_client_t client)
{
aisl_client_close(client);
aisl_client_close(client, AISL_SUCCESS);
#ifndef AISL_WITHOUT_SSL
if (client->ssl)
@ -380,7 +408,7 @@ aisl_client_free(aisl_client_t client)
aisl_status_t
aisl_client_touch(aisl_client_t client)
aisl_client_touch(aisl_client_t client, int32_t timeout)
{
aisl_status_t result = AISL_IDLE,
status = AISL_IDLE;
@ -418,29 +446,22 @@ aisl_client_touch(aisl_client_t client)
if (result == AISL_SUCCESS)
client->timestamp = time(NULL);
else
{
time_t now;
time(&now);
if ( !(now - client->timestamp < timeout) )
{
aisl_client_close(client, result);
}
}
return result;
}
bool
aisl_client_is_timed_out(aisl_client_t client, uint32_t timeout)
{
time_t now;
time(&now);
if ( !(now - client->timestamp < timeout) )
{
aisl_raise(client->server->instance, client, AISL_EVENT_CLIENT_TIMEOUT);
aisl_client_close(client);
return true;
}
else
return false;
}
int
aisl_client_get_socket(aisl_client_t client)
{
@ -494,19 +515,11 @@ aisl_client_is_online(aisl_client_t client)
void
aisl_client_close(aisl_client_t client)
aisl_client_disconnect(aisl_client_t client)
{
if (client->fd != -1)
{
aisl_raise(client->server->instance, client, AISL_EVENT_CLIENT_DISCONNECT);
close(client->fd);
shutdown(client->fd, SHUT_RDWR);
client->fd = -1;
}
aisl_client_close(client, AISL_SUCCESS);
}
aisl_http_version_t
aisl_client_get_http_version(aisl_client_t client)
{

View File

@ -54,20 +54,11 @@ aisl_client_free(aisl_client_t client);
* @brief Does all HTTP client routines.
* Reads and parses requests, writes responses.
* @param client an #aisl_client_t instance pointer.
* @param timeout an allowed client silence time in seconds.
* @return #aisl_status_t code.
*/
aisl_status_t
aisl_client_touch(aisl_client_t client);
/**
* @brief Controls if communication time is not timed out.
* @param client an #aisl_client_t instance pointer.
* @param timeout an allowed client silence time in seconds.
* @return true if client communication is timed out, otherwise false.
*/
bool
aisl_client_is_timed_out(aisl_client_t client, uint32_t timeout);
aisl_client_touch(aisl_client_t client, int32_t timeout);
/**

View File

@ -25,14 +25,53 @@
#include "client.h"
#include "server.h"
#include "ssl.h"
//#include "globals.h"
#include "stream.h"
#include "instance.h"
#ifndef AISL_WITHOUT_SSL
static uint32_t m_instances = 0;
static const aisl_ssl_t
aisl_new_ssl( aisl_t instance, const aisl_cfg_ssl_t cfg_ssl)
{
SSL_CTX * ssl_ctx = NULL;
aisl_ssl_t * list = instance->ssl,
ssl;
/* lookup for existing contexts */
while( (ssl = *list) )
{
if (ssl->key_file && strcmp(ssl->key_file, cfg_ssl->key_file)==0 &&
ssl->crt_file && strcmp(ssl->crt_file, cfg_ssl->crt_file)==0 )
{
ssl_ctx = ssl->ctx;
break;
}
list++;
}
ssl = aisl_ssl_new( cfg_ssl->host,
cfg_ssl->key_file,
cfg_ssl->crt_file,
ssl_ctx );
if (ssl)
{
if ( !ssl_ctx && !aisl_ssl_get_ctx(ssl, (void*) instance))
{
aisl_ssl_free(ssl);
ssl = NULL;
}
}
return ssl;
}
#endif
@ -40,34 +79,50 @@ static uint32_t m_instances = 0;
__attribute__ ((visibility ("default") ))
aisl_t
aisl_new( aisl_config_t config )
aisl_new( aisl_cfg_t cfg )
{
aisl_t instance;
/* allocate root structure */
if ( !(instance = calloc(1, sizeof(struct aisl))) )
goto finally;
/* allocate servers */
if ( !(instance->srv = calloc(cfg->srv_cnt+1, sizeof(aisl_server_t))) )
goto release;
for (int i=0; i<cfg->srv_cnt; i++)
{
DPRINTF("new srv %d", i);
if (!(instance->srv[i] = aisl_server_new(&cfg->srv[i], instance)))
goto release;
}
#ifndef AISL_WITHOUT_SSL
if ((m_instances++) == 0)
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
if ( !(instance->ssl = calloc(cfg->ssl_cnt+1, sizeof(aisl_ssl_t))) )
goto release;
for (int i=0; i<cfg->ssl_cnt; i++)
{
DPRINTF("new ssl %d", i);
if (!(instance->ssl[i] = aisl_new_ssl(instance, &cfg->ssl[i])))
goto release;
}
#endif
if ( !(instance = calloc(1, sizeof(struct aisl))) )
goto finally;
if ( list_init(&instance->server_spool, config->server_spool_size) == -1 )
if ( list_init(&instance->client_spool, cfg->client_spool_size) == -1 )
goto release;
if ( list_init(&instance->client_spool, config->client_spool_size) == -1 )
goto release;
#ifndef AISL_WITHOUT_SSL
if ( list_init(&instance->ssl_spool, config->ssl_spool_size) == -1 )
goto release;
#endif
instance->accept_limit = config->client_accept_limit;
instance->silence_timeout = config->client_silence_timeout;
instance->accept_limit = cfg->client_accept_limit;
instance->silence_timeout = cfg->client_silence_timeout;
instance->callback = cfg->callback;
instance->p_ctx = cfg->p_ctx;
goto finally;
@ -84,304 +139,100 @@ __attribute__ ((visibility ("default") ))
void
aisl_free( aisl_t instance )
{
if (instance->srv)
{
aisl_server_t * srv = instance->srv;
while (*srv)
{
aisl_server_free(*srv);
srv++;
}
free(instance->srv);
}
list_release(&instance->client_spool, (list_destructor_t) aisl_client_free );
list_release(&instance->server_spool, (list_destructor_t) aisl_server_free );
#ifndef AISL_WITHOUT_SSL
list_release(&instance->ssl_spool, (list_destructor_t) aisl_ssl_free );
#endif
if (instance->ssl)
{
aisl_ssl_t * ssl = instance->ssl;
if (instance->last_error)
free(instance->last_error);
while (*ssl)
{
aisl_ssl_free(*ssl);
ssl++;
}
free(instance);
free(instance->ssl);
}
#ifndef AISL_WITHOUT_SSL
if ((--m_instances) == 0)
{
EVP_cleanup();
}
#endif
}
__attribute__ ((visibility ("default") ))
aisl_server_t
aisl_listen( aisl_t instance, const char * address, uint16_t port )
{
aisl_server_t result;
if ( (result = aisl_server_new(instance, address, port)) != NULL )
{
if (list_append(&instance->server_spool, result) == -1)
{
aisl_server_free(result);
}
}
return result;
free(instance);
}
#ifndef AISL_WITHOUT_SSL
static int
aisl_on_get_ssl( SSL * ssl, int * ptr, void * instance )
{
const char * server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
SSL_CTX * ctx = aisl_get_ssl_ctx( (aisl_t) instance, server_name );
if (ctx)
{
SSL_set_SSL_CTX(ssl, ctx);
}
(void)ptr;
return SSL_TLSEXT_ERR_OK;
}
static aisl_status_t
aisl_set_ssl_ctx(aisl_t instance, aisl_ssl_t ssl)
{
const SSL_METHOD * method;
SSL_CTX * ctx;
method = SSLv23_server_method();
if ( (ctx = SSL_CTX_new(method)) != NULL )
{
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tlsext_servername_callback( ctx, aisl_on_get_ssl );
SSL_CTX_set_tlsext_servername_arg( ctx, (void *) instance );
if (!(SSL_CTX_use_certificate_file(ctx, ssl->crt_file, SSL_FILETYPE_PEM)>0))
goto except;
if (!(SSL_CTX_use_PrivateKey_file(ctx, ssl->key_file, SSL_FILETYPE_PEM)>0))
goto except;
ssl->ctx = ctx;
return AISL_SUCCESS;
}
except:
SSL_CTX_free(ctx);
aisl_set_error( instance, ERR_error_string(ERR_get_error(),NULL) );
return AISL_SYSCALL_ERROR;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_ssl( aisl_t instance, const char * host,
const char * key_file,
const char * crt_file )
{
SSL_CTX * ssl_ctx = NULL;
aisl_ssl_t ssl;
size_t i;
/* lookup for existing contexts */
for (i=0; i<instance->ssl_spool.count; i++)
{
ssl = LIST_INDEX(instance->ssl_spool, i);
if (ssl->key_file && strcmp(ssl->key_file, key_file)==0 &&
ssl->crt_file && strcmp(ssl->crt_file, crt_file)==0 )
{
ssl_ctx = ssl->ctx;
break;
}
}
if ((ssl = aisl_ssl_new(host, key_file, crt_file, ssl_ctx)) != NULL)
{
if (!ssl_ctx || (aisl_set_ssl_ctx(instance, ssl) == AISL_SUCCESS))
{
if (list_append(&instance->ssl_spool, ssl) != -1)
return AISL_SUCCESS;
}
aisl_ssl_free(ssl);
}
return AISL_MALLOC_ERROR;
}
SSL_CTX *
aisl_get_ssl_ctx( aisl_t instance, const char * host )
{
size_t i;
aisl_ssl_t ssl;
aisl_ssl_t * list = instance->ssl,
ssl;
if (host)
{
for (i=0; i<instance->ssl_spool.count; i++)
while ( (ssl = *list) )
{
ssl = LIST_INDEX(instance->ssl_spool, i);
if (strcmp(ssl->host, host) != 0)
continue;
if (str_cmpi(ssl->host, host) == 0)
{
return ssl->ctx;
}
return ssl->ctx;
list++;
}
}
return NULL;
}
#endif
__attribute__ ((visibility ("default") ))
void
aisl_set_callback( aisl_t instance,
aisl_event_t event,
aisl_callback_t callback )
aisl_raise_evt( aisl_t instance, aisl_evt_t const evt )
{
switch( event )
{
case AISL_EVENT_SERVER_OPEN:
instance->on_server_open = (aisl_on_server_open_t) callback;
break;
#ifdef AISL_WITHOUT_STRINGIFIERS
DPRINTF("! %d", evt->code);
#else
DPRINTF("! %s", aisl_evt_code_to_string(evt->code));
#endif
case AISL_EVENT_SERVER_ERROR:
instance->on_server_error = (aisl_on_server_error_t) callback;
break;
case AISL_EVENT_CLIENT_CONNECT:
instance->on_client_connect = (aisl_on_client_connect_t) callback;
break;
case AISL_EVENT_CLIENT_DISCONNECT:
instance->on_client_disconnect = (aisl_on_client_disconnect_t) callback;
break;
case AISL_EVENT_CLIENT_TIMEOUT:
instance->on_client_timeout = (aisl_on_client_timeout_t) callback;
break;
case AISL_EVENT_STREAM_OPEN:
instance->on_stream_open = (aisl_on_stream_open_t) callback;
break;
case AISL_EVENT_STREAM_HEADER:
instance->on_stream_header = (aisl_on_stream_header_t) callback;
break;
case AISL_EVENT_STREAM_INPUT:
instance->on_stream_input = (aisl_on_stream_input_t) callback;
break;
case AISL_EVENT_STREAM_REQUEST:
instance->on_stream_request = (aisl_on_stream_request_t) callback;
break;
case AISL_EVENT_STREAM_OUTPUT:
instance->on_stream_output = (aisl_on_stream_output_t) callback;
break;
case AISL_EVENT_STREAM_CLOSE:
instance->on_stream_close = (aisl_on_stream_close_t) callback;
break;
case AISL_EVENT_STREAM_ERROR:
instance->on_stream_error = (aisl_on_stream_error_t) callback;
break;
}
if (instance->callback)
instance->callback(evt, instance->p_ctx);
}
void
aisl_raise( aisl_t instance, void * source, aisl_event_t event, ... )
aisl_raise( aisl_t instance,
void * source,
aisl_evt_code_t code,
aisl_status_t status )
{
DPRINTF("event %s", aisl_event_to_string(event));
struct aisl_evt evt;
va_list vl;
evt.source = source;
evt.code = code;
evt.status = status;
va_start(vl, event);
switch( event )
{
case AISL_EVENT_SERVER_OPEN:
if (instance->on_server_open)
instance->on_server_open((aisl_server_t)source);
break;
case AISL_EVENT_SERVER_ERROR:
if (instance->on_server_error)
instance->on_server_error((aisl_server_t)source);
break;
case AISL_EVENT_CLIENT_CONNECT:
if (instance->on_client_connect)
instance->on_client_connect((aisl_client_t)source);
break;
case AISL_EVENT_CLIENT_DISCONNECT:
if (instance->on_client_disconnect)
instance->on_client_disconnect((aisl_client_t)source);
break;
case AISL_EVENT_CLIENT_TIMEOUT:
if (instance->on_client_timeout)
instance->on_client_timeout((aisl_client_t)source);
break;
case AISL_EVENT_STREAM_OPEN:
if (instance->on_stream_open)
{
aisl_http_method_t method = va_arg(vl, aisl_http_method_t);
const char * path = va_arg(vl, const char *);
const char * query = va_arg(vl, const char *);
instance->on_stream_open((aisl_stream_t)source, method, path, query);
}
break;
case AISL_EVENT_STREAM_HEADER:
if (instance->on_stream_header)
{
const char * key = va_arg(vl, const char *);
const char * val = va_arg(vl, const char *);
instance->on_stream_header((aisl_stream_t)source, key, val);
}
break;
case AISL_EVENT_STREAM_INPUT:
if (instance->on_stream_input)
{
const char * data = va_arg(vl, const char *);
int32_t size = va_arg(vl, int32_t);
instance->on_stream_input((aisl_stream_t)source, data, size);
}
break;
case AISL_EVENT_STREAM_REQUEST:
if (instance->on_stream_request)
instance->on_stream_request((aisl_stream_t)source);
break;
case AISL_EVENT_STREAM_OUTPUT:
if (instance->on_stream_output)
instance->on_stream_output((aisl_stream_t)source);
break;
case AISL_EVENT_STREAM_CLOSE:
if (instance->on_stream_close)
instance->on_stream_close((aisl_stream_t)source);
break;
case AISL_EVENT_STREAM_ERROR:
if (instance->on_stream_error)
instance->on_stream_error((aisl_stream_t)source);
break;
}
va_end(vl);
aisl_raise_evt(instance, &evt);
}
@ -391,103 +242,49 @@ aisl_run_cycle( aisl_t instance )
{
aisl_status_t result = AISL_IDLE;
int32_t i = instance->iterator,
max = instance->server_spool.count + instance->client_spool.count;
aisl_server_t * list = instance->srv,
srv;
aisl_client_t cli;
while ( result == AISL_IDLE && max != 0)
while ( (srv = *list) )
{
aisl_client_t cli = NULL;
cli = NULL;
if (i < instance->server_spool.count)
if (aisl_server_touch(srv, &cli) != AISL_IDLE)
result = AISL_SUCCESS;
if (cli)
{
if (instance->client_spool.count < instance->accept_limit)
{
aisl_server_t srv;
/* SSL_CTX * ssl_ctx; */
srv = (aisl_server_t) LIST_INDEX(instance->server_spool, i);
/*
ssl_ctx = (aisl_server_get_ssl(srv)) ?
aisl_get_ssl_ctx(instance, NULL) :
NULL;
*/
result = aisl_server_touch(srv, &cli);
if (cli)
{
DPRINTF("Accepted %p", (void*)cli);
if ( list_append(&instance->client_spool, cli) != -1 )
{
aisl_raise(instance, cli, AISL_EVENT_CLIENT_CONNECT);
}
else
{
aisl_client_free(cli);
/* todo: save error message here */
}
}
}
else
{
i = instance->server_spool.count;
continue;
}
}
else
{
int32_t j = i - instance->server_spool.count;
if (j < instance->client_spool.count)
{
aisl_client_t c = LIST_INDEX(instance->client_spool, j);
result = aisl_client_touch(c);
if (aisl_client_is_timed_out( c, instance->silence_timeout ) )
aisl_raise( instance, c, AISL_EVENT_CLIENT_TIMEOUT );
if ( !aisl_client_is_online(c) )
{
aisl_client_free( c );
list_remove_index(&instance->client_spool, j);
}
}
else
{
i = 0;
continue;
}
DPRINTF("Accepted %p", (void*)cli);
if ( list_append(&instance->client_spool, cli) == -1 )
aisl_client_free(cli);
}
max--;
i++;
list++;
}
instance->iterator = i;
for (int32_t i=0; i < instance->client_spool.count; i++)
{
cli = LIST_INDEX(instance->client_spool, i);
if (aisl_client_touch(cli, instance->silence_timeout) != AISL_IDLE)
result = AISL_SUCCESS;
/* if (aisl_client_is_timed_out( c, instance->silence_timeout ) )
aisl_raise( instance, c, AISL_EVENT_CLIENT_TIMEOUT );
*/
if ( !aisl_client_is_online(cli) )
{
aisl_client_free( cli );
list_remove_index(&instance->client_spool, i);
}
}
return result;
}
__attribute__ ((visibility ("default") ))
const char *
aisl_get_error( aisl_t instance )
{
return instance->last_error;
}
void
aisl_set_error( aisl_t instance, const char * err_msg )
{
if (instance->last_error)
free(instance->last_error);
instance->last_error = str_copy(err_msg);
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_sleep( aisl_t instance, uint32_t usec )
@ -503,19 +300,21 @@ aisl_sleep( aisl_t instance, uint32_t usec )
fd_set fs;
FD_ZERO (&fs);
for (i=0; i<instance->server_spool.count; i++)
{
aisl_server_t s = LIST_INDEX(instance->server_spool, i);
aisl_server_t * list = instance->srv,
srv;
sd = aisl_server_get_socket(s);
while ( (srv = *list) )
{
sd = aisl_server_get_socket(srv);
if (sd != -1)
{
FD_SET(sd, &fs);
if (sd > maxfd) maxfd = sd;
}
}
list++;
}
for (i=0; i<instance->client_spool.count; i++)
{

View File

@ -15,37 +15,23 @@
#endif
#include <aisl/instance.h>
#include "ssl.h"
#include "list.h"
struct aisl
{
struct list server_spool;
struct list client_spool;
aisl_server_t * srv;
#ifndef AISL_WITHOUT_SSL
struct list ssl_spool;
aisl_ssl_t * ssl;
#endif
struct list client_spool;
aisl_callback_t callback;
void * p_ctx;
char * last_error;
int32_t iterator;
uint32_t accept_limit;
uint32_t silence_timeout;
/* callbacks */
aisl_on_server_open_t on_server_open;
aisl_on_server_error_t on_server_error;
aisl_on_client_connect_t on_client_connect;
aisl_on_client_disconnect_t on_client_disconnect;
aisl_on_client_timeout_t on_client_timeout;
aisl_on_stream_open_t on_stream_open;
aisl_on_stream_header_t on_stream_header;
aisl_on_stream_input_t on_stream_input;
aisl_on_stream_request_t on_stream_request;
aisl_on_stream_output_t on_stream_output;
aisl_on_stream_close_t on_stream_close;
aisl_on_stream_error_t on_stream_error;
uint32_t accept_limit;
uint32_t silence_timeout;
uint32_t buffer_size;
};
@ -61,24 +47,19 @@ aisl_get_ssl_ctx( aisl_t instance, const char * server_name );
#endif
/**
* @brief Sets error message for AISL instace.
* @param instance a pointer to #aisl_t instance.
* @param err_msge a null-terminated string with error message.
*/
void
aisl_set_error( aisl_t instance, const char * err_msg );
/**
* @brief Raises event from source.
* @param instance a pointer to #aisl_t instance.
* @param source a pointer to an event source.
* @param event a code of event.
* @param ... a list of arguments specific for event.
* @param evt a pointer to event structure.
*/
void
aisl_raise( aisl_t instance, void * source, aisl_event_t event, ... );
aisl_raise_evt( aisl_t instance, aisl_evt_t const evt );
void
aisl_raise( aisl_t instance,
void * source,
aisl_evt_code_t code,
aisl_status_t status );
#endif /* !AISL_INSTANCE_H */

View File

@ -22,9 +22,6 @@
#include "server.h"
/**
* @brief Creates TCP server socket, binds to address and starts to listen.
* @param server a pointer to #aisl_server_t instance.
@ -101,8 +98,6 @@ aisl_server_accept( aisl_server_t server,
else if (errno == EWOULDBLOCK)
return AISL_IDLE;
aisl_raise( server->instance, server, AISL_EVENT_SERVER_ERROR );
return AISL_SYSCALL_ERROR;
}
@ -116,13 +111,17 @@ aisl_server_touch( aisl_server_t server,
if (server->fd == -1)
{
aisl_event_t event;
result = aisl_server_open(server);
event = (result == AISL_SUCCESS) ? AISL_EVENT_SERVER_OPEN
: AISL_EVENT_SERVER_ERROR;
aisl_raise(server->instance, server, event);
if ((result = aisl_server_open(server)) != AISL_IDLE)
{
aisl_raise(
server->instance,
server,
((result == AISL_SUCCESS) ? AISL_EVENT_SERVER_OPEN
: AISL_EVENT_SERVER_ERROR),
result
);
}
}
else
result = aisl_server_accept(server, p_client);
@ -141,7 +140,7 @@ aisl_server_get_socket( aisl_server_t server )
/* API Level ---------------------------------------------------------------- */
aisl_server_t
aisl_server_new(aisl_t instance, const char * host, uint16_t port)
aisl_server_new(aisl_cfg_srv_t const cfg_srv, aisl_t instance)
{
aisl_server_t server;
@ -150,8 +149,9 @@ aisl_server_new(aisl_t instance, const char * host, uint16_t port)
server->instance = instance;
server->fd = -1;
server->address.sin_family = AF_INET;
server->address.sin_addr.s_addr = inet_addr(host);
server->address.sin_port = htons(port);
server->address.sin_addr.s_addr = inet_addr(cfg_srv->host);
server->address.sin_port = htons(cfg_srv->port);
server->ssl = cfg_srv->secure;
}
return server;
@ -174,13 +174,6 @@ aisl_server_free(aisl_server_t server)
}
aisl_t
aisl_server_get_instance( aisl_server_t server )
{
return server->instance;
}
void
aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address)
{
@ -190,13 +183,6 @@ aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address)
#ifndef AISL_WITHOUT_SSL
void
aisl_server_set_ssl( aisl_server_t server, bool value )
{
server->ssl = value;
}
bool
aisl_server_get_ssl( aisl_server_t server )
{

View File

@ -10,6 +10,7 @@
#ifndef AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
#define AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
#include <aisl/config.h>
#include <aisl/server.h>
#define AISL_SERVER(x) ((aisl_server_t) x)
@ -27,13 +28,12 @@ struct aisl_server
/**
* @brief Allocates and instance of #aisl_server_t.
* @param cfg_srv a pointer to server configuration structure.
* @param instance a pointer to #aisl_t instance.
* @param host a null-terminated string with address to listen to.
* @param port a TCP server port number to listen to.
* @return a pointer to #aisl_server_t instance.
*/
aisl_server_t
aisl_server_new(aisl_t instance, const char * host, uint16_t port);
aisl_server_new(aisl_cfg_srv_t const cfg_srv, aisl_t instance);
/**

View File

@ -6,13 +6,60 @@
*/
#include <openssl/err.h>
#include "ssl.h"
#include "str-utils.h"
#include "instance.h"
#include "ssl.h"
#ifndef AISL_WITHOUT_SSL
static int
aisl_ssl_on_get_ctx( SSL * ssl, int * ptr, void * instance )
{
const char * server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
SSL_CTX * ctx = aisl_get_ssl_ctx( (aisl_t) instance, server_name );
if (ctx)
{
SSL_set_SSL_CTX(ssl, ctx);
}
(void)ptr;
return SSL_TLSEXT_ERR_OK;
}
SSL_CTX *
aisl_ssl_get_ctx(aisl_ssl_t ssl, void * p_instance)
{
SSL_CTX * ctx;
if ( (ctx = SSL_CTX_new(SSLv23_server_method())) != NULL )
{
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tlsext_servername_callback( ctx, aisl_ssl_on_get_ctx );
SSL_CTX_set_tlsext_servername_arg( ctx, p_instance );
if (!(SSL_CTX_use_certificate_file(ctx, ssl->crt_file, SSL_FILETYPE_PEM)>0))
goto except;
if (!(SSL_CTX_use_PrivateKey_file(ctx, ssl->key_file, SSL_FILETYPE_PEM)>0))
goto except;
ssl->ctx = ctx;
return ctx;
}
except:
SSL_CTX_free(ctx);
return NULL;
}
aisl_ssl_t
aisl_ssl_new( const char * key_file,
const char * crt_file,

View File

@ -10,6 +10,7 @@
#ifndef AISL_SSL_H_6F82B0BA_7C59_45BA_AF3B_C82A67C8585E
#define AISL_SSL_H_6F82B0BA_7C59_45BA_AF3B_C82A67C8585E
#include <aisl/config.h>
#include <aisl/types.h>
#include <openssl/ssl.h>
@ -32,6 +33,10 @@ aisl_ssl_new( const char * key_file,
SSL_CTX * ctx );
SSL_CTX *
aisl_ssl_get_ctx(aisl_ssl_t ssl, void * p_instance);
void
aisl_ssl_free( aisl_ssl_t ssl );

View File

@ -25,11 +25,12 @@ aisl_stream_reset(aisl_stream_t stream, bool initial)
{
if (!initial)
{
aisl_t instance;
instance = aisl_stream_get_instance(stream);
aisl_raise(instance, stream, AISL_EVENT_STREAM_CLOSE);
aisl_raise(
aisl_stream_get_instance(stream)
, (void*) stream
, AISL_EVENT_STREAM_CLOSE
, AISL_SUCCESS
);
}
buffer_release(&stream->buffer);
@ -134,6 +135,7 @@ aisl_stream_set_request( aisl_stream_t stream,
const char * path,
const char * query )
{
struct aisl_evt_stream_open on_open;
stream->state = AISL_STREAM_STATE_WAIT_HEADER;
@ -144,22 +146,24 @@ aisl_stream_set_request( aisl_stream_t stream,
, query
);
aisl_raise(
aisl_stream_get_instance(stream),
stream,
AISL_EVENT_STREAM_OPEN,
http_method,
path,
query
);
on_open.evt.code = AISL_EVENT_STREAM_OPEN;
on_open.evt.source = (void *) stream;
on_open.evt.status = AISL_SUCCESS;
on_open.http_method = http_method;
on_open.path = path;
on_open.query = query;
aisl_raise_evt(aisl_stream_get_instance(stream), (aisl_evt_t)&on_open);
}
void
aisl_stream_set_header( aisl_stream_t stream,
const char * key,
const char * value )
aisl_stream_set_header( aisl_stream_t stream,
const char * key,
const char * value )
{
struct aisl_evt_stream_header on_header;
if (stream->state != AISL_STREAM_STATE_WAIT_HEADER)
return;
@ -173,13 +177,13 @@ aisl_stream_set_header( aisl_stream_t stream,
DPRINTF("%s: %s", key, value);
aisl_raise(
aisl_stream_get_instance(stream),
stream,
AISL_EVENT_STREAM_HEADER,
key,
value
);
on_header.evt.code = AISL_EVENT_STREAM_HEADER;
on_header.evt.source = (void *) stream;
on_header.evt.status = AISL_SUCCESS;
on_header.key = key;
on_header.value = value;
aisl_raise_evt(aisl_stream_get_instance(stream), (aisl_evt_t)&on_header);
}
@ -208,6 +212,8 @@ aisl_stream_set_body( aisl_stream_t stream, const char * data, int32_t size )
{
if ( !(stream->content_length < size) )
{
struct aisl_evt_stream_input on_input;
if (stream->content_length == 0)
{
stream->state = AISL_STREAM_STATE_READY;
@ -216,13 +222,13 @@ aisl_stream_set_body( aisl_stream_t stream, const char * data, int32_t size )
else
result = 1;
aisl_raise(
aisl_stream_get_instance(stream),
stream,
AISL_EVENT_STREAM_OUTPUT,
data,
size
);
on_input.evt.code = AISL_EVENT_STREAM_INPUT;
on_input.evt.source = (void *) stream;
on_input.evt.status = AISL_SUCCESS;
on_input.data = data;
on_input.size = size;
aisl_raise_evt(stream->client->server->instance, (aisl_evt_t)&on_input);
}
else
result = -1;
@ -295,7 +301,7 @@ __attribute__ ((visibility ("default") ))
void
aisl_reject(aisl_stream_t s)
{
aisl_client_close( s->client );
aisl_client_disconnect( s->client );
}
@ -662,5 +668,5 @@ __attribute__ ((visibility ("default") ))
aisl_t
aisl_stream_get_instance(aisl_stream_t stream)
{
return aisl_server_get_instance(aisl_client_get_server(stream->client));
return stream->client->server->instance;
}

View File

@ -37,22 +37,21 @@ aisl_status_to_string(aisl_status_t status)
__attribute__ ((visibility ("default") ))
const char *
aisl_event_to_string( aisl_event_t event )
aisl_evt_code_to_string( aisl_evt_code_t evt_code )
{
switch(event)
switch(evt_code)
{
case AISL_EVENT_SERVER_OPEN: return "SERVER_OPEN";
case AISL_EVENT_SERVER_ERROR: return "SERVER_ERROR";
case AISL_EVENT_CLIENT_CONNECT: return "CLIENT_CONNECT";
case AISL_EVENT_CLIENT_DISCONNECT: return "CLIENT_DISCONNECT";
case AISL_EVENT_CLIENT_TIMEOUT: return "CLIENT_TIMEOUT";
case AISL_EVENT_STREAM_OPEN: return "STREAM_OPEN";
case AISL_EVENT_STREAM_HEADER: return "STREAM_HEADER";
case AISL_EVENT_STREAM_INPUT: return "STREAM_INPUT";
case AISL_EVENT_STREAM_REQUEST: return "STREAM_REQUEST";
case AISL_EVENT_STREAM_OUTPUT: return "STREAM_OUTPUT";
case AISL_EVENT_STREAM_CLOSE: return "STREAM_CLOSE";
case AISL_EVENT_STREAM_ERROR: return "STREAM_ERROR";
case AISL_EVENT_SERVER_OPEN: return "SERVER OPEN";
case AISL_EVENT_SERVER_ERROR: return "SERVER ERROR";
case AISL_EVENT_CLIENT_CONNECT: return "CLIENT CONNECT";
case AISL_EVENT_CLIENT_DISCONNECT: return "CLIENT DISCONNECT";
case AISL_EVENT_STREAM_OPEN: return "STREAM OPEN";
case AISL_EVENT_STREAM_HEADER: return "STREAM HEADER";
case AISL_EVENT_STREAM_INPUT: return "STREAM INPUT";
case AISL_EVENT_STREAM_REQUEST: return "STREAM REQUEST";
case AISL_EVENT_STREAM_OUTPUT: return "STREAM OUTPUT";
case AISL_EVENT_STREAM_CLOSE: return "STREAM CLOSE";
case AISL_EVENT_STREAM_ERROR: return "STREAM ERROR";
}
return "UNKNOWN";