From 8847f92528a296c638470a19bea2eb62f60cfb12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilja=20Karta=C5=A1ov?= Date: Mon, 18 Mar 2019 09:13:02 +0100 Subject: [PATCH] Implemented all except parser --- config.mk | 26 -- examples.mk | 31 ++ examples/hello-world.c | 115 ++++++++ include/aisl/stream.h | 3 +- include/aisl/types.h | 6 +- project.mk | 56 ++++ src/buffer.c | 209 ++++++++----- src/buffer.h | 39 ++- src/client.c | 30 +- src/client.h | 11 +- src/instance.c | 96 +++--- src/list.c | 204 ++++--------- src/list.h | 57 ++-- src/server.c | 8 + src/str-utils.c | 646 +++-------------------------------------- src/str-utils.h | 110 +------ src/stream.c | 416 +++++++++++++++++++------- src/stream.h | 6 +- 18 files changed, 903 insertions(+), 1166 deletions(-) delete mode 100644 config.mk create mode 100644 examples.mk create mode 100644 examples/hello-world.c create mode 100644 project.mk diff --git a/config.mk b/config.mk deleted file mode 100644 index c765c6d..0000000 --- a/config.mk +++ /dev/null @@ -1,26 +0,0 @@ -# -# config.mk -# Löwenware Makefile Config, 2019-03-02 17:35 -# - -PREFIX = /usr/ - -PKG_CONFIG = pkg-config - -# includes and libs -# INCS = -I$(X11INC) \ -# `$(PKG_CONFIG) --cflags fontconfig` \ -# `$(PKG_CONFIG) --cflags freetype2` - -# LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ -# `$(PKG_CONFIG) --libs fontconfig` \ -# `$(PKG_CONFIG) --libs freetype2` - -# flags -# STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -# STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) -# STLDFLAGS = $(LIBS) $(LDFLAGS) - - -# vim:ft=make -# diff --git a/examples.mk b/examples.mk new file mode 100644 index 0000000..dec700e --- /dev/null +++ b/examples.mk @@ -0,0 +1,31 @@ +# +# examples.mk +# Ilja Kartašov, 2019-03-17 17:40 +# + +EXAMPLES_DIR ?= examples + +EXAMPLES_CFLAGS := \ + $(PROJECT_INCLUDES) \ + -std=c99 \ + -pedantic \ + -Wall \ + -Wmissing-prototypes \ + -Wstrict-prototypes \ + -Wold-style-definition \ + -O2 \ + -s \ + $(CFLAGS) \ + + +EXAMPLES_LDFLAGS = -L./ -L./build -laisl -Wl,-rpath=./build + +examples: library hello_world + +hello_world: + $(info compiling: hello world) + $(CC) $(EXAMPLES_CFLAGS) \ + -o $(OUT_DIR)/hello-world $(EXAMPLES_DIR)/hello-world.c $(EXAMPLES_LDFLAGS) + +# vim:ft=make +# diff --git a/examples/hello-world.c b/examples/hello-world.c new file mode 100644 index 0000000..0b3a002 --- /dev/null +++ b/examples/hello-world.c @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file hello-world.c + * @author Ilja Kartašov + * @brief AISL usage example: Hello World + * + * @see https://lowenware.com/aisl/ + */ + +#include +#include + +/* Include library meta header */ +#include + + +#define DEFAULT_HTTP_PORT 8080 /**< Default HTTP server port */ + + +static bool +hello_world(aisl_stream_t s) +{ + aisl_status_t status; + + const char html[] = + "" + "" + "Hello World" + "" + "" + "

Hello World

" + "

Powered by AISL

