From d87c7454b594eff1669d5d59114da6e99323cd5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilja=20Karta=C5=A1ov?= Date: Tue, 5 Mar 2019 22:16:00 +0100 Subject: [PATCH] Refactoring pending --- include/aisl/aisl.h | 13 +- include/aisl/callback.h | 76 ------ include/aisl/client.h | 2 +- include/aisl/event.h | 42 --- include/aisl/http.h | 104 -------- include/aisl/instance.h | 57 ++-- include/aisl/server.h | 3 +- include/aisl/status.h | 29 -- include/aisl/stream.h | 11 +- include/aisl/types.h | 243 +++++++++++++++++ src/aisl.c | 376 -------------------------- src/aisl.h | 19 -- src/client.c | 15 ++ src/client.h | 44 +--- src/globals.h | 7 +- src/instance.c | 572 ++++++++++++++++++++++++++++++++++++++++ src/instance.h | 5 + src/server.c | 18 +- src/server.h | 44 +--- src/stream.c | 252 +++++++++++++++++- src/stream.h | 39 +-- 21 files changed, 1180 insertions(+), 791 deletions(-) delete mode 100644 include/aisl/callback.h delete mode 100644 include/aisl/event.h delete mode 100644 include/aisl/http.h delete mode 100644 include/aisl/status.h create mode 100644 include/aisl/types.h delete mode 100644 src/aisl.c delete mode 100644 src/aisl.h diff --git a/include/aisl/aisl.h b/include/aisl/aisl.h index 4267256..798c134 100644 --- a/include/aisl/aisl.h +++ b/include/aisl/aisl.h @@ -13,14 +13,8 @@ /* AISL configuration structure */ #include -/* AISL status codes and utilities */ -#include - -/* AISL callbacks definitions */ -#include - -/* AISL events enumeration and utilities*/ -#include +/* AISL types and stringifiers */ +#include /* AISL instancing, initialization and processing */ #include @@ -34,7 +28,4 @@ /* HTTP(s) streaming */ #include -/* HTTP constants and utilities */ -#include - #endif /* !AISL_H */ diff --git a/include/aisl/callback.h b/include/aisl/callback.h deleted file mode 100644 index 97f128b..0000000 --- a/include/aisl/callback.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * - * Copyright (c) 2017 by Löwenware Ltd. - * - * Project homepage: https://lowenware.com/aisl/ - * - */ - -#ifndef AISL_CALLBACK_H_E99458C9_CCAA_4CAC_97F8_41E8869EE26F -#define AISL_CALLBACK_H_E99458C9_CCAA_4CAC_97F8_41E8869EE26F - -#include -#include -#include - -#include -#include -#include -#include - -#define AISL_CALLBACK(x) ((aisl_callback_t) x) - - -/* void-type callback */ -typedef void -(* aisl_callback_t) (void); - - -/* real type callbacks */ - -typedef bool -(*aisl_server_open_t)( aisl_server_t server, int flags ); - -typedef bool -(*aisl_server_error_t)( aisl_server_t server, int flags, const char * details ); - -typedef bool -(*aisl_client_connect_t)( aisl_server_t server, aisl_client_t client ); - -typedef bool -(*aisl_client_disconnect_t)( aisl_server_t server, aisl_client_t client ); - -typedef bool -(*aisl_client_timeout_t)( aisl_server_t server, aisl_client_t client ); - -typedef bool -(*aisl_stream_open_t)( aisl_stream_t stream, - aisl_http_method_t method, - const char * path, - const char * query ); - -typedef bool -(*aisl_stream_header_t)( aisl_stream_t stream, - const char * key, - const char * val ); - -typedef bool -(*aisl_stream_input_t)( aisl_stream_t stream, char * data, int len ); - -typedef bool -(*aisl_stream_request_t)( aisl_stream_t stream ); - -typedef bool -(*aisl_stream_output_t)( aisl_stream_t stream, uint32_t buffer_space ); - -typedef bool -(*aisl_stream_close_t)( aisl_stream_t stream ); - -typedef bool -(*aisl_stream_error_t)( aisl_stream_t stream, const char * details ); - -typedef bool -(*aisl_custom_event_t)( void * source, va_list vl ); - -#endif /* !AISL_CALLBACK_H */ diff --git a/include/aisl/client.h b/include/aisl/client.h index 2016132..ea80a43 100644 --- a/include/aisl/client.h +++ b/include/aisl/client.h @@ -10,6 +10,6 @@ #ifndef AISL_CLIENT_H_A6C37DCF_2183_4F22_A5A0_668311757A08 #define AISL_CLIENT_H_A6C37DCF_2183_4F22_A5A0_668311757A08 -typedef struct aisl_client * aisl_client_t; +#include #endif /* !AISL_CLIENT_H */ diff --git a/include/aisl/event.h b/include/aisl/event.h deleted file mode 100644 index 2d9852b..0000000 --- a/include/aisl/event.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * - * Copyright (c) 2017 by Löwenware Ltd. - * - * Project homepage: https://lowenware.com/aisl/ - * - */ - -#ifndef AISL_EVENT_H_E99458C9_CCAA_4CAC_97F8_41E8869EE26F -#define AISL_EVENT_H_E99458C9_CCAA_4CAC_97F8_41E8869EE26F - -#include - -enum -{ - AISL_SERVER_OPEN = 100 - , AISL_SERVER_ERROR = 190 - - , AISL_CLIENT_CONNECT = 200 - , AISL_CLIENT_DISCONNECT = 210 - , AISL_CLIENT_TIMEOUT = 220 - - , AISL_STREAM_OPEN = 300 - , AISL_STREAM_HEADER = 310 - , AISL_STREAM_INPUT = 320 - , AISL_STREAM_REQUEST = 330 - , AISL_STREAM_OUTPUT = 340 - , AISL_STREAM_CLOSE = 350 - , AISL_STREAM_ERROR = 390 - - , AISL_EVENTS_CUSTOM = 1000 - -}; - -typedef uint32_t aisl_event_t; - - -const char * -aisl_event_get_text( aisl_event_t event ); - -#endif /* !AISL_EVENT_H */ diff --git a/include/aisl/http.h b/include/aisl/http.h deleted file mode 100644 index 1260eaf..0000000 --- a/include/aisl/http.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * aisl/http.h - * - * Copyright (c) 2017 by Löwenware Ltd. - * - * Project homepage: https://lowenware.com/aisl/ - * - */ - -#ifndef AISL_HTTP_H_2BB40A17_5EB3_438B_8A98_EB3C68BA3A45 -#define AISL_HTTP_H_2BB40A17_5EB3_438B_8A98_EB3C68BA3A45 - - -typedef enum -{ - AISL_HTTP_1_0 - , AISL_HTTP_1_1 - , AISL_HTTP_2_0 - -} aisl_http_version_t; - -typedef enum -{ - AISL_HTTP_GET - , AISL_HTTP_PUT - , AISL_HTTP_POST - , AISL_HTTP_HEAD - , AISL_HTTP_TRACE - , AISL_HTTP_DELETE - , AISL_HTTP_OPTIONS - , AISL_HTTP_CONNECT - - , AISL_HTTP_PRI - -} aisl_http_method_t; - -typedef enum -{ - AISL_HTTP_CONTINUE = 100 - , AISL_HTTP_SWITCHING_PROTOCOLS - - , AISL_HTTP_OK = 200 - , AISL_HTTP_CREATED - , AISL_HTTP_ACCEPTED - , AISL_HTTP_NON_AUTHORITATIVE_INFORMATION - , AISL_HTTP_NO_CONTENT - , AISL_HTTP_RESET_CONTENT - , AISL_HTTP_PARTIAL_CONTENT - - , AISL_HTTP_MULTIPLE_CHOICES = 300 - , AISL_HTTP_MOVED_PERMANENTLY - , AISL_HTTP_FOUND - , AISL_HTTP_SEE_OTHER - , AISL_HTTP_NOT_MODIFIED - , AISL_HTTP_USE_PROXY - , AISL_HTTP_UNUSED - , AISL_HTTP_TEMPORARY_REDIRECT - - , AISL_HTTP_BAD_REQUEST = 400 - , AISL_HTTP_UNAUTHORIZED - , AISL_HTTP_PAYMENT_REQUIRED - , AISL_HTTP_FORBIDDEN - , AISL_HTTP_NOT_FOUND - , AISL_HTTP_METHOD_NOT_ALLOWED - , AISL_HTTP_NOT_ACCEPTABLE - , AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED - , AISL_HTTP_REQUEST_TIMEOUT - , AISL_HTTP_CONFLICT - , AISL_HTTP_GONE - , AISL_HTTP_LENGTH_REQUIRED - , AISL_HTTP_PRECONDITION_FAILED - , AISL_HTTP_REQUEST_ENTITY_TOO_LARGE - , AISL_HTTP_REQUEST_URI_TOO_LONG - , AISL_HTTP_UNSUPPORTED_MEDIA_TYPE - , AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE - , AISL_HTTP_EXPECTATION_FAILED - - , AISL_HTTP_INTERNAL_SERVER_ERROR = 500 - , AISL_HTTP_NOT_IMPLEMENTED - , AISL_HTTP_BAD_GATEWAY - , AISL_HTTP_SERVICE_UNAVAILABLE - , AISL_HTTP_GATEWAY_TIMEOUT - , AISL_HTTP_VERSION_NOT_SUPPORTED - -} aisl_http_response_t; - - -const char * -aisl_http_version_to_string( aisl_http_version_t version ); - - -const char * -aisl_http_response_to_string( aisl_http_response_t code ); - - -const char * -aisl_http_secure_to_string( int is_secure ); - - -const char * -aisl_http_method_to_string( aisl_http_method_t method ); - - -#endif /* !AISL_HTTP_H */ diff --git a/include/aisl/instance.h b/include/aisl/instance.h index 584d273..177bc78 100644 --- a/include/aisl/instance.h +++ b/include/aisl/instance.h @@ -7,69 +7,76 @@ * */ -#ifndef INSTANCE_H_60576F41_454C_4189_B91A_F40501132230 -#define INSTANCE_H_60576F41_454C_4189_B91A_F40501132230 +#ifndef AISL_INSTANCE_H_60576F41_454C_4189_B91A_F40501132230 +#define AISL_INSTANCE_H_60576F41_454C_4189_B91A_F40501132230 #include #include +#include +#include -typedef struct aisl_instance * aisl_instance_t; - /* Initialization functions */ -aisl_instance_t -aisl_new( aisl_config_t * config ); +aisl_t +aisl_new( aisl_config_t config ); void -aisl_free( aisl_instance_t instance ); +aisl_free( aisl_t instance ); aisl_server_t -aisl_listen( aisl_instance_t instance, - const char * address, - uint16_t port ); +aisl_listen( aisl_t instance, const char * address, uint16_t port ); #ifdef AISL_WITH_SSL aisl_status_t -aisl_set_ssl( aisl_instance_t instance, +aisl_set_ssl( aisl_t instance, const char * hostname, const char * key_file, const char * crt_file ); #endif +/* Callbacks and Events functions */ aisl_status_t -aisl_set_callback( aisl_instance_t instance, +aisl_set_callback( aisl_t instance, void * source, - aisl_event_t e_id, - aisl_callback_t cb ); + aisl_event_t event, + aisl_callback_t callback ); + + +aisl_status_t +aisl_raise( aisl_t instance, void * source, aisl_event_t event, ... ); + + +aisl_status_t +aisl_raise_vl( aisl_t instance, + void * source, + aisl_event_t event, + va_list args ); + + +void +aisl_unset_callback_for( aisl_t instance, void * source ); /* Control functions */ aisl_status_t -aisl_run_cycle( aisl_instance_t instance ); +aisl_run_cycle( aisl_t instance ); const char * -aisl_get_error( aisl_instance_t instance ); +aisl_get_error( aisl_t instance ); aisl_status_t -aisl_sleep( aisl_instance_t instance, uint32_t usec ); +aisl_sleep( aisl_t instance, uint32_t usec ); -aisl_status_t -aisl_raise( aisl_instance_t instance, aisl_event_t event, ...); - - -aisl_status_t -aisl_raisev( aisl_instance_t instance, aisl_event_t event, va_list args); - -#endif /* !INSTANCE_H */ +#endif /* !AISL_INSTANCE_H */ diff --git a/include/aisl/server.h b/include/aisl/server.h index cc20e47..8f36b19 100644 --- a/include/aisl/server.h +++ b/include/aisl/server.h @@ -10,9 +10,8 @@ #ifndef AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768 #define AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768 -typedef struct aisl_server * aisl_server_t; - +#include #ifdef AISL_WITH_SSL aisl_status_t diff --git a/include/aisl/status.h b/include/aisl/status.h deleted file mode 100644 index 34e0e33..0000000 --- a/include/aisl/status.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * - * - * Copyright (c) 2017 by Löwenware Ltd. - * - * Project homepage: https://lowenware.com/aisl/ - * - */ - -#ifndef AISL_STATUS_H_BF7E4434_A711_4D7C_B3AE_1BA2E1A020EF -#define AISL_STATUS_H_BF7E4434_A711_4D7C_B3AE_1BA2E1A020EF - - -typedef enum -{ - AISL_EXTCALL_ERROR = -3 - , AISL_SYSCALL_ERROR = -2 - , AISL_MALLOC_ERROR = -1 - - , AISL_SUCCESS = 0 - , AISL_IDLE = 1 - -} aisl_status_t; - - -const char * -aisl_status_to_string(aisl_status_t status); - -#endif /* !AISL_STATUS_H */ diff --git a/include/aisl/stream.h b/include/aisl/stream.h index bb7822b..6a7055b 100644 --- a/include/aisl/stream.h +++ b/include/aisl/stream.h @@ -7,10 +7,13 @@ * */ -#ifndef STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC -#define STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC +#ifndef AISL_STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC +#define AISL_STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC + +#include +#include +#include -typedef struct aisl_stream * aisl_stream_t; /* Stream helpers */ @@ -31,7 +34,7 @@ aisl_http_version_t aisl_get_http_version( aisl_stream_t stream ); -aisl_instance_t +aisl_t aisl_stream_get_instance( aisl_stream_t s ); diff --git a/include/aisl/types.h b/include/aisl/types.h new file mode 100644 index 0000000..e975351 --- /dev/null +++ b/include/aisl/types.h @@ -0,0 +1,243 @@ +/* + * + * + * Copyright (c) 2017-2019 by Löwenware Ltd. + * + * Project homepage: https://lowenware.com/aisl/ + * + */ + +#ifndef AISL_TYPES_H_86A9DBA7_C0E6_4CF4_8A64_DAAD4A81031B +#define AISL_TYPES_H_86A9DBA7_C0E6_4CF4_8A64_DAAD4A81031B + +#include +#include +#include + +/* type casts */ +#define AISL_CALLBACK(x) ((aisl_callback_t) x) + + +/* 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; + +/* HTTP(s) Client */ +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 +{ + AISL_EXTCALL_ERROR = -3 + , AISL_SYSCALL_ERROR = -2 + , AISL_MALLOC_ERROR = -1 + + , AISL_SUCCESS = 0 + , AISL_IDLE = 1 + +} aisl_status_t; + +#ifdef WITH_STRINGIFIERS + +const char * +aisl_status_to_string(aisl_status_t status); + +#endif + +/* Generic HTTP Enumerations */ + +typedef enum +{ + AISL_HTTP_1_0 + , AISL_HTTP_1_1 + , AISL_HTTP_2_0 + +} aisl_http_version_t; + +#ifdef WITH_STRINGIFIERS + +const char * +aisl_http_version_to_string( aisl_http_version_t version ); + +#endif + + +typedef enum +{ + AISL_HTTP_GET + , AISL_HTTP_PUT + , AISL_HTTP_POST + , AISL_HTTP_HEAD + , AISL_HTTP_TRACE + , AISL_HTTP_DELETE + , AISL_HTTP_OPTIONS + , AISL_HTTP_CONNECT + + , AISL_HTTP_PRI + +} aisl_http_method_t; + +#ifdef WITH_STRINGIFIERS + +const char * +aisl_http_method_to_string( aisl_http_method_t method ); + +#endif + + +typedef enum +{ + AISL_HTTP_CONTINUE = 100 + , AISL_HTTP_SWITCHING_PROTOCOLS + + , AISL_HTTP_OK = 200 + , AISL_HTTP_CREATED + , AISL_HTTP_ACCEPTED + , AISL_HTTP_NON_AUTHORITATIVE_INFORMATION + , AISL_HTTP_NO_CONTENT + , AISL_HTTP_RESET_CONTENT + , AISL_HTTP_PARTIAL_CONTENT + + , AISL_HTTP_MULTIPLE_CHOICES = 300 + , AISL_HTTP_MOVED_PERMANENTLY + , AISL_HTTP_FOUND + , AISL_HTTP_SEE_OTHER + , AISL_HTTP_NOT_MODIFIED + , AISL_HTTP_USE_PROXY + , AISL_HTTP_UNUSED + , AISL_HTTP_TEMPORARY_REDIRECT + + , AISL_HTTP_BAD_REQUEST = 400 + , AISL_HTTP_UNAUTHORIZED + , AISL_HTTP_PAYMENT_REQUIRED + , AISL_HTTP_FORBIDDEN + , AISL_HTTP_NOT_FOUND + , AISL_HTTP_METHOD_NOT_ALLOWED + , AISL_HTTP_NOT_ACCEPTABLE + , AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED + , AISL_HTTP_REQUEST_TIMEOUT + , AISL_HTTP_CONFLICT + , AISL_HTTP_GONE + , AISL_HTTP_LENGTH_REQUIRED + , AISL_HTTP_PRECONDITION_FAILED + , AISL_HTTP_REQUEST_ENTITY_TOO_LARGE + , AISL_HTTP_REQUEST_URI_TOO_LONG + , AISL_HTTP_UNSUPPORTED_MEDIA_TYPE + , AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE + , AISL_HTTP_EXPECTATION_FAILED + + , AISL_HTTP_INTERNAL_SERVER_ERROR = 500 + , AISL_HTTP_NOT_IMPLEMENTED + , AISL_HTTP_BAD_GATEWAY + , AISL_HTTP_SERVICE_UNAVAILABLE + , AISL_HTTP_GATEWAY_TIMEOUT + , AISL_HTTP_VERSION_NOT_SUPPORTED + +} aisl_http_response_t; + +#ifdef WITH_STRINGIFIERS + +const char * +aisl_http_response_to_string( aisl_http_response_t code ); + +#endif + + +#ifdef WITH_STRINGIFIERS + +const char * +aisl_http_secure_to_string( bool is_secure ); + +#endif + + +/* Built-in Events IDs */ + +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 + , AISL_EVENT_STREAM_INPUT = 320 + , AISL_EVENT_STREAM_REQUEST = 330 + , AISL_EVENT_STREAM_OUTPUT = 340 + , AISL_EVENT_STREAM_CLOSE = 350 + , AISL_EVENT_STREAM_ERROR = 390 + + , AISL_EVENTS_CUSTOM = 1000 + +}; + +#ifdef WITH_STRINGIFIERS + +const char * +aisl_event_to_string( aisl_event_t event ); + +#endif + + +/* real type event callbacks */ + +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, char * data, size_t len ); + +typedef bool +(*aisl_on_stream_request_t)( aisl_stream_t stream ); + +typedef bool +(*aisl_on_stream_output_t)( aisl_stream_t stream, size_t buffer_space ); + +typedef bool +(*aisl_on_stream_close_t)( aisl_stream_t stream ); + +typedef bool +(*aisl_on_stream_error_t)( aisl_stream_t stream ); + +typedef bool +(*aisl_on_custom_event_t)( void * source, va_list vl ); + +#endif /* !AISL_TYPES_H */ diff --git a/src/aisl.c b/src/aisl.c deleted file mode 100644 index 86fd636..0000000 --- a/src/aisl.c +++ /dev/null @@ -1,376 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "aisl.h" -#include "list.h" -#include "str-utils.h" -#include "handle.h" -#include "client.h" -#include "server.h" -#include "globals.h" -#include "stream.h" -#include "buffer.h" - - -struct aisl_instance -{ - list_t * servers; - #ifdef AISL_WITH_SSL - list_t * ssl; - #endif - list_t servers; - list_t clients; - list_t callbacks; - buffer_t buffer; - char * last_error; - int iterator; - int stage; - int flags; - uint32_t accept_limit; -}; - - -#ifdef AISL_WITH_SSL -static uint32_t m_instances = 0; -#endif - -/* Initialization functions */ - -__attribute__ ((visibility ("default") )) -aisl_t -aisl_new( aisl_config_t * config ) -{ - aisl_t self; - - #ifdef AISL_WITH_SSL - if ((m_instances++) == 0) - { - SSL_load_error_strings(); - OpenSSL_add_ssl_algorithms(); - } - #endif - - if ( !(self = calloc(1, sizeof(struct aisl_instance))) ) - goto finally; - - if ( !(self->servers = list_new(config->servers_spool_size)) ) - goto release; - - if ( !(self->clients = list_new(config->clients_spool_size)) ) - goto release; - - if ( !(self->callbacks = list_new(config->callbacks_spool_size)) ) - goto release; - - if ( !(self->buffer = buffer_new(config->initial_buffer_size)) ) - goto release; - - #ifdef AISL_WITH_SSL - if ( !(self->ssl = list_new(config->ssl_spool_size)) ) - goto release; - #endif - - self->accept_limit = config->clients_accept_limit; - - goto finally; - -release: - aisl_free(self); - self = NULL; - -finally: - return self; -} - - -__attribute__ ((visibility ("default") )) -void -aisl_free( aisl_t self ) -{ - if (self->clients) - list_free(self->clients, (list_destructor_t) client_free ); - - if (self->servers) - list_free(self->servers, (list_destructor_t) server_free ); - - if (self->callbacks) - list_free(self->callbacks, free); - - if (self->buffer) - buffer_free(self->buffer); - - if (self->ssl) - list_free(self->ssl, (list_destructor_t) crypter_free ); - - if (self->last_error) - free(self->last_error); - - free(self); - - #ifdef AISL_WITH_SSL - if ((--m_instances) == 0) - { - EVP_cleanup(); - } - #endif -} - - -__attribute__ ((visibility ("default") )) -aisl_server_t -aisl_listen( aisl_instance_t instance, - const char * address, - uint16_t port ) -{ - aisl_server_t result; - - if ( (result = aisl_server_new(address, port)) != NULL ) - { - result->instance = instance; - - if (list_append(instance->servers, result) == LIST_NAN) - { - server_free(result); - } - } - - return result; -} - - -static char * -get_response_begin(stream_t stream) -{ - char * r; - client_t cli = CLIENT(ASTREAM(stream)->client); - - r = str_printf( - "%s %d %s\r\n" - "Server: AISL\r\n" - "Connection: %s\r\n\r\n", - aisl_http_version_to_string(cli->protocol), - stream->response, - aisl_http_response_to_string(stream->response), - ((cli->flags & CLIENT_FLAG_KEEPALIVE) ? "keep-alive" : "close") - ); - - return r; -} - -__attribute__ ((visibility ("default") )) -aisl_status_t -aisl_response(aisl_stream_t stream, aisl_http_response_t status_code, - const char *content_type, - uint32_t content_length) -{ - char * pch; - int l; - - - /* check if those headers were already sent */ - if (STREAM(stream)->state > STREAM_REQUEST_READY) return AISL_IDLE; - - STREAM(stream)->response = status_code; - STREAM(stream)->c_type = content_type; - STREAM(stream)->c_length = content_length; - - if ( !(pch = get_response_begin(STREAM(stream))) ) - return AISL_MALLOC_ERROR; - - l = strlen(pch); - STREAM(stream)->c_offset = l-2; - - buffer_clear(STREAM(stream)->buffer, content_length); - - l = buffer_add( STREAM(stream)->buffer, pch, l ); - free(pch); - - if (l == BUFFER_EOB) return AISL_MALLOC_ERROR; - - if (content_length) - { - if (!aisl_header_printf( stream, "Content-Length", "%u", content_length )) - return AISL_MALLOC_ERROR; - } - - if (content_type) - { - if (!aisl_header( stream, "Content-Type", content_type )) - return AISL_MALLOC_ERROR; - } - - STREAM(stream)->state = STREAM_RESPONSE_HEADER; - - return AISL_SUCCESS; -} - - -__attribute__ ((visibility ("default") )) -aisl_status_t -aisl_flush(aisl_stream_t stream) -{ - stream_t s = STREAM(stream); - if ( ! s->c_length ) - { - s->c_length = s->buffer->size - s->c_offset - 2; - if (!aisl_header_printf(stream, "Content-Length", "%u", s->c_length)) - return AISL_MALLOC_ERROR; - } - - /* - fprintf(stdout, "(%lu bytes)------->\n", STREAM(stream)->buffer->size); - fwrite(STREAM(stream)->buffer->data, 1, STREAM(stream)->buffer->size, stdout); - fprintf(stdout, "<------\n"); - */ - s->state = STREAM_RESPONSE_READY; - - s->flags |= STREAM_FLAG_OUTPUT_READY; - - return AISL_SUCCESS; -} - - -__attribute__ ((visibility ("default") )) -int -aisl_header(aisl_stream_t stream, const char *key, const char *value) -{ - int ret; - char * pch; - - if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL ) - { - ret = strlen(pch); - if ( buffer_insert( - STREAM(stream)->buffer, - STREAM(stream)->c_offset, - pch, - ret - ) == BUFFER_EOB ) - { - ret = -1; - } - else - STREAM(stream)->c_offset += ret; - - free(pch); - } - else - ret = -1; - - return ret; -} - - -__attribute__ ((visibility ("default") )) -int -aisl_header_printf(aisl_stream_t stream, const char *key, - const char *f_value, ...) -{ - int ret; - - va_list arg; - va_start(arg, f_value); - - ret = aisl_header_vprintf(stream, key, f_value, arg); - - va_end(arg); - - return ret; -} - - -__attribute__ ((visibility ("default") )) -int -aisl_header_vprintf(aisl_stream_t stream, const char *key, - const char *format, - va_list args) -{ - int ret; - char * value; - - if ( (value = str_vprintf(format, args)) != NULL ) - { - ret = aisl_header( stream, key, value ); - free(value); - } - else - ret = -1; - - return ret; -} - - -__attribute__ ((visibility ("default") )) -int -aisl_printf(aisl_stream_t stream, const char *format, ...) -{ - va_list arg; - va_start(arg, format); - - int result = aisl_vprintf(stream, format, arg); - - va_end(arg); - - /* No need to update length there, because vprintf do that - * - * if (STREAM(stream)->c_length_unknown) - STREAM(stream)->c_length += result; - */ - - - return result; - -} - - -__attribute__ ((visibility ("default") )) -int -aisl_vprintf(aisl_stream_t stream, const char *format, va_list args) -{ - int result; - char * r; - - if ( (r = str_vprintf(format, args)) != NULL) - { - result = strlen(r); - if (buffer_add(STREAM(stream)->buffer, r, result) == BUFFER_EOB) - result = -1; - - free(r); - } - else - result = -1; - - return result; -} - - -__attribute__ ((visibility ("default") )) -int -aisl_write(aisl_stream_t stream, const char *data, int d_len) -{ - if (d_len < 0) - d_len = strlen(data); - - if (buffer_add(STREAM(stream)->buffer, data, d_len) == BUFFER_EOB) - d_len = -1; - - return d_len; -} - - -__attribute__ ((visibility ("default") )) -int -aisl_puts(const char *str, aisl_stream_t stream) -{ - return aisl_write( stream, str, strlen(str)); -} - - diff --git a/src/aisl.h b/src/aisl.h deleted file mode 100644 index 7e25bd9..0000000 --- a/src/aisl.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * src/aisl.h - * - * Copyright (c) 2017 by Löwenware Ltd. - * - * Project homepage: https://lowenware.com/aisl/ - * - */ - -#ifndef AISL_H_F49DC34C_7EF3_44EF_8E4B_22F4CC1A665C -#define AISL_H_F49DC34C_7EF3_44EF_8E4B_22F4CC1A665C - -bool -aisl_raise_event( aisl_instance_t instance, - void * source, - aisl_event_t e_id, - ... ); - -#endif /* !AISL_H */ diff --git a/src/client.c b/src/client.c index 2f04654..9f37a55 100644 --- a/src/client.c +++ b/src/client.c @@ -15,7 +15,22 @@ #ifndef OUTPUT_BUFFER_SIZE #define OUTPUT_BUFFER_SIZE 4096 #endif +struct client +{ + struct sockaddr_in address; + server_t server; + int fd; + int next_id; /* server id generator (even, starts from 2) */ + int istream; /* input stream id */ + int ostream; /* output stream id */ + list_t streams; + SSL * ssl; + + time_t timestamp; + aisl_http_version_t protocol; + int flags; +}; /* -------------------------------------------------------------------------- */ void diff --git a/src/client.h b/src/client.h index dd6d34d..08bc834 100644 --- a/src/client.h +++ b/src/client.h @@ -1,67 +1,47 @@ -#ifndef _AISL_CLIENT_H_ -#define _AISL_CLIENT_H_ +#ifndef AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777 +#define AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777 #include #include -#include -#include -#include "list.h" #include #include +#include #include "server.h" +#include "list.h" #define CLIENT_FLAG_KEEPALIVE (1<<0) #define CLIENT_FLAG_HANDSHAKE (1<<1) - -struct client -{ - struct sockaddr_in address; - server_t server; - int fd; - - int next_id; /* server id generator (even, starts from 2) */ - int istream; /* input stream id */ - int ostream; /* output stream id */ - list_t streams; - SSL * ssl; - - time_t timestamp; - aisl_http_version_t protocol; - int flags; -}; - -typedef struct client * client_t; - -#define CLIENT(x) ((client_t)x) +#define CLIENT(x) ((aisl_client_t)x) /* constructor -------------------------------------------------------------- */ aisl_status_t -client_accept(client_t * self, server_t server); +aisl_client_accept(aisl_client_t * self, aisl_server_t server); /* destructor --------------------------------------------------------------- */ void -client_free(client_t self); +aisl_client_free(aisl_client_t self); /* all regular client routines. return true if something happened ----------- */ bool -client_touch(client_t self); +aisl_client_touch(aisl_client_t self); /* check if communication time with client is expired ----------------------- */ bool -client_is_timeout(client_t self); +aisl_client_is_timeout(aisl_client_t self); /* -------------------------------------------------------------------------- */ void -client_close(client_t self); +aisl_client_close(aisl_client_t self); /* -------------------------------------------------------------------------- */ -#endif + +#endif /* !AISL_CLIENT_H */ diff --git a/src/globals.h b/src/globals.h index f5abe2a..b3e39fc 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1,9 +1,7 @@ #ifndef _AISL_GLOBALS_H_ #define _AISL_GLOBALS_H_ -#pragma GCC diagnostic ignored "-Wuninitialized" - -#include +//#pragma GCC diagnostic ignored "-Wuninitialized" /* MACOS FIX AND OTHER OS */ #ifndef SOCK_NONBLOCK @@ -42,7 +40,4 @@ #define AISL_MAX_CLIENT_SILENCE 10 #endif - -extern aisl_handle_t gHandle; - #endif diff --git a/src/instance.c b/src/instance.c index 40928e9..dbba0b3 100644 --- a/src/instance.c +++ b/src/instance.c @@ -7,7 +7,579 @@ * */ +#include +#include +#include +#include +#include +#include +#include + +#include "list.h" +#include "str-utils.h" +#include "buffer.h" + +#include "client.h" +#include "server.h" +//#include "globals.h" +//#include "stream.h" #include "instance.h" +enum { + AISL_CYCLE_SERVER = 0 + , AISL_CYCLE_CLIENT = 1 +}; + + +struct aisl +{ + list_t servers; + list_t clients; + list_t callbacks; + #ifdef AISL_WITH_SSL + list_t ssl; + #endif + buffer_t buffer; + char * last_error; + int iterator; + int stage; + int flags; + uint32_t accept_limit; +}; + + +#ifdef AISL_WITH_SSL +static uint32_t m_instances = 0; +#endif + + +/* Initialization functions */ + +__attribute__ ((visibility ("default") )) +aisl_t +aisl_new( aisl_config_t config ) +{ + aisl_t instance; + + #ifdef AISL_WITH_SSL + if ((m_instances++) == 0) + { + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + } + #endif + + if ( !(instance = calloc(1, sizeof(struct aisl))) ) + goto finally; + + if ( !(instance->servers = list_new(config->servers_spool_size)) ) + goto release; + + if ( !(instance->clients = list_new(config->clients_spool_size)) ) + goto release; + + if ( !(instance->callbacks = list_new(config->callbacks_spool_size)) ) + goto release; + + if ( !(instance->buffer = buffer_new(config->initial_buffer_size)) ) + goto release; + + #ifdef AISL_WITH_SSL + if ( !(instance->ssl = list_new(config->ssl_spool_size)) ) + goto release; + #endif + + instance->accept_limit = config->clients_accept_limit; + + goto finally; + +release: + aisl_free(instance); + instance = NULL; + +finally: + return instance; +} + + +__attribute__ ((visibility ("default") )) +void +aisl_free( aisl_t instance ) +{ + if (instance->clients) + list_free(instance->clients, (list_destructor_t) aisl_client_free ); + + if (instance->servers) + list_free(instance->servers, (list_destructor_t) aisl_server_free ); + + if (instance->callbacks) + list_free(instance->callbacks, free); + + if (instance->buffer) + buffer_free(instance->buffer); + + if (instance->ssl) + list_free(instance->ssl, (list_destructor_t) ssl_free ); + + if (instance->last_error) + free(instance->last_error); + + free(instance); + + #ifdef AISL_WITH_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(address, port)) != NULL ) + { + result->instance = instance; + + if (list_append(instance->servers, result) == LIST_NAN) + { + aisl_server_free(result); + } + } + + return result; +} + + +#ifdef AISL_WITH_SSL + + +static int +get_ssl_context( SSL * ssl, int * ptr, void * handle ) +{ + const char * server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + + SSL_CTX * ctx = aisl_get_ssl_ctx( (aisl_t) handle, server_name ); + + if (ctx) + { + SSL_set_SSL_CTX(ssl, ctx); + } + + return SSL_TLSEXT_ERR_OK; +} + +/* -------------------------------------------------------------------------- */ + +static SSL_CTX * +create_ssl_context( aisl_t instance, + const char * key_file, + const char * crt_file ) +{ + const SSL_METHOD * method; + SSL_CTX * ctx; + + method = SSLv23_server_method(); + + if ( !(ctx = SSL_CTX_new(method)) ) + goto except; + + SSL_CTX_set_ecdh_auto(ctx, 1); + + SSL_CTX_set_tlsext_servername_callback( ctx, get_ssl_context ); + SSL_CTX_set_tlsext_servername_arg( ctx, (void *) instance ); + + if (!(SSL_CTX_use_certificate_file(ctx, crt_file, SSL_FILETYPE_PEM) > 0)) + goto release; + + if (!(SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) > 0)) + goto release; + + goto finally; + +release: + SSL_CTX_free(ctx); + ctx = NULL; + +except: + aisl_set_error( instance, ERR_error_string(ERR_get_error(),NULL) ); + +finally: + return ctx; +} + +__attribute__ ((visibility ("default") )) +aisl_status_t +aisl_set_ssl( aisl_t instance, const char * server_name, + const char * key_file, + const char * crt_file ) +{ + SSL_CTX * ssl_ctx = NULL; + int i; + crypter_t crypter; + + /* lookup for existing contexts */ + for (i=0; icrypters->count; i++) + { + crypter = list_index(instance->crypters, i); + if (crypter->keyFile && strcmp(crypter->keyFile, key_file)==0 && + crypter->crtFile && strcmp(crypter->crtFile, crt_file)==0 ) + { + ssl_ctx = crypter->sslCtx; + key_file = NULL; + crt_file = NULL; + break; + } + } + + if (! (crypter = crypter_new(server_name, key_file, crt_file)) ) + { + return AISL_MALLOC_ERROR; + } + + if (! ssl_ctx) + { + if (!(ssl_ctx = create_ssl_context(instance, key_file, crt_file))) + { + crypter_free(crypter); + return AISL_EXTCALL_ERROR; + } + } + + crypter->sslCtx = ssl_ctx; + + if (list_append(instance->crypters, crypter)==-1) + { + crypter_free(crypter); + return AISL_MALLOC_ERROR; + } + + return AISL_SUCCESS; +} + +SSL_CTX * +aisl_get_ssl_ctx( aisl_t instance, const char * server_name ) +{ + int i; + crypter_t crypter; + + for (i=0; icrypters->count; i++) + { + crypter = list_index(instance->crypters, i); + if (server_name) + { + if (strcmp(crypter->srvName, server_name)!=0) + continue; + } + + return crypter->sslCtx; + } + + return NULL; +} + + +#endif + +__attribute__ ((visibility ("default") )) +aisl_status_t +aisl_set_callback( aisl_t instance, + void * source, + aisl_event_t e_id, + aisl_callback_t cb ) +{ + listener_t listener; + + if (! (listener = listener_new(source, e_id, cb)) ) + return AISL_MALLOC_ERROR; + + if (list_append(instance->callbacks, listener) == -1) + { + free(listener); + return AISL_MALLOC_ERROR; + } + + if (e_id == AISL_STREAM_OUTPUT) /* subscribtion for chunked output */ + { + if (source) + { + ( (stream_t) source )->flags |= STREAM_FLAG_OUTPUT_CHUNKED; + } + } + else if (e_id == AISL_STREAM_OPEN) + { + instance->flags |= AISL_HANDLE_HAS_STREAM_LISTENERS; + } + + return AISL_SUCCESS; +} + + +__attribute__ ((visibility ("default") )) +void +aisl_unset_callback_for( aisl_t instance, void * source ) +{ + int i=instance->callbacks->count-1; + while ( !(i < 0) ) + { + listener_t listener = list_index(instance->callbacks, i); + if ( listener->source == source ) + { + free(listener); + list_remove_index(instance->callbacks, i); + } + + i--; + } +} + +__attribute__ ((visibility ("default") )) +bool +aisl_raise( aisl_t instance, + void * source, + aisl_event_t e_id, + ... ) +{ + va_list vl; + bool result; + + va_start(vl, e_id); + result = aisl_raise_vl(instance, source, e_id, vl); + va_end(vl); + + return result; +} + + +__attribute__ ((visibility ("default") )) +bool +aisl_raise_vl( aisl_t instance, + void * source, + aisl_event_t e_id, + va_list vl ) +{ + int i, + i_val; + listener_t lst; + bool res = false; + + char * c_ptr, + * c_ptr2; + + for(i=instance->callbacks->count-1; i>=0; i--) + { + lst = list_index(instance->callbacks, i); + + /*printf("AISL> raise %s:%s, %p:%p\n", _event_text(e_id), _event_text(lst->e_id), source, lst->source);*/ + if (lst->e_id == e_id && (source == lst->source || lst->source == NULL)) + { + /* + if (e_id == AISL_STREAM_HEADER) + fprintf(stderr,"FOUND HANDLER %d\n", i); + */ + + /*printf(" catch\n");*/ + switch(e_id) + { + /* server events */ + case AISL_EVENT_SERVER_OPEN: + i_val = va_arg(vl, aisl_status_t); + res = ((aisl_on_server_open_t) lst->cb)( source, i_val ); + break; + case AISL_EVENT_SERVER_ERROR: + i_val = va_arg(vl, aisl_status_t); + c_ptr = va_arg(vl, char *); + res = ((aisl_on_server_error_t) lst->cb)( source, i_val, c_ptr ); + break; + + /* client events */ + case AISL_EVENT_CLIENT_CONNECT: + res = ((aisl_on_client_connect_t) lst->cb)(source, va_arg(vl, void *)); + break; + case AISL_EVENT_CLIENT_DISCONNECT: + res = ((aisl_on_client_disconnect_t) lst->cb)(source, va_arg(vl, void*)); + aisl_unset_callback_for( instance, source ); + break; + case AISL_EVENT_CLIENT_TIMEOUT: + res = ((aisl_client_timeout_t) lst->cb)(source, va_arg(vl, void *)); + break; + + /* request events */ + case AISL_EVENT_STREAM_OPEN: + i_val = va_arg(vl, int); + c_ptr = va_arg(vl, char *); + c_ptr2 = va_arg(vl, char *); + res = ((aisl_on_stream_open_t) lst->cb)(source, i_val, c_ptr, c_ptr2); + break; + + case AISL_EVENT_STREAM_HEADER: + c_ptr = va_arg(vl, char *); + c_ptr2 = va_arg(vl, char *); + res = ((aisl_on_stream_header_t) lst->cb)(source, c_ptr, c_ptr2); + break; + + + case AISL_EVENT_STREAM_INPUT: + /*printf("AISL> raise AISL_STREAM_INPUT\n");*/ + c_ptr = va_arg(vl, char *); + i_val = va_arg(vl, int ); + res = ((aisl_on_stream_input_t) lst->cb)(source, c_ptr, i_val); + break; + case AISL_EVENT_STREAM_REQUEST: + /*printf("AISL> raise AISL_STREAM_REQUEST\n");*/ + buffer_clear( STREAM(source)->buffer, 0); + res = ((aisl_on_stream_request_t) lst->cb)(source); + break; + + + case AISL_EVENT_STREAM_ERROR: + res = ((aisl_on_stream_error_t) lst->cb)( source, va_arg(vl, char *)); + break; + + /* response events */ + case AISL_EVENT_STREAM_OUTPUT: + res = ((aisl_on_stream_output_t)lst->cb)( + source, + va_arg(vl, uint32_t) + ); + break; + case AISL_EVENT_STREAM_CLOSE: + res = ((aisl_on_stream_close_t)lst->cb)( source ); + aisl_unset_callback_for( instance, source ); + ((aisl_stream_t) source)->u_ptr=NULL; + break; + + default: + res = ((aisl_on_custom_event_t) lst->cb)(source, vl); + } + if (res) break; + } + } + + return res; +} + + + +__attribute__ ((visibility ("default") )) +aisl_status_t +aisl_run_cycle( aisl_t instance ) +{ + int max = instance->servers->count+instance->clients->count+instance->delays->count, + cnt = 0; + + + switch (instance->stage) + { + case STAGE_SERVER: + while (instance->iterator < instance->servers->count ) + { + aisl_server_t srv = (server_t)list_index(instance->servers, instance->iterator++); + if ( aisl_server_touch(srv) != AISL_IDLE ) + return AISL_SUCCESS; + + if ( ! (++cnt < max) ) return AISL_IDLE; + } + if ( ! (instance->flags & AISL_HANDLE_HAS_STREAM_LISTENERS) ) + return AISL_IDLE; + + instance->iterator = 0; + instance->stage++; + + + case STAGE_CLIENT: + while (instance->iterator < instance->clients->count ) + { + int i = instance->iterator++; + aisl_client_t cli = list_index(instance->clients, i); + bool r = aisl_client_touch( cli ); + + if (aisl_client_is_timeout( cli ) ) + aisl_raise( instance, cli->server, AISL_CLIENT_TIMEOUT, cli ); + + if ( cli->fd == -1 ) + { + aisl_client_free( cli ); + list_remove_index(instance->clients, i); + } + + if (r) return AISL_SUCCESS; + + if ( ! (++cnt < max) ) return AISL_IDLE; + } + instance->iterator = 0; + instance->stage = 0; + } + + return AISL_IDLE; +} + + +__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") )) +int +aisl_sleep( aisl_t instance, unsigned long usec ) +{ + int maxfd=0, + sd; + size_t i; + struct timeval timeout = {0,usec}; + + memset(&timeout, 0, sizeof(struct timeval)); + timeout.tv_usec = usec; + + fd_set fs; + FD_ZERO (&fs); + + for (i=0; iservers->count; i++) + { + aisl_server_t s = list_index(instance->servers, i); + + sd = aisl_server_get_socket(s); + + if (sd != -1) + { + FD_SET(sd, &fs); + if (sd > maxfd) maxfd = sd; + } + } + + + for (i=0; iclients->count; i++) + { + aisl_client_t c = list_index(instance->clients, i); + sd = aisl_client_get_socket(s); + if (sd != -1) + { + FD_SET(sd, &fs); + if (sd > maxfd) maxfd = sd; + } + } + + return select(maxfd+1, &fs, NULL, NULL, &timeout); + +} + diff --git a/src/instance.h b/src/instance.h index 129830a..a9fde93 100644 --- a/src/instance.h +++ b/src/instance.h @@ -10,7 +10,12 @@ #ifndef INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484 #define INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484 +#include #include +SSL_CTX * +aisl_get_ssl_ctx( aisl_t instance, const char * server_name ); +void +aisl_set_error( aisl_t instance, const char * err_msg ); #endif /* !INSTANCE_H */ diff --git a/src/server.c b/src/server.c index 20e67d4..4da25aa 100644 --- a/src/server.c +++ b/src/server.c @@ -8,11 +8,27 @@ #include "server.h" -#include "handle.h" +#include "instance.h" #include "client.h" #include "globals.h" #include "str-utils.h" +#ifdef __APPLE__ + +#include +#include + +#endif + +struct aisl_server +{ + struct sockaddr_in address; + aisl_t instance; + char * host; + int fd; + int port; + int flags; +}; /* -------------------------------------------------------------------------- */ static bool diff --git a/src/server.h b/src/server.h index 4c48575..74d5c5b 100644 --- a/src/server.h +++ b/src/server.h @@ -1,47 +1,25 @@ -#ifndef _AISL_SERVER_H_ -#define _AISL_SERVER_H_ +#ifndef AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2 +#define AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2 -#include -#include #include +#include +#include +#include -#ifdef __APPLE__ -#include -#include +#define SERVER(x) ((aisl_server_t) x) -#endif -/* types -------------------------------------------------------------------- */ -struct server -{ - struct sockaddr_in address; - aisl_handle_t owner; - char * host; - int fd; - int port; - int flags; -}; +aisl_server_t +aisl_server_new(const char * address, int port); -typedef struct server * server_t; - -#define SERVER(x) ((server_t) x) - -/* -------------------------------------------------------------------------- */ - -server_t -server_new(const char * address, int port); - -/* -------------------------------------------------------------------------- */ void -server_free(server_t self); +aisl_server_free(aisl_server_t self); -/* -------------------------------------------------------------------------- */ bool -server_touch(server_t self); +aisl_server_touch(aisl_server_t self); -/* -------------------------------------------------------------------------- */ -#endif +#endif /* !AISL_SERVER_H */ diff --git a/src/stream.c b/src/stream.c index 9414f5a..d18e09c 100644 --- a/src/stream.c +++ b/src/stream.c @@ -1,13 +1,31 @@ #include #include #include -#include #include "stream.h" #include "globals.h" #include "client.h" #include "handle.h" +struct stream +{ + struct aisl_stream _public; + /* private data */ + list_t headers; /* request headers */ + buffer_t buffer; + + const char *c_type; + + aisl_http_response_t response; + stream_state_t state; + uint32_t c_length; + uint32_t c_offset; + int id; + int flags; + + bool c_length_unknown; + +}; static void pair_free( pair_t self ) { @@ -194,3 +212,235 @@ aisl_reject(aisl_stream_t s) } /* -------------------------------------------------------------------------- */ + + + +static char * +get_response_begin(stream_t stream) +{ + char * r; + client_t cli = CLIENT(ASTREAM(stream)->client); + + r = str_printf( + "%s %d %s\r\n" + "Server: AISL\r\n" + "Connection: %s\r\n\r\n", + aisl_http_version_to_string(cli->protocol), + stream->response, + aisl_http_response_to_string(stream->response), + ((cli->flags & CLIENT_FLAG_KEEPALIVE) ? "keep-alive" : "close") + ); + + return r; +} + +__attribute__ ((visibility ("default") )) +aisl_status_t +aisl_response(aisl_stream_t stream, aisl_http_response_t status_code, + const char *content_type, + uint32_t content_length) +{ + char * pch; + int l; + + + /* check if those headers were already sent */ + if (STREAM(stream)->state > STREAM_REQUEST_READY) return AISL_IDLE; + + STREAM(stream)->response = status_code; + STREAM(stream)->c_type = content_type; + STREAM(stream)->c_length = content_length; + + if ( !(pch = get_response_begin(STREAM(stream))) ) + return AISL_MALLOC_ERROR; + + l = strlen(pch); + STREAM(stream)->c_offset = l-2; + + buffer_clear(STREAM(stream)->buffer, content_length); + + l = buffer_add( STREAM(stream)->buffer, pch, l ); + free(pch); + + if (l == BUFFER_EOB) return AISL_MALLOC_ERROR; + + if (content_length) + { + if (!aisl_header_printf( stream, "Content-Length", "%u", content_length )) + return AISL_MALLOC_ERROR; + } + + if (content_type) + { + if (!aisl_header( stream, "Content-Type", content_type )) + return AISL_MALLOC_ERROR; + } + + STREAM(stream)->state = STREAM_RESPONSE_HEADER; + + return AISL_SUCCESS; +} + + +__attribute__ ((visibility ("default") )) +aisl_status_t +aisl_flush(aisl_stream_t stream) +{ + stream_t s = STREAM(stream); + if ( ! s->c_length ) + { + s->c_length = s->buffer->size - s->c_offset - 2; + if (!aisl_header_printf(stream, "Content-Length", "%u", s->c_length)) + return AISL_MALLOC_ERROR; + } + + /* + fprintf(stdout, "(%lu bytes)------->\n", STREAM(stream)->buffer->size); + fwrite(STREAM(stream)->buffer->data, 1, STREAM(stream)->buffer->size, stdout); + fprintf(stdout, "<------\n"); + */ + s->state = STREAM_RESPONSE_READY; + + s->flags |= STREAM_FLAG_OUTPUT_READY; + + return AISL_SUCCESS; +} + + +__attribute__ ((visibility ("default") )) +int +aisl_header(aisl_stream_t stream, const char *key, const char *value) +{ + int ret; + char * pch; + + if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL ) + { + ret = strlen(pch); + if ( buffer_insert( + STREAM(stream)->buffer, + STREAM(stream)->c_offset, + pch, + ret + ) == BUFFER_EOB ) + { + ret = -1; + } + else + STREAM(stream)->c_offset += ret; + + free(pch); + } + else + ret = -1; + + return ret; +} + + +__attribute__ ((visibility ("default") )) +int +aisl_header_printf(aisl_stream_t stream, const char *key, + const char *f_value, ...) +{ + int ret; + + va_list arg; + va_start(arg, f_value); + + ret = aisl_header_vprintf(stream, key, f_value, arg); + + va_end(arg); + + return ret; +} + + +__attribute__ ((visibility ("default") )) +int +aisl_header_vprintf(aisl_stream_t stream, const char *key, + const char *format, + va_list args) +{ + int ret; + char * value; + + if ( (value = str_vprintf(format, args)) != NULL ) + { + ret = aisl_header( stream, key, value ); + free(value); + } + else + ret = -1; + + return ret; +} + + +__attribute__ ((visibility ("default") )) +int +aisl_printf(aisl_stream_t stream, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + + int result = aisl_vprintf(stream, format, arg); + + va_end(arg); + + /* No need to update length there, because vprintf do that + * + * if (STREAM(stream)->c_length_unknown) + STREAM(stream)->c_length += result; + */ + + + return result; + +} + + +__attribute__ ((visibility ("default") )) +int +aisl_vprintf(aisl_stream_t stream, const char *format, va_list args) +{ + int result; + char * r; + + if ( (r = str_vprintf(format, args)) != NULL) + { + result = strlen(r); + if (buffer_add(STREAM(stream)->buffer, r, result) == BUFFER_EOB) + result = -1; + + free(r); + } + else + result = -1; + + return result; +} + + +__attribute__ ((visibility ("default") )) +int +aisl_write(aisl_stream_t stream, const char *data, int d_len) +{ + if (d_len < 0) + d_len = strlen(data); + + if (buffer_add(STREAM(stream)->buffer, data, d_len) == BUFFER_EOB) + d_len = -1; + + return d_len; +} + + +__attribute__ ((visibility ("default") )) +int +aisl_puts(const char *str, aisl_stream_t stream) +{ + return aisl_write( stream, str, strlen(str)); +} + + diff --git a/src/stream.h b/src/stream.h index ef59fa2..112a6a3 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,5 +1,5 @@ -#ifndef _AISL_STREAM_H__ -#define _AISL_STREAM_H__ +#ifndef AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3 +#define AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3 #include #include @@ -43,51 +43,32 @@ typedef enum { STREAM_RESPONSE_CONTENT, STREAM_RESPONSE_READY -} stream_state_t; +} aisl_stream_state_t; /* real wrapper for aisl_stream_t */ -struct stream -{ - struct aisl_stream _public; - /* private data */ - list_t headers; /* request headers */ - buffer_t buffer; - const char *c_type; - - aisl_http_response_t response; - stream_state_t state; - uint32_t c_length; - uint32_t c_offset; - int id; - int flags; - - bool c_length_unknown; - -}; - -typedef struct stream * stream_t; +typedef struct aisl_stream * aisl_stream_t; #define STREAM(x) ((stream_t) x) #define ASTREAM(x) ((aisl_stream_t) x) /* -------------------------------------------------------------------------- */ -stream_t -stream_new(struct sockaddr_in *client, int id, stream_state_t state); +aisl_stream_t +aisl_stream_new(struct sockaddr_in *client, int id, stream_state_t state); /* -------------------------------------------------------------------------- */ void -stream_free(stream_t self); +aisl_stream_free(aisl_stream_t self); /* -------------------------------------------------------------------------- */ -stream_t -stream_reset(stream_t self); +aisl_stream_t +aisl_stream_reset(aisl_stream_t self); /* -------------------------------------------------------------------------- */ -#endif +#endif /* !AISL_STREAM_H */