Implemented all except parser
This commit is contained in:
parent
fc33a0e49e
commit
8847f92528
26
config.mk
26
config.mk
|
@ -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
|
|
||||||
#
|
|
|
@ -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
|
||||||
|
#
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -63,8 +63,7 @@ aisl_reject( aisl_stream_t stream );
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_response( aisl_stream_t stream,
|
aisl_response( aisl_stream_t stream,
|
||||||
aisl_http_response_t status_code,
|
aisl_http_response_t status_code,
|
||||||
const char * content_type,
|
uint64_t content_length );
|
||||||
uint32_t content_length);
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define AISL_AUTO_LENGTH (~0)
|
||||||
|
|
||||||
/* type casts */
|
/* type casts */
|
||||||
#define AISL_CALLBACK(x) ((aisl_callback_t) x)
|
#define AISL_CALLBACK(x) ((aisl_callback_t) x)
|
||||||
|
|
||||||
|
@ -229,13 +231,13 @@ typedef bool
|
||||||
const char * val );
|
const char * val );
|
||||||
|
|
||||||
typedef bool
|
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
|
typedef bool
|
||||||
(*aisl_on_stream_request_t)( aisl_stream_t stream );
|
(*aisl_on_stream_request_t)( aisl_stream_t stream );
|
||||||
|
|
||||||
typedef bool
|
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
|
typedef bool
|
||||||
(*aisl_on_stream_close_t)( aisl_stream_t stream );
|
(*aisl_on_stream_close_t)( aisl_stream_t stream );
|
||||||
|
|
|
@ -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
|
||||||
|
#
|
209
src/buffer.c
209
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 <ik@lowenware.com>
|
||||||
|
* @brief Buffer module source file
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "buffer.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
|
int32_t
|
||||||
buffer_init( buffer_t buffer, int32_t size )
|
buffer_init( buffer_t buffer, int32_t size )
|
||||||
{
|
{
|
||||||
if ((buffer->data = malloc(size)) != NULL)
|
if ( (size = buffer_set_size(buffer, size)) != -1)
|
||||||
{
|
buffer->used = 0;
|
||||||
buffer->size = size;
|
|
||||||
buffer->length = 0;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,90 +66,120 @@ buffer_release( buffer_t buffer )
|
||||||
if (buffer->data)
|
if (buffer->data)
|
||||||
free(buffer->data);
|
free(buffer->data);
|
||||||
|
|
||||||
buffer->length = 0;
|
buffer->used = 0;
|
||||||
buffer->size = 0;
|
buffer->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t
|
static int32_t
|
||||||
buffer_add( buffer_t self, const char * data, int32_t size )
|
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 )
|
return size;
|
||||||
{
|
|
||||||
memcpy( &ptr[self->size], data, size );
|
|
||||||
ptr[ result ] = 0;
|
|
||||||
self->data = ptr;
|
|
||||||
self->size = result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = -1;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t
|
int32_t
|
||||||
buffer_clear( buffer_t self, int32_t to_alloc )
|
buffer_insert( buffer_t buffer
|
||||||
{
|
, int32_t offset
|
||||||
self->length = 0;
|
, const char * data
|
||||||
|
, int32_t size )
|
||||||
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 )
|
|
||||||
{
|
{
|
||||||
int32_t result;
|
int32_t result;
|
||||||
|
|
||||||
if (size && !(size > self->size))
|
if ( (result = buffer_set_size(buffer, size)) != -1)
|
||||||
{
|
{
|
||||||
result = self->size - size;
|
if ((result = buffer_move_offset(buffer, offset, size)) != -1)
|
||||||
memmove(self->data, &self->data[size], result);
|
{
|
||||||
self->size = result;
|
memcpy(&buffer->data[offset], data, size);
|
||||||
|
buffer->used += result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
result = -1;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t
|
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;
|
va_start(args, format);
|
||||||
|
result = buffer_append_vprintf( buffer, format, args);
|
||||||
if ( (ptr = realloc(self->data, result+1)) != NULL )
|
va_end(args);
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
39
src/buffer.h
39
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 <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
|
struct buffer
|
||||||
{
|
{
|
||||||
char * data;
|
char * data;
|
||||||
int32_t size;
|
int32_t size;
|
||||||
int32_t length;
|
int32_t used;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct buffer * buffer_t;
|
typedef struct buffer * buffer_t;
|
||||||
|
@ -23,19 +39,24 @@ buffer_release( buffer_t buffer );
|
||||||
|
|
||||||
|
|
||||||
int32_t
|
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
|
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
|
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
|
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 */
|
||||||
|
|
30
src/client.c
30
src/client.c
|
@ -124,7 +124,7 @@ aisl_client_parse(aisl_client_t client, char * data, int32_t size)
|
||||||
|
|
||||||
|
|
||||||
if (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;
|
return AISL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -139,8 +139,8 @@ aisl_client_input(aisl_client_t client)
|
||||||
{
|
{
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
char * data = &client->in.data[ client->in.length ];
|
char * data = &client->in.data[ client->in.used ];
|
||||||
int32_t size = client->in.size - client->in.length;
|
int32_t size = client->in.size - client->in.used;
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#ifndef AISL_WITHOUT_SSL
|
||||||
if (client->ssl)
|
if (client->ssl)
|
||||||
|
@ -174,9 +174,9 @@ aisl_client_input(aisl_client_t client)
|
||||||
if (l > 0)
|
if (l > 0)
|
||||||
{
|
{
|
||||||
data = client->in.data;
|
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);
|
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 )
|
if ( !l )
|
||||||
return AISL_IDLE;
|
return AISL_IDLE;
|
||||||
|
@ -256,7 +256,7 @@ aisl_client_output(aisl_client_t client)
|
||||||
if (s->state == STREAM_RESPONSE_READY && / * flushed * /
|
if (s->state == STREAM_RESPONSE_READY && / * flushed * /
|
||||||
s->buffer->size == 0) / * all sent * /
|
s->buffer->size == 0) / * all sent * /
|
||||||
*/
|
*/
|
||||||
if ( ! aisl_stream_has_data(s) )
|
if ( aisl_stream_is_done(s) )
|
||||||
{
|
{
|
||||||
/* buffer_clear(s->buffer, 0); */
|
/* 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 ---------------------------------------------------------------- */
|
/* API Level ---------------------------------------------------------------- */
|
||||||
|
|
||||||
aisl_server_t
|
aisl_server_t
|
||||||
|
|
11
src/client.h
11
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.
|
* @return true if keepalive mode is on, otherwise false.
|
||||||
*/
|
*/
|
||||||
bool
|
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);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -43,11 +43,11 @@ typedef struct callback * callback_t;
|
||||||
|
|
||||||
struct aisl
|
struct aisl
|
||||||
{
|
{
|
||||||
list_t server_spool;
|
struct list server_spool;
|
||||||
list_t client_spool;
|
struct list client_spool;
|
||||||
list_t callback_spool;
|
struct list callback_spool;
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#ifndef AISL_WITHOUT_SSL
|
||||||
list_t ssl_spool;
|
struct list ssl_spool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char * last_error;
|
char * last_error;
|
||||||
|
@ -83,17 +83,17 @@ aisl_new( aisl_config_t config )
|
||||||
if ( !(instance = calloc(1, sizeof(struct aisl))) )
|
if ( !(instance = calloc(1, sizeof(struct aisl))) )
|
||||||
goto finally;
|
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;
|
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;
|
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;
|
goto release;
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#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;
|
goto release;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -115,18 +115,14 @@ __attribute__ ((visibility ("default") ))
|
||||||
void
|
void
|
||||||
aisl_free( aisl_t instance )
|
aisl_free( aisl_t instance )
|
||||||
{
|
{
|
||||||
if (instance->client_spool)
|
list_release(&instance->client_spool, (list_destructor_t) aisl_client_free );
|
||||||
list_free(instance->client_spool, (list_destructor_t) aisl_client_free );
|
|
||||||
|
|
||||||
if (instance->server_spool)
|
list_release(&instance->server_spool, (list_destructor_t) aisl_server_free );
|
||||||
list_free(instance->server_spool, (list_destructor_t) aisl_server_free );
|
|
||||||
|
|
||||||
if (instance->callback_spool)
|
list_release(&instance->callback_spool, (list_destructor_t) free);
|
||||||
list_free(instance->callback_spool, (list_destructor_t) free);
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#ifndef AISL_WITHOUT_SSL
|
||||||
if (instance->ssl_spool)
|
list_release(&instance->ssl_spool, (list_destructor_t) aisl_ssl_free );
|
||||||
list_free(instance->ssl_spool, (list_destructor_t) aisl_ssl_free );
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (instance->last_error)
|
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 ( (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);
|
aisl_server_free(result);
|
||||||
}
|
}
|
||||||
|
@ -226,9 +222,9 @@ aisl_set_ssl( aisl_t instance, const char * host,
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
/* lookup for existing contexts */
|
/* 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 &&
|
if (ssl->key_file && strcmp(ssl->key_file, key_file)==0 &&
|
||||||
ssl->crt_file && strcmp(ssl->crt_file, crt_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 (!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;
|
return AISL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,9 +256,9 @@ aisl_get_ssl_ctx( aisl_t instance, const char * host )
|
||||||
|
|
||||||
if (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)
|
if (strcmp(ssl->host, host) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -291,7 +287,7 @@ aisl_set_callback( aisl_t instance,
|
||||||
cb->event = event;
|
cb->event = event;
|
||||||
cb->f_ptr = callback;
|
cb->f_ptr = callback;
|
||||||
|
|
||||||
if ( list_append(instance->callback_spool, cb) != LIST_NAN )
|
if ( list_append(&instance->callback_spool, cb) != -1 )
|
||||||
{
|
{
|
||||||
switch(event)
|
switch(event)
|
||||||
{
|
{
|
||||||
|
@ -321,17 +317,17 @@ __attribute__ ((visibility ("default") ))
|
||||||
void
|
void
|
||||||
aisl_unset_callbacks_for( aisl_t instance, void * source )
|
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)
|
if (i)
|
||||||
{
|
{
|
||||||
for(i=i-1; i <= 0; 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 )
|
if ( callback->source == source )
|
||||||
{
|
{
|
||||||
free(callback);
|
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") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
bool
|
bool
|
||||||
aisl_raise_vl( aisl_t instance,
|
aisl_raise_vl( aisl_t instance,
|
||||||
|
@ -426,11 +411,11 @@ aisl_raise_vl( aisl_t instance,
|
||||||
bool result = false,
|
bool result = false,
|
||||||
stop_propg = false;
|
stop_propg = false;
|
||||||
|
|
||||||
i = instance->callback_spool->count;
|
i = instance->callback_spool.count;
|
||||||
|
|
||||||
while(i--)
|
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))
|
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_REQUEST:
|
||||||
case AISL_EVENT_STREAM_CLOSE:
|
case AISL_EVENT_STREAM_CLOSE:
|
||||||
case AISL_EVENT_STREAM_ERROR:
|
case AISL_EVENT_STREAM_ERROR:
|
||||||
|
case AISL_EVENT_STREAM_OUTPUT:
|
||||||
stop_propg = aisl_on_source_event(source, cb->f_ptr, vl_copy);
|
stop_propg = aisl_on_source_event(source, cb->f_ptr, vl_copy);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -461,10 +447,6 @@ aisl_raise_vl( aisl_t instance,
|
||||||
stop_propg = aisl_on_stream_input(source, cb->f_ptr, vl_copy);
|
stop_propg = aisl_on_stream_input(source, cb->f_ptr, vl_copy);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AISL_EVENT_STREAM_OUTPUT:
|
|
||||||
stop_propg = aisl_on_stream_output(source, cb->f_ptr, vl_copy);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
stop_propg = ((aisl_on_custom_event_t) cb->f_ptr)(source, vl_copy);
|
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;
|
aisl_status_t result = AISL_IDLE;
|
||||||
|
|
||||||
size_t i = instance->iterator,
|
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)
|
while ( result == AISL_IDLE && max != 0)
|
||||||
{
|
{
|
||||||
aisl_client_t cli;
|
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;
|
aisl_server_t srv;
|
||||||
SSL_CTX * ssl_ctx;
|
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)) ?
|
ssl_ctx = (aisl_server_get_ssl(srv)) ?
|
||||||
aisl_get_ssl_ctx(instance, NULL) :
|
aisl_get_ssl_ctx(instance, NULL) :
|
||||||
|
@ -512,7 +494,7 @@ aisl_run_cycle( aisl_t instance )
|
||||||
|
|
||||||
if (result == AISL_SUCCESS)
|
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);
|
aisl_raise(instance, cli, AISL_EVENT_CLIENT_CONNECT);
|
||||||
}
|
}
|
||||||
|
@ -525,17 +507,17 @@ aisl_run_cycle( aisl_t instance )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i = instance->server_spool->count;
|
i = instance->server_spool.count;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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);
|
result = aisl_client_touch(c);
|
||||||
|
|
||||||
|
@ -545,7 +527,7 @@ aisl_run_cycle( aisl_t instance )
|
||||||
if ( !aisl_client_is_online(c) )
|
if ( !aisl_client_is_online(c) )
|
||||||
{
|
{
|
||||||
aisl_client_free( c );
|
aisl_client_free( c );
|
||||||
list_remove_index(instance->client_spool, j);
|
list_remove_index(&instance->client_spool, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -598,9 +580,9 @@ aisl_sleep( aisl_t instance, uint32_t usec )
|
||||||
fd_set fs;
|
fd_set fs;
|
||||||
FD_ZERO (&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);
|
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);
|
sd = aisl_client_get_socket(c);
|
||||||
if (sd != -1)
|
if (sd != -1)
|
||||||
{
|
{
|
||||||
|
|
204
src/list.c
204
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:
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
* git://lowenware.com:standard.git
|
* Please, refer LICENSE file for legal information
|
||||||
* MAINTAINER:
|
|
||||||
* Ilja Kartaschoff <ik@lowenware.com>
|
|
||||||
*
|
*
|
||||||
* 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:
|
* @file list.c
|
||||||
* you can use, redistribute and/or modify it without any limits or
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
* restrictions.
|
* @brief List module source file
|
||||||
*
|
*
|
||||||
* All code described above is distributed in hope to be useful for somebody
|
* @see https://lowenware.com/aisl/
|
||||||
* 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 <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
int32_t
|
||||||
|
list_init(list_t list, int32_t size)
|
||||||
list_t
|
|
||||||
list_new(int size)
|
|
||||||
{
|
{
|
||||||
list_t self = calloc(1, sizeof(struct list));
|
if ((list->data = calloc(size, sizeof(void*))) != NULL)
|
||||||
if (self)
|
|
||||||
{
|
{
|
||||||
if (size)
|
list->size = size;
|
||||||
{
|
list->count = 0;
|
||||||
self->size = size;
|
return 0;
|
||||||
|
|
||||||
if ( (self->list = calloc(size, sizeof(void *))) == NULL )
|
|
||||||
{
|
|
||||||
free(self);
|
|
||||||
self = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return self;
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
list_free(list_t self, list_destructor_t destructor)
|
list_release(list_t list, list_destructor_t destructor)
|
||||||
{
|
{
|
||||||
int i;
|
if (list->data)
|
||||||
if (self)
|
|
||||||
{
|
{
|
||||||
if (self->list)
|
if (destructor)
|
||||||
{
|
{
|
||||||
if (destructor)
|
int32_t i;
|
||||||
|
for (i=0; i<list->count; i++)
|
||||||
{
|
{
|
||||||
for(i=0; i<self->count; i++)
|
void * ptr;
|
||||||
{
|
|
||||||
if (self->list[i])
|
if ( (ptr = list->data[i]) != NULL)
|
||||||
destructor(self->list[i]);
|
destructor( list->data[i] );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(self->list);
|
|
||||||
}
|
}
|
||||||
free(self);
|
free(list->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#ifdef CSTUFF_LIST_WITH_INSERT
|
int32_t
|
||||||
|
list_append(list_t list, void * entry)
|
||||||
int
|
|
||||||
list_insert( list_t self, void * item, int position )
|
|
||||||
{
|
{
|
||||||
int r;
|
int32_t pos = list->count;
|
||||||
|
|
||||||
if ( (r = list_append(self, item)) == -1)
|
if ( !(pos < list->size) )
|
||||||
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 ( (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;
|
return -1;
|
||||||
|
|
||||||
|
list->data = new_list;
|
||||||
self->list = new_list;
|
list->size = new_size;
|
||||||
self->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 *
|
void *
|
||||||
list_remove_index( list_t self, int index )
|
list_remove_index(list_t list, int32_t index)
|
||||||
{
|
{
|
||||||
void * result;
|
void * result;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (index < self->count)
|
if (index < list->count)
|
||||||
{
|
{
|
||||||
result = self->list[index];
|
int32_t i, c = --list->count;
|
||||||
self->count--;
|
|
||||||
for (i=index; i<self->count; i++)
|
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
|
else
|
||||||
|
@ -176,26 +97,3 @@ list_remove_index( list_t self, int index )
|
||||||
return result;
|
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
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
57
src/list.h
57
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 <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>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define LIST_NAN (~0)
|
#define LIST_INDEX(L, I) ( L.data[ I ] )
|
||||||
|
|
||||||
|
|
||||||
struct list
|
struct list
|
||||||
{
|
{
|
||||||
void ** list;
|
void ** data;
|
||||||
size_t size;
|
int32_t size;
|
||||||
size_t count;
|
int32_t count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct list * list_t;
|
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
|
int32_t
|
||||||
list_new(int size);
|
list_init(list_t list, int32_t 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);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
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 *
|
void *
|
||||||
list_remove_index( list_t self, int index );
|
list_remove_index(list_t list, int32_t index);
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
list_set_item(list_t self, int index, void * value);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* !AISL_LIST_H */
|
#endif /* !AISL_LIST_H */
|
||||||
|
|
|
@ -140,6 +140,14 @@ aisl_server_touch( aisl_server_t server,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
aisl_server_get_socket( aisl_server_t server )
|
||||||
|
{
|
||||||
|
return server->fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* API Level ---------------------------------------------------------------- */
|
/* API Level ---------------------------------------------------------------- */
|
||||||
|
|
||||||
aisl_server_t
|
aisl_server_t
|
||||||
|
|
646
src/str-utils.c
646
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:
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
* git://lowenware.com:standard.git
|
* Please, refer LICENSE file for legal information
|
||||||
* MAINTAINER:
|
|
||||||
* Ilja Kartaschoff <ik@lowenware.com>
|
|
||||||
*
|
*
|
||||||
* 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:
|
* @file str-utils.c
|
||||||
* you can use, redistribute and/or modify it without any limits or
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
* restrictions.
|
* @brief String utilities source file
|
||||||
*
|
*
|
||||||
* All code described above is distributed in hope to be useful for somebody
|
* @see https://lowenware.com/aisl/
|
||||||
* 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
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#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;
|
int l = strlen(source);
|
||||||
while ( *source != 0 && *target != 0 )
|
|
||||||
{
|
|
||||||
r = tolower(*source) - tolower(*target);
|
|
||||||
if ( r != 0 ) return r;
|
|
||||||
source++;
|
|
||||||
target++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ( *source == 0 && *target == 0 ) ? 0: -1;
|
char * result = malloc(l+1);
|
||||||
}
|
|
||||||
|
|
||||||
# endif
|
if (result)
|
||||||
|
strcpy(result, source);
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#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;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
int
|
||||||
|
str_cmpi(const char * s1, const char * s2)
|
||||||
#ifdef CSTUFF_STR_UTILS_WITH_FROM_TIMESTAMP
|
|
||||||
|
|
||||||
char *
|
|
||||||
str_from_timestamp_iso_utc(time_t ts)
|
|
||||||
{
|
{
|
||||||
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
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
110
src/str-utils.h
110
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:
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
* git://lowenware.com:standard.git
|
* Please, refer LICENSE file for legal information
|
||||||
* MAINTAINER:
|
|
||||||
* Ilja Kartaschoff <ik@lowenware.com>
|
|
||||||
*
|
*
|
||||||
* 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:
|
* @file str-utils.h
|
||||||
* you can use, redistribute and/or modify it without any limits or
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
* restrictions.
|
* @brief String utilities header file
|
||||||
*
|
*
|
||||||
* All code described above is distributed in hope to be useful for somebody
|
* @see https://lowenware.com/aisl/
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
|
|
||||||
#ifndef _CSTUFF_STR_UTILS_H_
|
#ifndef STR_UTILS_H_799148B5_F829_437C_8B96_55876A37C38E
|
||||||
#define _CSTUFF_STR_UTILS_H_
|
#define STR_UTILS_H_799148B5_F829_437C_8B96_55876A37C38E
|
||||||
|
|
||||||
#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);
|
|
||||||
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
str_printf(const char * format, ...);
|
str_copy(const char * source);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
str_to_int(const char * ptr, int l, int32_t * result);
|
str_cmpi(const char * anycase, const char * lowcase);
|
||||||
|
|
||||||
|
#endif /* !STR_UTILS_H */
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
416
src/stream.c
416
src/stream.c
|
@ -9,10 +9,13 @@
|
||||||
#include "str-utils.h"
|
#include "str-utils.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
#define FLAG_OUTPUT_READY (1<<0)
|
#define FLAG_FLUSHED (1<<0)
|
||||||
#define FLAG_OUTPUT_CHUNKED (1<<1)
|
#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
|
struct aisl_stream
|
||||||
{
|
{
|
||||||
|
@ -20,10 +23,10 @@ struct aisl_stream
|
||||||
aisl_client_t client;
|
aisl_client_t client;
|
||||||
|
|
||||||
void * u_ptr;
|
void * u_ptr;
|
||||||
const char * content_type;
|
|
||||||
|
|
||||||
size_t content_length;
|
uint64_t content_length;
|
||||||
int32_t content_offset;
|
int32_t head_offset;
|
||||||
|
int32_t body_offset;
|
||||||
int id;
|
int id;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
@ -32,6 +35,8 @@ struct aisl_stream
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Library level */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
aisl_stream_reset(aisl_stream_t stream, bool initial)
|
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);
|
buffer_release(&stream->buffer);
|
||||||
|
|
||||||
stream->u_ptr = NULL;
|
stream->u_ptr = NULL;
|
||||||
stream->content_type = NULL;
|
stream->content_length = AISL_AUTO_LENGTH;
|
||||||
stream->content_length = SIZE_NAN;
|
stream->head_offset = 0;
|
||||||
stream->content_offset = 0; /* headers length */
|
|
||||||
stream->flags = 0;
|
stream->flags = 0;
|
||||||
stream->state = AISL_STREAM_STATE_IDLE;
|
stream->state = AISL_STREAM_STATE_IDLE;
|
||||||
stream->response = AISL_HTTP_OK;
|
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?
|
/* Why it was here?
|
||||||
static int
|
static int
|
||||||
aisl_stream_write(aisl_stream_t stream, const char * data, uint32_t d_len)
|
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") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
void *
|
void *
|
||||||
aisl_get_context(aisl_stream_t s)
|
aisl_get_context(aisl_stream_t s)
|
||||||
|
@ -146,66 +211,107 @@ aisl_reject(aisl_stream_t s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static char *
|
static aisl_status_t
|
||||||
aisl_stream_get_response_begin(aisl_stream_t stream)
|
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") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
|
aisl_response( aisl_stream_t stream
|
||||||
const char *content_type,
|
, aisl_http_response_t status_code
|
||||||
uint32_t content_length)
|
, uint64_t content_length )
|
||||||
{
|
{
|
||||||
char * pch;
|
int32_t l;
|
||||||
int l;
|
|
||||||
|
|
||||||
|
|
||||||
/* check if those headers were already sent */
|
/* check if those headers were already sent */
|
||||||
if (stream->state > AISL_STREAM_STATE_READY) return AISL_IDLE;
|
if (stream->state > AISL_STREAM_STATE_READY) return AISL_IDLE;
|
||||||
|
|
||||||
stream->response = status_code;
|
stream->response = status_code;
|
||||||
stream->content_type = content_type;
|
|
||||||
stream->content_length = content_length;
|
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;
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
l = strlen(pch);
|
stream->head_offset = l;
|
||||||
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->state = AISL_STREAM_STATE_SEND_HEADER;
|
stream->state = AISL_STREAM_STATE_SEND_HEADER;
|
||||||
|
|
||||||
|
@ -217,39 +323,114 @@ __attribute__ ((visibility ("default") ))
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_flush(aisl_stream_t s)
|
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;
|
char hdr[ 40 ];
|
||||||
if (!aisl_header_printf(s, "Content-Length", "%u", s->content_length))
|
|
||||||
|
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;
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
|
s->flags |= FLAG_CONTENT_LENGTH_HEADER_SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
s->state = AISL_STREAM_STATE_DONE;
|
||||||
fprintf(stdout, "(%lu bytes)------->\n", stream->buffer->size);
|
s->flags |= FLAG_FLUSHED;
|
||||||
fwrite(stream->buffer->data, 1, stream->buffer->size, stdout);
|
|
||||||
fprintf(stdout, "<------\n");
|
|
||||||
*/
|
|
||||||
s->state = AISL_STREAM_STATE_READY;
|
|
||||||
|
|
||||||
s->flags |= FLAG_OUTPUT_READY;
|
|
||||||
|
|
||||||
return AISL_SUCCESS;
|
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") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
int
|
int32_t
|
||||||
aisl_header(aisl_stream_t stream, const char *key, const char *value)
|
aisl_header(aisl_stream_t stream, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
int ret;
|
int32_t result;
|
||||||
char * pch;
|
|
||||||
|
|
||||||
|
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 )
|
if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL )
|
||||||
{
|
{
|
||||||
ret = strlen(pch);
|
ret = strlen(pch);
|
||||||
if ( buffer_insert(
|
if ( buffer_insert(
|
||||||
&stream->buffer,
|
&stream->buffer,
|
||||||
stream->content_offset,
|
stream->end_of_headers,
|
||||||
pch,
|
pch,
|
||||||
ret
|
ret
|
||||||
) == -1 )
|
) == -1 )
|
||||||
|
@ -257,7 +438,7 @@ aisl_header(aisl_stream_t stream, const char *key, const char *value)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
stream->content_offset += ret;
|
stream->end_of_headers += ret;
|
||||||
|
|
||||||
free(pch);
|
free(pch);
|
||||||
}
|
}
|
||||||
|
@ -265,45 +446,60 @@ aisl_header(aisl_stream_t stream, const char *key, const char *value)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
int
|
int32_t
|
||||||
aisl_header_printf(aisl_stream_t stream, const char *key,
|
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_list args;
|
||||||
va_start(arg, f_value);
|
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") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
int
|
int32_t
|
||||||
aisl_header_vprintf(aisl_stream_t stream, const char *key,
|
aisl_header_vprintf(aisl_stream_t stream, const char *key,
|
||||||
const char *format,
|
const char *format,
|
||||||
va_list args)
|
va_list args)
|
||||||
{
|
{
|
||||||
int ret;
|
int32_t result,
|
||||||
char * value;
|
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 );
|
l = buffer_append_vprintf( &stream->buffer, format, args );
|
||||||
free(value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
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") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
int
|
int32_t
|
||||||
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
|
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
int result;
|
if (stream->state < AISL_STREAM_STATE_SEND_BODY)
|
||||||
char * r;
|
|
||||||
|
|
||||||
if ( (r = str_vprintf(format, args)) != NULL)
|
|
||||||
{
|
{
|
||||||
result = strlen(r);
|
if (aisl_stream_close_headers(stream) != AISL_SUCCESS)
|
||||||
if (buffer_add(&stream->buffer, r, result) == -1)
|
return -1;
|
||||||
result = -1;
|
|
||||||
|
|
||||||
free(r);
|
|
||||||
}
|
}
|
||||||
else
|
return buffer_append_vprintf(&stream->buffer, format, args);
|
||||||
result = -1;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
int
|
int32_t
|
||||||
aisl_write(aisl_stream_t stream, const char *data, int d_len)
|
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);
|
d_len = strlen(data);
|
||||||
|
|
||||||
if (buffer_add(&stream->buffer, data, d_len) == -1)
|
return buffer_append(&stream->buffer, data, d_len);
|
||||||
d_len = -1;
|
|
||||||
|
|
||||||
return d_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -370,7 +559,18 @@ __attribute__ ((visibility ("default") ))
|
||||||
int
|
int
|
||||||
aisl_puts(const char *str, aisl_stream_t stream)
|
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));
|
||||||
|
}
|
||||||
|
|
|
@ -47,8 +47,8 @@ int32_t
|
||||||
aisl_stream_get_buffer_size(aisl_stream_t stream);
|
aisl_stream_get_buffer_size(aisl_stream_t stream);
|
||||||
|
|
||||||
|
|
||||||
void
|
char *
|
||||||
aisl_stream_get_buffer(aisl_stream_t stream, char ** data, int32_t * size);
|
aisl_stream_get_data(aisl_stream_t stream, int32_t * p_length);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -56,7 +56,7 @@ aisl_stream_shift(aisl_stream_t stream, int32_t offset);
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
aisl_stream_has_data(aisl_stream_t stream);
|
aisl_stream_is_done(aisl_stream_t stream);
|
||||||
|
|
||||||
|
|
||||||
aisl_stream_state_t
|
aisl_stream_state_t
|
||||||
|
|
Loading…
Reference in New Issue