" + "" + ""; + + status = aisl_response(s, AISL_HTTP_OK, sizeof(html)-1); + + if (status == AISL_SUCCESS) + { + if (aisl_write(s, html, sizeof(html)-1) != -1) + { + aisl_flush(s); + } + else + aisl_reject(s); + } + + return true; /**< do not propagate event anymore */ +} + + +int +main(int argc, char ** argv) +{ + aisl_t aisl; /**< AISL instance pointer */ + aisl_status_t status; /**< AISL status code */ + uint16_t port = 0; + + /* 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; + + /* Initialize instance */ + if ( (aisl = aisl_new(NULL)) != NULL ) + { + if (aisl_listen( aisl, "0.0.0.0", port ) != NULL) + { + aisl_callback_t callback = AISL_CALLBACK(hello_world); + + /* Set up request callback */ + status = aisl_set_callback( aisl + , NULL + , AISL_EVENT_STREAM_REQUEST + , callback ); + + /* if callback was set, launch application loop */ + if ( status == AISL_SUCCESS ) + { + fprintf(stdout, "Entering main loop" ); + for(;;) + { + status = aisl_run_cycle(aisl); + + if ( status != AISL_SUCCESS ) + aisl_sleep(aisl, 500); + } + } + else + fprintf(stderr, "Failed to register callback" ); + + aisl_free(aisl); + } + else + fprintf(stderr, "Failed to initialize HTTP server" ); + } + else + fprintf(stderr, "Failed to initialize AISL"); + + + (void)argc; + (void)argv; + + return 0; +} + diff --git a/include/aisl/stream.h b/include/aisl/stream.h index 172c695..a7c768b 100644 --- a/include/aisl/stream.h +++ b/include/aisl/stream.h @@ -63,8 +63,7 @@ aisl_reject( aisl_stream_t stream ); aisl_status_t aisl_response( aisl_stream_t stream, aisl_http_response_t status_code, - const char * content_type, - uint32_t content_length); + uint64_t content_length ); int diff --git a/include/aisl/types.h b/include/aisl/types.h index 50b5370..7c35a4e 100644 --- a/include/aisl/types.h +++ b/include/aisl/types.h @@ -18,6 +18,8 @@ #include #endif +#define AISL_AUTO_LENGTH (~0) + /* type casts */ #define AISL_CALLBACK(x) ((aisl_callback_t) x) @@ -229,13 +231,13 @@ typedef bool const char * val ); typedef bool -(*aisl_on_stream_input_t)( aisl_stream_t stream, char * data, size_t len ); +(*aisl_on_stream_input_t)( aisl_stream_t stream, 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, size_t buffer_space ); +(*aisl_on_stream_output_t)( aisl_stream_t stream ); typedef bool (*aisl_on_stream_close_t)( aisl_stream_t stream ); diff --git a/project.mk b/project.mk new file mode 100644 index 0000000..8327ffd --- /dev/null +++ b/project.mk @@ -0,0 +1,56 @@ +# +# config.mk +# Löwenware Makefile Config, 2019-03-02 17:35 +# + +PREFIX = /usr/ +PKG_CONFIG = pkg-config + +PROJECT_NAME = aisl + +# Version + +PROJECT_VERSION_MAJOR = 1 +PROJECT_VERSION_MINOR = 0 +PROJECT_VERSION_TWEAK = 0 +PROJECT_VERSION_LABEL = 0 + +#SRC_DIR = src +#SDK_DIR = sdk +#OUT_DIR = ./build + + +# Source files + +PROJECT_SOURCES := \ + $(SRC_DIR)/instance.c \ + $(SRC_DIR)/server.c \ + $(SRC_DIR)/client.c \ + $(SRC_DIR)/stream.c \ + $(SRC_DIR)/http.c \ + $(SRC_DIR)/ssl.c \ + $(SRC_DIR)/list.c \ + $(SRC_DIR)/str-utils.c \ + $(SRC_DIR)/buffer.c \ + $(SRC_DIR)/types.c \ + + +# includes +PROJECT_INCLUDES = -I./ \ + -I./include \ + `$(PKG_CONFIG) --cflags openssl` \ + +# libraries +PROJECT_LIBRARIES = \ + `$(PKG_CONFIG) --libs openssl` \ + + +# flags +PROJECT_CFLAGS = -D_POSIX_C_SOURCE=200809L \ + + +# PROJECT_LDFLAGS = -L + + +# vim:ft=make +# diff --git a/src/buffer.c b/src/buffer.c index 31aca61..735aa09 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,21 +1,62 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file buffer.c + * @author Ilja Kartašov + * @brief Buffer module source file + * + * @see https://lowenware.com/ + */ #include #include -#include #include #include "buffer.h" +static int32_t +buffer_set_size(buffer_t buffer, int32_t new_size) +{ + if ( new_size < buffer->size ) + { + if (new_size) + { + int32_t s = new_size / 1024; + + if ( new_size % 1024 ) + { + new_size = (s+1) * 1024; + } + } + else + new_size = 4096; + + char * data = realloc(buffer->data, new_size); + + if (data) + { + buffer->data = data; + buffer->size = new_size; + } + else + new_size = -1; + } + + return new_size; +} + + int32_t buffer_init( buffer_t buffer, int32_t size ) { - if ((buffer->data = malloc(size)) != NULL) - { - buffer->size = size; - buffer->length = 0; - return size; - } + if ( (size = buffer_set_size(buffer, size)) != -1) + buffer->used = 0; - return -1; + return size; } @@ -25,90 +66,120 @@ buffer_release( buffer_t buffer ) if (buffer->data) free(buffer->data); - buffer->length = 0; + buffer->used = 0; buffer->size = 0; } -int32_t -buffer_add( buffer_t self, const char * data, int32_t size ) +static int32_t +buffer_move_offset( buffer_t buffer, int32_t offset, int32_t size ) { - int32_t result = size+self->size; + int32_t to_move = buffer->used - offset; - char * ptr; + if (to_move < 0) + return -1; + else if (to_move) + memmove(&buffer->data[offset+size], &buffer->data[offset], to_move); - if ( (ptr = realloc(self->data, result+1)) != NULL ) - { - memcpy( &ptr[self->size], data, size ); - ptr[ result ] = 0; - self->data = ptr; - self->size = result; - } - else - result = -1; - - return result; + return size; } - int32_t -buffer_clear( buffer_t self, int32_t to_alloc ) -{ - self->length = 0; - - if (to_alloc > 0) - { - if ( (self->data = realloc(self->data, to_alloc)) != NULL ) - { - self->size = to_alloc; - return to_alloc; - } - else - to_alloc = -1; - } - - free(self->data); - self->data = NULL; - - return to_alloc; -} - - -int32_t -buffer_shift( buffer_t self, int32_t size ) +buffer_insert( buffer_t buffer + , int32_t offset + , const char * data + , int32_t size ) { int32_t result; - if (size && !(size > self->size)) + if ( (result = buffer_set_size(buffer, size)) != -1) { - result = self->size - size; - memmove(self->data, &self->data[size], result); - self->size = result; + if ((result = buffer_move_offset(buffer, offset, size)) != -1) + { + memcpy(&buffer->data[offset], data, size); + buffer->used += result; + } } - else - result = -1; return result; } int32_t -buffer_insert( buffer_t self, int32_t offset, const char * data, int32_t size ) +buffer_append_printf( buffer_t buffer, const char * format, ... ) { - int32_t result = size + self->size; + int32_t result; + va_list args; - char * ptr; - - if ( (ptr = realloc(self->data, result+1)) != NULL ) - { - memmove( &ptr[offset+size], &ptr[offset], self->size - offset ); - memcpy( &ptr[offset], data, size ); - ptr[ result ] = 0; - self->data = ptr; - self->size = result; - } - else - result = -1; + va_start(args, format); + result = buffer_append_vprintf( buffer, format, args); + va_end(args); return result; } + +int32_t +buffer_append_vprintf( buffer_t buffer, const char * format, va_list args ) +{ + int32_t space = buffer->size - buffer->used, + result; + + va_list cp_args; + va_copy(args, cp_args); + + result = vsnprintf( &buffer->data[buffer->used], space, format, args ); + + if ( result < space ) /* enough space */ + { + buffer->used += result; + } + else + { + if ((result = buffer_set_size(buffer, buffer->size + result - space)) != -1) + result = buffer_append_vprintf(buffer, format, cp_args); + } + va_end(cp_args); + + return result; +} + + +int32_t +buffer_append( buffer_t buffer, const char * data, int32_t size ) +{ + int32_t used = buffer->used, + space = buffer->size - used; + + if ( size > space ) /* enough space */ + { + if ( buffer_set_size(buffer, buffer->size + size - space) == -1) + return -1; + } + + memcpy(&buffer->data[used], data, size); + buffer->used += size; + + return size; +} + + +int32_t +buffer_shift( buffer_t buffer, int32_t offset ) +{ + int32_t used = buffer->used - offset; + + if (offset > 0) + { + if (offset < used) + { + memmove(buffer->data, &buffer->data[offset], used); + } + else + used = 0; + + buffer->used = used; + } + + return used; +} + diff --git a/src/buffer.h b/src/buffer.h index 3d3fd28..81854f5 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -1,14 +1,30 @@ -#ifndef _AISL_BUFFER_H_ -#define _AISL_BUFFER_H_ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ -#include +/** + * @file buffer.h + * @author Ilja Kartašov + * @brief Buffer module header file + * + * @see https://lowenware.com/aisl/ + */ + +#ifndef AISL_BUFFER_H_D60EB5DF_B70B_4D8F_AA63_7FDB569D67E9 +#define AISL_BUFFER_H_D60EB5DF_B70B_4D8F_AA63_7FDB569D67E9 + +#include +#include struct buffer { char * data; int32_t size; - int32_t length; + int32_t used; }; typedef struct buffer * buffer_t; @@ -23,19 +39,24 @@ buffer_release( buffer_t buffer ); int32_t -buffer_clear( buffer_t self, int32_t to_alloc ); +buffer_insert(buffer_t buffer, int32_t offset, const char * data, int32_t size); int32_t -buffer_insert( buffer_t self, int32_t offset, const char * data, int32_t size ); +buffer_append_printf( buffer_t buffer, const char * format, ... ); int32_t -buffer_add( buffer_t self, const char * data, int32_t size ); +buffer_append_vprintf( buffer_t buffer, const char * format, va_list args ); int32_t -buffer_shift( buffer_t self, int32_t size ); +buffer_append( buffer_t buffer, const char * data, int32_t size ); -#endif +int32_t +buffer_shift( buffer_t buffer, int32_t size ); + + + +#endif /* !AISL_BUFFER_H */ diff --git a/src/client.c b/src/client.c index 060ed28..52fbb8f 100644 --- a/src/client.c +++ b/src/client.c @@ -124,7 +124,7 @@ aisl_client_parse(aisl_client_t client, char * data, int32_t size) if (size) - buffer_shift(&client->in, client->in.length - size); /* reset buffer */ + buffer_shift(&client->in, client->in.used - size); /* reset buffer */ return AISL_SUCCESS; } @@ -139,8 +139,8 @@ aisl_client_input(aisl_client_t client) { int l; - char * data = &client->in.data[ client->in.length ]; - int32_t size = client->in.size - client->in.length; + char * data = &client->in.data[ client->in.used ]; + int32_t size = client->in.size - client->in.used; #ifndef AISL_WITHOUT_SSL if (client->ssl) @@ -174,9 +174,9 @@ aisl_client_input(aisl_client_t client) if (l > 0) { data = client->in.data; - size = client->in.length + l; + size = client->in.used + l; - client->in.length = size; + client->in.used = size; return aisl_client_parse(client, data, size); } @@ -239,7 +239,7 @@ aisl_client_output(aisl_client_t client) ); } - aisl_stream_get_buffer(s, &data, &l); + data = aisl_stream_get_data(s, &l); if ( !l ) return AISL_IDLE; @@ -256,7 +256,7 @@ aisl_client_output(aisl_client_t client) if (s->state == STREAM_RESPONSE_READY && / * flushed * / s->buffer->size == 0) / * all sent * / */ - if ( ! aisl_stream_has_data(s) ) + if ( aisl_stream_is_done(s) ) { /* buffer_clear(s->buffer, 0); */ @@ -452,6 +452,22 @@ aisl_client_get_socket(aisl_client_t client) } +bool +aisl_client_get_keepalive(aisl_client_t client) +{ + return (client->flags & FLAG_KEEPALIVE); +} + + +void +aisl_client_set_keepalive(aisl_client_t client, bool value) +{ + if (value) + client->flags |= FLAG_KEEPALIVE; + else + client->flags &= ~FLAG_KEEPALIVE; +} + /* API Level ---------------------------------------------------------------- */ aisl_server_t diff --git a/src/client.h b/src/client.h index d2c27a6..abcbe16 100644 --- a/src/client.h +++ b/src/client.h @@ -70,7 +70,16 @@ aisl_client_is_timed_out(aisl_client_t client, uint32_t timeout); * @return true if keepalive mode is on, otherwise false. */ bool -aisl_client_is_keepalive(aisl_client_t client); +aisl_client_get_keepalive(aisl_client_t client); + + +/** + * @Brief Sets if connection with client must be kept alive. + * @param client an #aisl_client_t instance pointer. + * @param value a true to enable keepalive mode, false to disable. + */ +void +aisl_client_set_keepalive(aisl_client_t client, bool value); /** diff --git a/src/instance.c b/src/instance.c index d96a386..6c983cc 100644 --- a/src/instance.c +++ b/src/instance.c @@ -43,11 +43,11 @@ typedef struct callback * callback_t; struct aisl { - list_t server_spool; - list_t client_spool; - list_t callback_spool; + struct list server_spool; + struct list client_spool; + struct list callback_spool; #ifndef AISL_WITHOUT_SSL - list_t ssl_spool; + struct list ssl_spool; #endif char * last_error; @@ -83,17 +83,17 @@ aisl_new( aisl_config_t config ) if ( !(instance = calloc(1, sizeof(struct aisl))) ) goto finally; - if ( !(instance->server_spool = list_new(config->server_spool_size)) ) + if ( list_init(&instance->server_spool, config->server_spool_size) == -1 ) goto release; - if ( !(instance->client_spool = list_new(config->client_spool_size)) ) + if ( list_init(&instance->client_spool, config->client_spool_size) == -1 ) goto release; - if ( !(instance->callback_spool = list_new(config->callback_spool_size)) ) + if ( list_init(&instance->callback_spool, config->callback_spool_size) == -1 ) goto release; #ifndef AISL_WITHOUT_SSL - if ( !(instance->ssl_spool = list_new(config->ssl_spool_size)) ) + if ( list_init(&instance->ssl_spool, config->ssl_spool_size) == -1 ) goto release; #endif @@ -115,18 +115,14 @@ __attribute__ ((visibility ("default") )) void aisl_free( aisl_t instance ) { - if (instance->client_spool) - list_free(instance->client_spool, (list_destructor_t) aisl_client_free ); + list_release(&instance->client_spool, (list_destructor_t) aisl_client_free ); - if (instance->server_spool) - list_free(instance->server_spool, (list_destructor_t) aisl_server_free ); + list_release(&instance->server_spool, (list_destructor_t) aisl_server_free ); - if (instance->callback_spool) - list_free(instance->callback_spool, (list_destructor_t) free); + list_release(&instance->callback_spool, (list_destructor_t) free); #ifndef AISL_WITHOUT_SSL - if (instance->ssl_spool) - list_free(instance->ssl_spool, (list_destructor_t) aisl_ssl_free ); + list_release(&instance->ssl_spool, (list_destructor_t) aisl_ssl_free ); #endif if (instance->last_error) @@ -151,7 +147,7 @@ aisl_listen( aisl_t instance, const char * address, uint16_t port ) if ( (result = aisl_server_new(instance, address, port)) != NULL ) { - if (list_append(instance->server_spool, result) == LIST_NAN) + if (list_append(&instance->server_spool, result) == -1) { aisl_server_free(result); } @@ -226,9 +222,9 @@ aisl_set_ssl( aisl_t instance, const char * host, size_t i; /* lookup for existing contexts */ - for (i=0; issl_spool->count; i++) + for (i=0; issl_spool.count; i++) { - ssl = list_index(instance->ssl_spool, 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 ) { @@ -241,7 +237,7 @@ aisl_set_ssl( aisl_t instance, const char * host, { if (!ssl_ctx || (aisl_set_ssl_ctx(instance, ssl) == AISL_SUCCESS)) { - if (list_append(instance->ssl_spool, ssl) != LIST_NAN) + if (list_append(&instance->ssl_spool, ssl) != -1) return AISL_SUCCESS; } @@ -260,9 +256,9 @@ aisl_get_ssl_ctx( aisl_t instance, const char * host ) if (host) { - for (i=0; issl_spool->count; i++) + for (i=0; issl_spool.count; i++) { - ssl = list_index(instance->ssl_spool, i); + ssl = LIST_INDEX(instance->ssl_spool, i); if (strcmp(ssl->host, host) != 0) continue; @@ -291,7 +287,7 @@ aisl_set_callback( aisl_t instance, cb->event = event; cb->f_ptr = callback; - if ( list_append(instance->callback_spool, cb) != LIST_NAN ) + if ( list_append(&instance->callback_spool, cb) != -1 ) { switch(event) { @@ -321,17 +317,17 @@ __attribute__ ((visibility ("default") )) void aisl_unset_callbacks_for( aisl_t instance, void * source ) { - size_t i = instance->callback_spool->count; + size_t i = instance->callback_spool.count; if (i) { for(i=i-1; i <= 0; i-- ) { - callback_t callback = list_index(instance->callback_spool, i); + callback_t callback = LIST_INDEX(instance->callback_spool, i); if ( callback->source == source ) { free(callback); - list_remove_index(instance->callback_spool, i); + list_remove_index(&instance->callback_spool, i); } } } @@ -401,17 +397,6 @@ aisl_on_stream_input( void * source, aisl_callback_t cb, va_list vl_args ) } -static bool -aisl_on_stream_output( void * source, aisl_callback_t cb, va_list vl_args ) -{ - aisl_on_stream_output_t callback = (aisl_on_stream_output_t) cb; - - size_t buffer_size = va_arg(vl_args, size_t); - - return callback( (aisl_stream_t) source, buffer_size ); -} - - __attribute__ ((visibility ("default") )) bool aisl_raise_vl( aisl_t instance, @@ -426,11 +411,11 @@ aisl_raise_vl( aisl_t instance, bool result = false, stop_propg = false; - i = instance->callback_spool->count; + i = instance->callback_spool.count; while(i--) { - cb = list_index(instance->callback_spool, i); + cb = LIST_INDEX(instance->callback_spool, i); if (cb->event == event && (source == cb->source || cb->source == NULL)) { @@ -446,6 +431,7 @@ aisl_raise_vl( aisl_t instance, case AISL_EVENT_STREAM_REQUEST: case AISL_EVENT_STREAM_CLOSE: case AISL_EVENT_STREAM_ERROR: + case AISL_EVENT_STREAM_OUTPUT: stop_propg = aisl_on_source_event(source, cb->f_ptr, vl_copy); break; @@ -461,10 +447,6 @@ aisl_raise_vl( aisl_t instance, stop_propg = aisl_on_stream_input(source, cb->f_ptr, vl_copy); break; - case AISL_EVENT_STREAM_OUTPUT: - stop_propg = aisl_on_stream_output(source, cb->f_ptr, vl_copy); - break; - default: stop_propg = ((aisl_on_custom_event_t) cb->f_ptr)(source, vl_copy); } @@ -489,20 +471,20 @@ aisl_run_cycle( aisl_t instance ) aisl_status_t result = AISL_IDLE; size_t i = instance->iterator, - max = instance->server_spool->count + instance->client_spool->count; + max = instance->server_spool.count + instance->client_spool.count; while ( result == AISL_IDLE && max != 0) { aisl_client_t cli; - if (i < instance->server_spool->count) + if (i < instance->server_spool.count) { - if (instance->client_spool->count < instance->accept_limit) + 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); + srv = (aisl_server_t) LIST_INDEX(instance->server_spool, i); ssl_ctx = (aisl_server_get_ssl(srv)) ? aisl_get_ssl_ctx(instance, NULL) : @@ -512,7 +494,7 @@ aisl_run_cycle( aisl_t instance ) if (result == AISL_SUCCESS) { - if ( list_append(instance->client_spool, cli) != LIST_NAN ) + if ( list_append(&instance->client_spool, cli) != -1 ) { aisl_raise(instance, cli, AISL_EVENT_CLIENT_CONNECT); } @@ -525,17 +507,17 @@ aisl_run_cycle( aisl_t instance ) } else { - i = instance->server_spool->count; + i = instance->server_spool.count; continue; } } else { - size_t j = i - instance->server_spool->count; + size_t j = i - instance->server_spool.count; - if (j < instance->client_spool->count) + if (j < instance->client_spool.count) { - aisl_client_t c = list_index(instance->client_spool, j); + aisl_client_t c = LIST_INDEX(instance->client_spool, j); result = aisl_client_touch(c); @@ -545,7 +527,7 @@ aisl_run_cycle( aisl_t instance ) if ( !aisl_client_is_online(c) ) { aisl_client_free( c ); - list_remove_index(instance->client_spool, j); + list_remove_index(&instance->client_spool, j); } } else @@ -598,9 +580,9 @@ aisl_sleep( aisl_t instance, uint32_t usec ) fd_set fs; FD_ZERO (&fs); - for (i=0; iserver_spool->count; i++) + for (i=0; iserver_spool.count; i++) { - aisl_server_t s = list_index(instance->server_spool, i); + aisl_server_t s = LIST_INDEX(instance->server_spool, i); sd = aisl_server_get_socket(s); @@ -612,9 +594,9 @@ aisl_sleep( aisl_t instance, uint32_t usec ) } - for (i=0; iclient_spool->count; i++) + for (i=0; iclient_spool.count; i++) { - aisl_client_t c = list_index(instance->client_spool, i); + aisl_client_t c = LIST_INDEX(instance->client_spool, i); sd = aisl_client_get_socket(c); if (sd != -1) { diff --git a/src/list.c b/src/list.c index 10b15e7..59fa517 100644 --- a/src/list.c +++ b/src/list.c @@ -1,173 +1,94 @@ -/* list.c - code file of the List module - * Copyright (c) 2017 Löwenware Ltd (https://lowenware.com) +/****************************************************************************** * - * REPOSITORY: - * git://lowenware.com:standard.git - * MAINTAINER: - * Ilja Kartaschoff + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information * - * LICENSE and DISCLAIMER: - * All code stored in standard.git repository is designed to solve - * very common and widely meet development tasks. We are not about to patent - * wheels here, so all code you can find in this repository is FREE: - * you can use, redistribute and/or modify it without any limits or - * restrictions. - * - * All code described above is distributed in hope to be useful for somebody - * else WITHOUT ANY WARRANTY, without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * In case of questions or suggestions, feel free to contact maintainer. - * - * */ + ******************************************************************************/ + +/** + * @file list.c + * @author Ilja Kartašov + * @brief List module source file + * + * @see https://lowenware.com/aisl/ + */ -#include #include -#include #include "list.h" -/* -------------------------------------------------------------------------- */ - -list_t -list_new(int size) +int32_t +list_init(list_t list, int32_t size) { - list_t self = calloc(1, sizeof(struct list)); - if (self) + if ((list->data = calloc(size, sizeof(void*))) != NULL) { - if (size) - { - self->size = size; - - if ( (self->list = calloc(size, sizeof(void *))) == NULL ) - { - free(self); - self = NULL; - } - } + list->size = size; + list->count = 0; + return 0; } - return self; + + return -1; } -/* -------------------------------------------------------------------------- */ void -list_free(list_t self, list_destructor_t destructor) +list_release(list_t list, list_destructor_t destructor) { - int i; - if (self) + if (list->data) { - if (self->list) + if (destructor) { - if (destructor) + int32_t i; + for (i=0; icount; i++) { - for(i=0; icount; i++) - { - if (self->list[i]) - destructor(self->list[i]); - } + void * ptr; + + if ( (ptr = list->data[i]) != NULL) + destructor( list->data[i] ); } - free(self->list); } - free(self); + free(list->data); } } -/* -------------------------------------------------------------------------- */ -#ifdef CSTUFF_LIST_WITH_INSERT - -int -list_insert( list_t self, void * item, int position ) +int32_t +list_append(list_t list, void * entry) { - int r; + int32_t pos = list->count; - if ( (r = list_append(self, item)) == -1) - return -1; - - if (position >= r || position < 0) - return r; - - memmove( - &self->list[position+1], - &self->list[position], - (self->count-position-1)*sizeof(void*) - ); - - self->list[position] = item; - - return position; -} - - -#endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_LIST_WITH_APPEND - -int -list_append(list_t self, void * item) -{ - void ** new_list; - int new_size = self->count+1; - - - if (new_size > self->size) + if ( !(pos < list->size) ) { - if ( (new_list = realloc( self->list, new_size*sizeof(void*) )) == NULL ) + void ** new_list; + int32_t new_size = pos + 1; + + if ( (new_list = realloc( list->data, new_size*sizeof(void*) )) == NULL ) return -1; - - self->list = new_list; - self->size = new_size; + list->data = new_list; + list->size = new_size; } - self->list[self->count]=item; + list->data[pos]=entry; + list->count++; - return self->count++; + return pos; } -#endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_LIST_WITH_REMOVE - -void -list_remove( list_t self, void * item ) -{ - int i; - - for (i=0; icount; i++) - { - if (self->list[i]==item) - { - list_remove_index(self, i); - break; - } - } -} - - -#endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_LIST_WITH_REMOVE_INDEX void * -list_remove_index( list_t self, int index ) +list_remove_index(list_t list, int32_t index) { void * result; - int i; - if (index < self->count) + if (index < list->count) { - result = self->list[index]; - self->count--; - for (i=index; icount; i++) + int32_t i, c = --list->count; + + result = list->data[index]; + + for (i=index; ilist[i]=self->list[i+1]; + list->data[i]=list->data[i+1]; } } else @@ -176,26 +97,3 @@ list_remove_index( list_t self, int index ) return result; } - - -#endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_LIST_WITH_SET_ITEM - -void -list_set_item(list_t self, int index, void * value) -{ - if (self->size > index) - { - self->list[index] = value; - if (index >= self->count) - self->count = index+1; - - } -} - -#endif - -/* -------------------------------------------------------------------------- */ diff --git a/src/list.h b/src/list.h index b66a391..b571d03 100644 --- a/src/list.h +++ b/src/list.h @@ -1,47 +1,54 @@ -#ifndef AISL_LIST_H_3223EF5C_CCF2_4D7C_8A3B_8BAF122E473F -#define AISL_LIST_H_3223EF5C_CCF2_4D7C_8A3B_8BAF122E473F +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file list.h + * @author Ilja Kartašov + * @brief List module header file + * + * @see https://lowenware.com/ + */ + +#ifndef AISL_LIST_H_21495B65_111D_40F7_840F_CC50D9D324A1 +#define AISL_LIST_H_21495B65_111D_40F7_840F_CC50D9D324A1 #include -#define LIST_NAN (~0) +#define LIST_INDEX(L, I) ( L.data[ I ] ) + struct list { - void ** list; - size_t size; - size_t count; + void ** data; + int32_t size; + int32_t count; }; typedef struct list * list_t; -typedef void (* list_destructor_t)(void * list_item); +typedef void +(* list_destructor_t)(void * list_item); -#define list_index(self, index) (self->list[index]) -list_t -list_new(int size); - -void -list_free(list_t self, list_destructor_t destructor); - -int -list_insert( list_t self, void * item, int position ); - -int -list_append(list_t self, void * item); +int32_t +list_init(list_t list, int32_t size); void -list_remove( list_t self, void * item ); +list_release(list_t list, list_destructor_t destructor); + + +int32_t +list_append(list_t list, void * entry); void * -list_remove_index( list_t self, int index ); - - -void -list_set_item(list_t self, int index, void * value); +list_remove_index(list_t list, int32_t index); #endif /* !AISL_LIST_H */ diff --git a/src/server.c b/src/server.c index 414d2e4..b7e9375 100644 --- a/src/server.c +++ b/src/server.c @@ -140,6 +140,14 @@ aisl_server_touch( aisl_server_t server, return result; } + +int +aisl_server_get_socket( aisl_server_t server ) +{ + return server->fd; +} + + /* API Level ---------------------------------------------------------------- */ aisl_server_t diff --git a/src/str-utils.c b/src/str-utils.c index 900b598..c9dc6bd 100644 --- a/src/str-utils.c +++ b/src/str-utils.c @@ -1,627 +1,53 @@ -/* str_utils.c - code file of the C string module - * Copyright (c) 2017 Löwenware Ltd (https://lowenware.com) +/****************************************************************************** * - * REPOSITORY: - * git://lowenware.com:standard.git - * MAINTAINER: - * Ilja Kartaschoff + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information * - * LICENSE and DISCLAIMER: - * All code stored in standard.git repository is designed to solve - * very common and widely meet development tasks. We are not about to patent - * wheels here, so all code you can find in this repository is FREE: - * you can use, redistribute and/or modify it without any limits or - * restrictions. + ******************************************************************************/ + +/** + * @file str-utils.c + * @author Ilja Kartašov + * @brief String utilities source file * - * All code described above is distributed in hope to be useful for somebody - * else WITHOUT ANY WARRANTY, without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * In case of questions or suggestions, feel free to contact maintainer. - * - * */ -#include -#include -#include - -#include "str-utils.h" - -#ifndef CSTUFF_TIMESTAMP_FORMAT -#define CSTUFF_TIMESTAMP_FORMAT "%Y-%m-%d %H:%M:%S" -#endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_SET - -char * -str_set(char * dst, const char * src) -{ - int len = (src) ? strlen(src) : 0; - - if (!dst || len > strlen(dst)) - { - char * r; - - if ( (r = realloc( dst, len + 1 )) != NULL ) - { - dst = r; - } - else - return r; - } - - if (len) - strncpy(dst, src, len); - - dst[len]=0; - - return dst; -} - -# endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_COPY - -char * -str_copy(const char * src) -{ - if (!src) return NULL; - - uint32_t s = strlen(src); - char * result = malloc((s+1)*sizeof(char)); - - strcpy(result, src); - - return result; -} - -# endif - - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_NCOPY - -char * -str_ncopy(const char * src, uint32_t s) -{ - if (!src) return NULL; - - char * result = malloc((s+1)*sizeof(char)); - - if (s) - strncpy(result, src, s); - - result[s]=0; - - return result; -} - -# endif -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_PRINTF - -#ifndef CSTUFF_STR_UTILS_WITH_VPRINTF -#define CSTUFF_STR_UTILS_WITH_VPRINTF -#endif - -char * -str_printf(const char * format, ...) -{ - va_list vl; - va_start (vl, format); - char * result = str_vprintf(format, vl); - va_end(vl); - - return result; -} - -# endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_VPRINTF - -char * -str_vprintf(const char * format, va_list vl) -{ - if (!format) return NULL; - - va_list _vl; - va_copy(_vl, vl); - - uint32_t total = 0, - fmt_len = 0; - - char tmp_buffer[64], - tmp_format[64], - * chr_arg; - const char * pch = format; - - - - enum { - wsFormatSearch, - wsFormatFlags, - wsFormatWidth, - wsFormatPrecisionDot, - wsFormatPrecision, - wsFormatLength, - wsFormatSpecifier - }; - - uint32_t stage = wsFormatSearch; - - while(*pch) - { - switch (stage) - { - case wsFormatSearch: - if (*pch=='%') - { - stage = wsFormatFlags; - strcpy(tmp_format, "%"); - fmt_len=1; - } - else - { - total++; - } - pch++; - break; - case wsFormatFlags: - switch (*pch) - { - case '-': - case '+': - case ' ': - case '#': - case '0': - tmp_format[fmt_len]=*pch; - fmt_len++; - pch++; - default: - stage=wsFormatWidth; - } - break; - case wsFormatWidth: - switch (*pch) - { - case '*': - stage=wsFormatPrecisionDot; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - tmp_format[fmt_len]=*pch; - fmt_len++; - pch++; - break; - default: - stage=wsFormatPrecisionDot; - } - break; - case wsFormatPrecisionDot: - if (*pch=='.') - { - tmp_format[fmt_len]=*pch; - fmt_len++; - pch++; - stage=wsFormatPrecision; - } - else - stage=wsFormatLength; - break; - case wsFormatPrecision: - switch(*pch) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - tmp_format[fmt_len]=*pch; - fmt_len++; - pch++; - break; - default: - stage=wsFormatLength; - } - break; - case wsFormatLength: - switch(*pch) - { - case 'h': - case 'l': - case 'j': - case 'z': - case 't': - case 'L': - tmp_format[fmt_len]=*pch; - fmt_len++; - pch++; - break; - default: - stage=wsFormatSpecifier; - - } - break; - case wsFormatSpecifier: - tmp_format[fmt_len]=*pch; - fmt_len++; - tmp_format[fmt_len]=0; - stage = wsFormatSearch; - - switch (*pch) - { - case '%': - total+=1; - break; - case 'd': - case 'i': - case 'u': - case 'o': - case 'x': - case 'X': - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - case 'a': - case 'A': - case 'c': - case 'p': - case 'n': - vsprintf(tmp_buffer, tmp_format, vl); - total+=strlen(tmp_buffer); - break; - case 's': - chr_arg = va_arg(vl, char*); - total+=chr_arg ? strlen( chr_arg ) : 6; /* (null) */ - break; - default: - fprintf( - stderr, "Warning: " - "bad format specifier (%s)\n", tmp_format - ); - return NULL; - } - pch++; - - break; - } - - } - - char * result = malloc(total+1); - - vsprintf(result, format, _vl); - - va_end(_vl); - - return result; -} - -# endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_CAT - -#ifndef CSTUFF_STR_UTILS_WITH_NCAT -#define CSTUFF_STR_UTILS_WITH_NCAT -#endif - -char * -str_cat(char * source, const char * target) -{ - return str_ncat(source, target, strlen(target)); -} - -# endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_NCAT - -char * -str_ncat(char * source, const char * target, uint32_t length) -{ - char * result = realloc( source, - length + ((source) ? strlen(source) : 0) + 1 - ); - if (result) - { - if (!source) - result[0]=0; - - if (target && length) - strncat(result, target, length); - - } - - return result; -} - -# endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_CMPI + * @see https://lowenware.com/aisl/ + */ #include +#include +#include +#include "str-utils.h" -int -str_cmpi(const char * source, const char * target) + +char * +str_copy(const char * source) { - char r; - while ( *source != 0 && *target != 0 ) - { - r = tolower(*source) - tolower(*target); - if ( r != 0 ) return r; - source++; - target++; - } + int l = strlen(source); - return ( *source == 0 && *target == 0 ) ? 0: -1; -} + char * result = malloc(l+1); -# endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_TO_INT - -int -str_to_int(const char * ptr, int l, int32_t * result) -{ - int64_t b; - int rc = str_to_int64(ptr, l, &b); - - *result = b & 0xFFFFFFFF; - - return rc; -} - -/* -------------------------------------------------------------------------- */ - -int -str_to_int64(const char * ptr, int l, int64_t * result) -{ - int rc; - char * src; - int dest; - - if ( (src = str_ncopy(ptr, l)) != NULL ) - { - char * p; - dest = strtoll(src, &p, 10); - - rc = (p && *p == 0) ? CSTUFF_SUCCESS : CSTUFF_PARSE_ERROR; - - free(src); - } - else - { - dest = 0; - rc = CSTUFF_MALLOC_ERROR; - } - - *result = dest; - - return rc; -} - -#endif - - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_TO_TIMESTAMP - -#include - -int -str_to_timestamp(const char * source, size_t l, time_t * p_ts, const char * tz) -{ - int result; - - if (!tz) - tz = "UTC"; - - if ( ! (l < 19) ) - { - struct tm * tms = calloc(1, sizeof(struct tm)); - if (tms) - { - char * curtz; - - tms->tm_year = strtol(source, NULL, 10) - 1900; - tms->tm_mon = strtol(&source[5], NULL, 10) - 1; - tms->tm_mday = strtol(&source[8], NULL, 10); - tms->tm_hour = strtol(&source[11], NULL, 10); - tms->tm_min = strtol(&source[14], NULL, 10); - tms->tm_sec = strtol(&source[17], NULL, 10); - tms->tm_isdst = -1; - - curtz = getenv("TZ"); - setenv("TZ", tz, 1); - - *p_ts = mktime(tms); - - if (curtz) - setenv("TZ", curtz, 1); - else - putenv("TZ"); - - free(tms); - - result = 0; - } - else - result = -1; - } - else - result = 1; + if (result) + strcpy(result, source); return result; } -#endif -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_FROM_TIMESTAMP - -char * -str_from_timestamp_iso_utc(time_t ts) +int +str_cmpi(const char * s1, const char * s2) { - return str_from_timestamp(ts, CSTUFF_TIMESTAMP_FORMAT, "UTC"); + char c1, c2, r = 0; + + do + { + c1 = tolower(*(s1++)); + c2 = tolower(*(s2++)); + + if ((r = c1-c2) != 0) + break; + + } while (c1 != 0); + + return r; } -#endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_FROM_TIMESTAMP_FORMAT - -char * -str_from_timestamp(time_t ts, const char * format, const char * timezone) -{ - char * result; - char * cur_tz; - - if (!format) - format = "%c"; - - if (!timezone) - timezone = "UTC"; - - cur_tz = getenv("TZ"); - setenv("TZ", timezone, 1); - - struct tm * p_tm = localtime(&ts); - - if (cur_tz) - setenv("TZ", cur_tz, 1); - else - putenv("TZ"); - - if ((result = calloc(64, sizeof(char))) != NULL) - { - strftime(result, 64, format, p_tm); - } - - return result; -} - -#endif - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_CHOP - -/* chop spaces from string, return number of prepending spaces */ -uint32_t -str_chop(char * source) -{ - char * p = source; - uint32_t s = 0; - - /* remove ending spaces */ - s = strlen(source); - while (--s) - { - if (source[s] != ' ') break; - source[s] = 0; - } - - s=0; - /* remove prepending spaces */ - while (*p == ' ') s++; - if (s) - strcpy(source, &source[s]); - - return s; - -} - -# endif - -/* -------------------------------------------------------------------------- */ - -#ifdef CSTUFF_STR_UTILS_WITH_REPLACE - -char * -str_replace(const char * haystack, const char * needle, const char * value) -{ - size_t h_len, - n_len = strlen(needle), - v_len, - match = 0; - - char * cur = (char *) haystack, - * ptr, - * result, - * out; - - while ( (ptr = strstr(cur, needle)) != NULL ) - { - cur = (char *)(ptr + n_len); - match++; - } - - if (!match) - return (char*) haystack; - - v_len = strlen(value); - h_len = strlen(haystack) - match * n_len + match * v_len + 1; - - if ((result = calloc(h_len, sizeof(char))) != NULL) - { - cur = (char *) haystack; - out = result; - - while ( (ptr = strstr(cur, needle)) != NULL ) - { - if (cur == haystack && ptr != haystack) - { - strncpy(result, haystack, (int)(ptr-haystack)); - out += (int)(ptr-haystack); - } - - strncpy(out, value, v_len); - - out += v_len; - - cur = (char *)(ptr + n_len); - } - - if (*cur) - strcpy(out, cur); - } - - return result; -} - -# endif - -/* -------------------------------------------------------------------------- */ diff --git a/src/str-utils.h b/src/str-utils.h index 37a1791..24fcbeb 100644 --- a/src/str-utils.h +++ b/src/str-utils.h @@ -1,104 +1,26 @@ -/* str_utils.h - header file of the C string module - * Copyright (c) 2017 Löwenware Ltd (https://lowenware.com) +/****************************************************************************** * - * REPOSITORY: - * git://lowenware.com:standard.git - * MAINTAINER: - * Ilja Kartaschoff + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information * - * LICENSE and DISCLAIMER: - * All code stored in standard.git repository is designed to solve - * very common and widely meet development tasks. We are not about to patent - * wheels here, so all code you can find in this repository is FREE: - * you can use, redistribute and/or modify it without any limits or - * restrictions. + ******************************************************************************/ + +/** + * @file str-utils.h + * @author Ilja Kartašov + * @brief String utilities header file * - * All code described above is distributed in hope to be useful for somebody - * else WITHOUT ANY WARRANTY, without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * In case of questions or suggestions, feel free to contact maintainer. - * - * */ + * @see https://lowenware.com/aisl/ + */ -#ifndef _CSTUFF_STR_UTILS_H_ -#define _CSTUFF_STR_UTILS_H_ - -#include -#include -#include - - -/* if init is not set or smaller than src, it will be reallocated - * */ -char * -str_set(char * init, const char * src); - - -/* copy src string to newly allocated one - * */ -char * -str_copy(const char * src); - - -/* copy num bytes from src string to newly allocated one - * */ -char * -str_ncopy(const char * src, uint32_t num); +#ifndef STR_UTILS_H_799148B5_F829_437C_8B96_55876A37C38E +#define STR_UTILS_H_799148B5_F829_437C_8B96_55876A37C38E char * -str_printf(const char * format, ...); - -char * -str_vprintf(const char * format, va_list vl); - - -/* for source will be called u_free automatically */ -char * -str_cat(char * source, const char * target); - - -/* for source will be called u_free automatically */ -char * -str_ncat(char * source, const char * target, uint32_t length); - - -/* compare strings ignoring case */ -int -str_cmpi(const char * source, const char * target); - +str_copy(const char * source); int -str_to_int(const char * ptr, int l, int32_t * result); +str_cmpi(const char * anycase, const char * lowcase); - -/* -------------------------------------------------------------------------- */ - -int -str_to_int64(const char * ptr, int l, int64_t * result); - - - -int -str_to_timestamp(const char * source, size_t l, time_t * p_ts, const char * tz); - - -char * -str_from_timestamp_iso_utc(time_t ts); - - -char * -str_from_timestamp(time_t ts, const char * format, const char * timezone); - - -/* chop spaces from string, return number of prepending spaces */ -uint32_t -str_chop(char * source); - - -char * -str_replace(const char * haystack, const char * needle, const char * value); - - -#endif +#endif /* !STR_UTILS_H */ diff --git a/src/stream.c b/src/stream.c index 0d3c2b4..25b1cdd 100644 --- a/src/stream.c +++ b/src/stream.c @@ -9,10 +9,13 @@ #include "str-utils.h" #include "stream.h" -#define FLAG_OUTPUT_READY (1<<0) -#define FLAG_OUTPUT_CHUNKED (1<<1) +#define FLAG_FLUSHED (1<<0) +#define FLAG_OUTPUT_CHUNKED (1<<1) +#define FLAG_SERVER_HEADER_SENT (1<<2) +#define FLAG_CONTENT_TYPE_HEADER_SENT (1<<3) +#define FLAG_CONTENT_LENGTH_HEADER_SENT (1<<4) +#define FLAG_CONNECTION_HEADER_SENT (1<<5) -#define SIZE_NAN (~0) struct aisl_stream { @@ -20,10 +23,10 @@ struct aisl_stream aisl_client_t client; void * u_ptr; - const char * content_type; - size_t content_length; - int32_t content_offset; + uint64_t content_length; + int32_t head_offset; + int32_t body_offset; int id; int flags; @@ -32,6 +35,8 @@ struct aisl_stream }; +/* Library level */ + static void aisl_stream_reset(aisl_stream_t stream, bool initial) { @@ -48,9 +53,8 @@ aisl_stream_reset(aisl_stream_t stream, bool initial) buffer_release(&stream->buffer); stream->u_ptr = NULL; - stream->content_type = NULL; - stream->content_length = SIZE_NAN; - stream->content_offset = 0; /* headers length */ + stream->content_length = AISL_AUTO_LENGTH; + stream->head_offset = 0; stream->flags = 0; stream->state = AISL_STREAM_STATE_IDLE; stream->response = AISL_HTTP_OK; @@ -81,6 +85,68 @@ aisl_stream_free(aisl_stream_t stream) } +void +aisl_stream_set_chunked_output(aisl_stream_t stream, bool value) +{ + if (value) + stream->flags |= FLAG_OUTPUT_CHUNKED; + else if (stream->flags & FLAG_OUTPUT_CHUNKED) + stream->flags &= ~FLAG_OUTPUT_CHUNKED; +} + + +bool +aisl_stream_get_chunked_output(aisl_stream_t stream) +{ + return (stream->flags & FLAG_OUTPUT_CHUNKED); +} + + +int32_t +aisl_stream_get_buffer_space(aisl_stream_t stream) +{ + return stream->buffer.size - stream->buffer.used; +} + + +int32_t +aisl_stream_get_buffer_size(aisl_stream_t stream) +{ + return stream->buffer.size; +} + + +char * +aisl_stream_get_data(aisl_stream_t stream, int32_t * p_length) +{ + *p_length = stream->buffer.used; + + return stream->buffer.data; +} + + +void +aisl_stream_shift(aisl_stream_t stream, int32_t offset) +{ + buffer_shift(&stream->buffer, offset); +} + + +bool +aisl_stream_is_done(aisl_stream_t stream) +{ + return (!stream->buffer.used && stream->state == AISL_STREAM_STATE_DONE); +} + + +aisl_stream_state_t +aisl_stream_get_state(aisl_stream_t stream) +{ + return stream->state; +} + +/* API Level */ + /* Why it was here? static int aisl_stream_write(aisl_stream_t stream, const char * data, uint32_t d_len) @@ -97,7 +163,6 @@ aisl_cancel(aisl_stream_t stream) } */ - __attribute__ ((visibility ("default") )) void * aisl_get_context(aisl_stream_t s) @@ -146,66 +211,107 @@ aisl_reject(aisl_stream_t s) } -static char * -aisl_stream_get_response_begin(aisl_stream_t stream) +static aisl_status_t +aisl_start_response(aisl_stream_t stream) { - char * r; + return aisl_response( stream + , AISL_HTTP_OK + , AISL_AUTO_LENGTH ); +} - r = str_printf( - "%s %d %s\r\n" - "Server: AISL\r\n" - "Connection: %s\r\n\r\n", - aisl_get_http_version(stream), - stream->response, - aisl_http_response_to_string(stream->response), - aisl_client_is_keepalive(stream->client) ? "keep-alive" : "close" - ); - return r; +static aisl_status_t +aisl_stream_close_headers(aisl_stream_t stream) +{ + int32_t l; + + if (aisl_start_response(stream) == AISL_MALLOC_ERROR) + return AISL_MALLOC_ERROR; + + if (!(stream->flags & FLAG_SERVER_HEADER_SENT)) + { + l = buffer_append( &stream->buffer, "Server: AISL\r\n", 14); + if (l == -1) + return AISL_MALLOC_ERROR; + + stream->flags |= FLAG_SERVER_HEADER_SENT; + } + + if (!(stream->flags & FLAG_CONTENT_TYPE_HEADER_SENT)) + { + l = buffer_append( &stream->buffer + , "Content-type: text/html; encoding=utf-8\r\n" + , 41); + if (l == -1) + return AISL_MALLOC_ERROR; + + stream->flags |= FLAG_CONTENT_TYPE_HEADER_SENT; + } + + if (!(stream->flags & FLAG_CONTENT_LENGTH_HEADER_SENT)) + { + if (stream->content_length == AISL_AUTO_LENGTH) + { + l = buffer_append_printf( &stream->buffer + , "Content-length: %"PRIu64"\r\n" + , stream->content_length ); + if (l == -1) + return AISL_MALLOC_ERROR; + + stream->flags |= FLAG_CONTENT_LENGTH_HEADER_SENT; + } + } + + if (!(stream->flags & FLAG_CONNECTION_HEADER_SENT)) + { + l = buffer_append_printf( &stream->buffer + , "Connection: %s\r\n" + , (aisl_client_get_keepalive(stream->client) ? + "keepalive" : "close")); + if (l == -1) + return AISL_MALLOC_ERROR; + + stream->flags |= FLAG_CONNECTION_HEADER_SENT; + } + + if (buffer_append( &stream->buffer, "\r\n", 2 ) == -1) + return AISL_MALLOC_ERROR; + + stream->body_offset = stream->buffer.used; + + stream->state = AISL_STREAM_STATE_SEND_BODY; + + return AISL_SUCCESS; } __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) +aisl_response( aisl_stream_t stream + , aisl_http_response_t status_code + , uint64_t content_length ) { - char * pch; - int l; - + int32_t l; /* check if those headers were already sent */ if (stream->state > AISL_STREAM_STATE_READY) return AISL_IDLE; stream->response = status_code; - stream->content_type = content_type; stream->content_length = content_length; - if ( !(pch = aisl_stream_get_response_begin(stream)) ) + buffer_init( &stream->buffer + , (content_length != AISL_AUTO_LENGTH) ? content_length : 0); + + l = buffer_append_printf( &stream->buffer + , "%s %d %s\r\n" + , aisl_get_http_version(stream) + , status_code + , aisl_http_response_to_string(status_code) ); + + if ( l == -1 ) return AISL_MALLOC_ERROR; - l = strlen(pch); - stream->content_offset = l-2; - - buffer_clear(&stream->buffer, content_length); - - l = buffer_add( &stream->buffer, pch, l ); - free(pch); - - if (l == -1) 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->head_offset = l; stream->state = AISL_STREAM_STATE_SEND_HEADER; @@ -217,39 +323,114 @@ __attribute__ ((visibility ("default") )) aisl_status_t aisl_flush(aisl_stream_t s) { - if ( ! s->content_length ) + if (!(s->flags & FLAG_CONTENT_LENGTH_HEADER_SENT)) { - s->content_length = s->buffer.size - s->content_offset - 2; - if (!aisl_header_printf(s, "Content-Length", "%u", s->content_length)) + char hdr[ 40 ]; + + uint64_t c_len = s->buffer.used - s->body_offset; + int32_t l; + + l = snprintf(hdr, sizeof(hdr), "Content-length: %"PRIu64"\r\n", c_len); + + l = buffer_insert( &s->buffer + , s->body_offset - 2 + , hdr + , l ); + + if (l == -1) return AISL_MALLOC_ERROR; + + s->flags |= FLAG_CONTENT_LENGTH_HEADER_SENT; } - /* - fprintf(stdout, "(%lu bytes)------->\n", stream->buffer->size); - fwrite(stream->buffer->data, 1, stream->buffer->size, stdout); - fprintf(stdout, "<------\n"); - */ - s->state = AISL_STREAM_STATE_READY; - - s->flags |= FLAG_OUTPUT_READY; + s->state = AISL_STREAM_STATE_DONE; + s->flags |= FLAG_FLUSHED; return AISL_SUCCESS; } +static int32_t +aisl_stream_verify_header( aisl_stream_t stream, + const char * key, + const char * value ) +{ + if (stream->state < AISL_STREAM_STATE_SEND_HEADER) + { + if (aisl_start_response(stream) != AISL_SUCCESS) + return -1; + } + else if (stream->state > AISL_STREAM_STATE_SEND_HEADER) + return 0; + + if (!(stream->flags & FLAG_CONNECTION_HEADER_SENT)) + { + if (str_cmpi(key, "connection")==0) + { + stream->flags |= FLAG_CONNECTION_HEADER_SENT; + if (value) + { + aisl_client_set_keepalive( stream->client + , (str_cmpi(value, "keepalive")==0) ); + } + return 1; + } + } + + if (!(stream->flags & FLAG_CONTENT_TYPE_HEADER_SENT)) + { + if (str_cmpi(key, "content-type")==0) + { + stream->flags |= FLAG_CONTENT_TYPE_HEADER_SENT; + return 1; + } + } + + if (!(stream->flags & FLAG_CONTENT_LENGTH_HEADER_SENT)) + { + if (str_cmpi(key, "content-length")==0) + { + stream->flags |= FLAG_CONTENT_LENGTH_HEADER_SENT; + return 1; + } + } + + if (!(stream->flags & FLAG_CONTENT_LENGTH_HEADER_SENT)) + { + if (str_cmpi(key, "content-length")==0) + { + stream->flags |= FLAG_CONTENT_LENGTH_HEADER_SENT; + return 1; + } + } + + return 1; +} + __attribute__ ((visibility ("default") )) -int +int32_t aisl_header(aisl_stream_t stream, const char *key, const char *value) { - int ret; - char * pch; + int32_t result; + if ( (result = aisl_stream_verify_header( stream, key, value )) != 1) + return result; + + result = buffer_append_printf( &stream->buffer + , "%s: %s\r\n" + , key + , value ); + + + return result; + + /* For debug purposes if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL ) { ret = strlen(pch); if ( buffer_insert( &stream->buffer, - stream->content_offset, + stream->end_of_headers, pch, ret ) == -1 ) @@ -257,7 +438,7 @@ aisl_header(aisl_stream_t stream, const char *key, const char *value) ret = -1; } else - stream->content_offset += ret; + stream->end_of_headers += ret; free(pch); } @@ -265,45 +446,60 @@ aisl_header(aisl_stream_t stream, const char *key, const char *value) ret = -1; return ret; + */ } __attribute__ ((visibility ("default") )) -int +int32_t aisl_header_printf(aisl_stream_t stream, const char *key, - const char *f_value, ...) + const char *format, ...) { - int ret; + int32_t result; - va_list arg; - va_start(arg, f_value); + va_list args; + va_start(args, format); - ret = aisl_header_vprintf(stream, key, f_value, arg); + result = aisl_header_vprintf( stream, key, format, args ); - va_end(arg); + va_end(args); - return ret; + return result; } __attribute__ ((visibility ("default") )) -int +int32_t aisl_header_vprintf(aisl_stream_t stream, const char *key, const char *format, va_list args) { - int ret; - char * value; + int32_t result, + l; - if ( (value = str_vprintf(format, args)) != NULL ) + if ( (result = aisl_stream_verify_header( stream, key, NULL )) != 1) + return result; + + result = buffer_append_printf( &stream->buffer, "%s: ", key ); + + if (result != -1) { - ret = aisl_header( stream, key, value ); - free(value); - } - else - ret = -1; + l = buffer_append_vprintf( &stream->buffer, format, args ); - return ret; + if (l != -1) + { + result += l; + if ((l = buffer_append(&stream->buffer, "\r\n", 2)) != -1) + { + result += l; + + return result; + } + } + } + + + return -1; } @@ -331,38 +527,31 @@ aisl_printf(aisl_stream_t stream, const char *format, ...) __attribute__ ((visibility ("default") )) -int +int32_t aisl_vprintf(aisl_stream_t stream, const char *format, va_list args) { - int result; - char * r; - - if ( (r = str_vprintf(format, args)) != NULL) + if (stream->state < AISL_STREAM_STATE_SEND_BODY) { - result = strlen(r); - if (buffer_add(&stream->buffer, r, result) == -1) - result = -1; - - free(r); + if (aisl_stream_close_headers(stream) != AISL_SUCCESS) + return -1; } - else - result = -1; - - return result; + return buffer_append_vprintf(&stream->buffer, format, args); } __attribute__ ((visibility ("default") )) -int -aisl_write(aisl_stream_t stream, const char *data, int d_len) +int32_t +aisl_write(aisl_stream_t stream, const char *data, int32_t d_len) { - if (d_len < 0) + if (stream->state < AISL_STREAM_STATE_SEND_BODY) + { + if (aisl_stream_close_headers(stream) != AISL_SUCCESS) + return -1; + } + if (d_len == -1) d_len = strlen(data); - if (buffer_add(&stream->buffer, data, d_len) == -1) - d_len = -1; - - return d_len; + return buffer_append(&stream->buffer, data, d_len); } @@ -370,7 +559,18 @@ __attribute__ ((visibility ("default") )) int aisl_puts(const char *str, aisl_stream_t stream) { - return aisl_write( stream, str, strlen(str)); + if (stream->state < AISL_STREAM_STATE_SEND_BODY) + { + if (aisl_stream_close_headers(stream) != AISL_SUCCESS) + return -1; + } + return aisl_write( stream, str, -1); } +__attribute__ ((visibility ("default") )) +aisl_t +aisl_stream_get_instance(aisl_stream_t stream) +{ + return aisl_server_get_instance(aisl_client_get_server(stream->client)); +} diff --git a/src/stream.h b/src/stream.h index 01209d0..1fb3e9e 100644 --- a/src/stream.h +++ b/src/stream.h @@ -47,8 +47,8 @@ int32_t aisl_stream_get_buffer_size(aisl_stream_t stream); -void -aisl_stream_get_buffer(aisl_stream_t stream, char ** data, int32_t * size); +char * +aisl_stream_get_data(aisl_stream_t stream, int32_t * p_length); void @@ -56,7 +56,7 @@ aisl_stream_shift(aisl_stream_t stream, int32_t offset); bool -aisl_stream_has_data(aisl_stream_t stream); +aisl_stream_is_done(aisl_stream_t stream); aisl_stream_state_t