Implemented all except parser

This commit is contained in:
Ilja Kartašov 2019-03-18 09:13:02 +01:00
parent fc33a0e49e
commit 8847f92528
18 changed files with 903 additions and 1166 deletions

View File

@ -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
#

31
examples.mk Normal file
View File

@ -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
#

115
examples/hello-world.c Normal file
View File

@ -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 <ik@lowenware.com>
* @brief AISL usage example: Hello World
*
* @see https://lowenware.com/aisl/
*/
#include <stdio.h>
#include <stdlib.h>
/* Include library meta header */
#include <aisl/aisl.h>
#define DEFAULT_HTTP_PORT 8080 /**< Default HTTP server port */
static bool
hello_world(aisl_stream_t s)
{
aisl_status_t status;
const char html[] =
"<html>"
"<head>"
"<title>Hello World</title>"
"</head>"
"<body>"
"<h1>Hello World</h1>"
"<p>Powered by AISL</p>"
"</body>"
"</html>";
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;
}

View File

@ -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

View File

@ -18,6 +18,8 @@
#include <openssl/ssl.h>
#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 );

56
project.mk Normal file
View File

@ -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
#

View File

@ -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 <ik@lowenware.com>
* @brief Buffer module source file
*
* @see https://lowenware.com/
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#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;
}

View File

@ -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 <sys/types.h>
/**
* @file buffer.h
* @author Ilja Kartašov <ik@lowenware.com>
* @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 <stdint.h>
#include <stdarg.h>
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 */

View File

@ -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

View File

@ -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);
/**

View File

@ -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; i<instance->ssl_spool->count; i++)
for (i=0; i<instance->ssl_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; i<instance->ssl_spool->count; i++)
for (i=0; i<instance->ssl_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; i<instance->server_spool->count; i++)
for (i=0; i<instance->server_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; i<instance->client_spool->count; i++)
for (i=0; i<instance->client_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)
{

View File

@ -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 <ik@lowenware.com>
* 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 <ik@lowenware.com>
* @brief List module source file
*
* @see https://lowenware.com/aisl/
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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; i<list->count; i++)
{
for(i=0; i<self->count; 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; i<self->count; 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; i<self->count; i++)
int32_t i, c = --list->count;
result = list->data[index];
for (i=index; i<c; i++)
{
self->list[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
/* -------------------------------------------------------------------------- */

View File

@ -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 <ik@lowenware.com>
* @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 <stdint.h>
#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 */

View File

@ -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

View File

@ -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 <ik@lowenware.com>
* 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 <ik@lowenware.com>
* @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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <ctype.h>
#include <stdlib.h>
#include <string.h>
#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 <time.h>
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
/* -------------------------------------------------------------------------- */

View File

@ -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 <ik@lowenware.com>
* 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 <ik@lowenware.com>
* @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 <stdint.h>
#include <stdarg.h>
#include <time.h>
/* 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 */

View File

@ -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));
}

View File

@ -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