Refactoring pending

This commit is contained in:
Ilja Kartašov 2019-03-05 22:16:00 +01:00
parent 86b69c89b8
commit d87c7454b5
21 changed files with 1180 additions and 791 deletions

View File

@ -13,14 +13,8 @@
/* AISL configuration structure */ /* AISL configuration structure */
#include <aisl/config.h> #include <aisl/config.h>
/* AISL status codes and utilities */ /* AISL types and stringifiers */
#include <aisl/status.h> #include <aisl/types.h>
/* AISL callbacks definitions */
#include <aisl/callback.h>
/* AISL events enumeration and utilities*/
#include <aisl/event.h>
/* AISL instancing, initialization and processing */ /* AISL instancing, initialization and processing */
#include <aisl/instance.h> #include <aisl/instance.h>
@ -34,7 +28,4 @@
/* HTTP(s) streaming */ /* HTTP(s) streaming */
#include <aisl/stream.h> #include <aisl/stream.h>
/* HTTP constants and utilities */
#include <aisl/http.h>
#endif /* !AISL_H */ #endif /* !AISL_H */

View File

@ -1,76 +0,0 @@
/*
* <aisl/callback.h>
*
* Copyright (c) 2017 by Löwenware Ltd.
*
* Project homepage: https://lowenware.com/aisl/
*
*/
#ifndef AISL_CALLBACK_H_E99458C9_CCAA_4CAC_97F8_41E8869EE26F
#define AISL_CALLBACK_H_E99458C9_CCAA_4CAC_97F8_41E8869EE26F
#include <stdbool.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <aisl/server.h>
#include <aisl/client.h>
#include <aisl/stream.h>
#include <aisl/http.h>
#define AISL_CALLBACK(x) ((aisl_callback_t) x)
/* void-type callback */
typedef void
(* aisl_callback_t) (void);
/* real type callbacks */
typedef bool
(*aisl_server_open_t)( aisl_server_t server, int flags );
typedef bool
(*aisl_server_error_t)( aisl_server_t server, int flags, const char * details );
typedef bool
(*aisl_client_connect_t)( aisl_server_t server, aisl_client_t client );
typedef bool
(*aisl_client_disconnect_t)( aisl_server_t server, aisl_client_t client );
typedef bool
(*aisl_client_timeout_t)( aisl_server_t server, aisl_client_t client );
typedef bool
(*aisl_stream_open_t)( aisl_stream_t stream,
aisl_http_method_t method,
const char * path,
const char * query );
typedef bool
(*aisl_stream_header_t)( aisl_stream_t stream,
const char * key,
const char * val );
typedef bool
(*aisl_stream_input_t)( aisl_stream_t stream, char * data, int len );
typedef bool
(*aisl_stream_request_t)( aisl_stream_t stream );
typedef bool
(*aisl_stream_output_t)( aisl_stream_t stream, uint32_t buffer_space );
typedef bool
(*aisl_stream_close_t)( aisl_stream_t stream );
typedef bool
(*aisl_stream_error_t)( aisl_stream_t stream, const char * details );
typedef bool
(*aisl_custom_event_t)( void * source, va_list vl );
#endif /* !AISL_CALLBACK_H */

View File

@ -10,6 +10,6 @@
#ifndef AISL_CLIENT_H_A6C37DCF_2183_4F22_A5A0_668311757A08 #ifndef AISL_CLIENT_H_A6C37DCF_2183_4F22_A5A0_668311757A08
#define AISL_CLIENT_H_A6C37DCF_2183_4F22_A5A0_668311757A08 #define AISL_CLIENT_H_A6C37DCF_2183_4F22_A5A0_668311757A08
typedef struct aisl_client * aisl_client_t; #include <aisl/types.h>
#endif /* !AISL_CLIENT_H */ #endif /* !AISL_CLIENT_H */

View File

@ -1,42 +0,0 @@
/*
* <aisl/event.h>
*
* Copyright (c) 2017 by Löwenware Ltd.
*
* Project homepage: https://lowenware.com/aisl/
*
*/
#ifndef AISL_EVENT_H_E99458C9_CCAA_4CAC_97F8_41E8869EE26F
#define AISL_EVENT_H_E99458C9_CCAA_4CAC_97F8_41E8869EE26F
#include <stdint.h>
enum
{
AISL_SERVER_OPEN = 100
, AISL_SERVER_ERROR = 190
, AISL_CLIENT_CONNECT = 200
, AISL_CLIENT_DISCONNECT = 210
, AISL_CLIENT_TIMEOUT = 220
, AISL_STREAM_OPEN = 300
, AISL_STREAM_HEADER = 310
, AISL_STREAM_INPUT = 320
, AISL_STREAM_REQUEST = 330
, AISL_STREAM_OUTPUT = 340
, AISL_STREAM_CLOSE = 350
, AISL_STREAM_ERROR = 390
, AISL_EVENTS_CUSTOM = 1000
};
typedef uint32_t aisl_event_t;
const char *
aisl_event_get_text( aisl_event_t event );
#endif /* !AISL_EVENT_H */

View File

@ -1,104 +0,0 @@
/*
* aisl/http.h
*
* Copyright (c) 2017 by Löwenware Ltd.
*
* Project homepage: https://lowenware.com/aisl/
*
*/
#ifndef AISL_HTTP_H_2BB40A17_5EB3_438B_8A98_EB3C68BA3A45
#define AISL_HTTP_H_2BB40A17_5EB3_438B_8A98_EB3C68BA3A45
typedef enum
{
AISL_HTTP_1_0
, AISL_HTTP_1_1
, AISL_HTTP_2_0
} aisl_http_version_t;
typedef enum
{
AISL_HTTP_GET
, AISL_HTTP_PUT
, AISL_HTTP_POST
, AISL_HTTP_HEAD
, AISL_HTTP_TRACE
, AISL_HTTP_DELETE
, AISL_HTTP_OPTIONS
, AISL_HTTP_CONNECT
, AISL_HTTP_PRI
} aisl_http_method_t;
typedef enum
{
AISL_HTTP_CONTINUE = 100
, AISL_HTTP_SWITCHING_PROTOCOLS
, AISL_HTTP_OK = 200
, AISL_HTTP_CREATED
, AISL_HTTP_ACCEPTED
, AISL_HTTP_NON_AUTHORITATIVE_INFORMATION
, AISL_HTTP_NO_CONTENT
, AISL_HTTP_RESET_CONTENT
, AISL_HTTP_PARTIAL_CONTENT
, AISL_HTTP_MULTIPLE_CHOICES = 300
, AISL_HTTP_MOVED_PERMANENTLY
, AISL_HTTP_FOUND
, AISL_HTTP_SEE_OTHER
, AISL_HTTP_NOT_MODIFIED
, AISL_HTTP_USE_PROXY
, AISL_HTTP_UNUSED
, AISL_HTTP_TEMPORARY_REDIRECT
, AISL_HTTP_BAD_REQUEST = 400
, AISL_HTTP_UNAUTHORIZED
, AISL_HTTP_PAYMENT_REQUIRED
, AISL_HTTP_FORBIDDEN
, AISL_HTTP_NOT_FOUND
, AISL_HTTP_METHOD_NOT_ALLOWED
, AISL_HTTP_NOT_ACCEPTABLE
, AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED
, AISL_HTTP_REQUEST_TIMEOUT
, AISL_HTTP_CONFLICT
, AISL_HTTP_GONE
, AISL_HTTP_LENGTH_REQUIRED
, AISL_HTTP_PRECONDITION_FAILED
, AISL_HTTP_REQUEST_ENTITY_TOO_LARGE
, AISL_HTTP_REQUEST_URI_TOO_LONG
, AISL_HTTP_UNSUPPORTED_MEDIA_TYPE
, AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE
, AISL_HTTP_EXPECTATION_FAILED
, AISL_HTTP_INTERNAL_SERVER_ERROR = 500
, AISL_HTTP_NOT_IMPLEMENTED
, AISL_HTTP_BAD_GATEWAY
, AISL_HTTP_SERVICE_UNAVAILABLE
, AISL_HTTP_GATEWAY_TIMEOUT
, AISL_HTTP_VERSION_NOT_SUPPORTED
} aisl_http_response_t;
const char *
aisl_http_version_to_string( aisl_http_version_t version );
const char *
aisl_http_response_to_string( aisl_http_response_t code );
const char *
aisl_http_secure_to_string( int is_secure );
const char *
aisl_http_method_to_string( aisl_http_method_t method );
#endif /* !AISL_HTTP_H */

View File

@ -7,69 +7,76 @@
* *
*/ */
#ifndef INSTANCE_H_60576F41_454C_4189_B91A_F40501132230 #ifndef AISL_INSTANCE_H_60576F41_454C_4189_B91A_F40501132230
#define INSTANCE_H_60576F41_454C_4189_B91A_F40501132230 #define AISL_INSTANCE_H_60576F41_454C_4189_B91A_F40501132230
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <aisl/types.h>
#include <aisl/config.h>
typedef struct aisl_instance * aisl_instance_t;
/* Initialization functions */ /* Initialization functions */
aisl_instance_t aisl_t
aisl_new( aisl_config_t * config ); aisl_new( aisl_config_t config );
void void
aisl_free( aisl_instance_t instance ); aisl_free( aisl_t instance );
aisl_server_t aisl_server_t
aisl_listen( aisl_instance_t instance, aisl_listen( aisl_t instance, const char * address, uint16_t port );
const char * address,
uint16_t port );
#ifdef AISL_WITH_SSL #ifdef AISL_WITH_SSL
aisl_status_t aisl_status_t
aisl_set_ssl( aisl_instance_t instance, aisl_set_ssl( aisl_t instance,
const char * hostname, const char * hostname,
const char * key_file, const char * key_file,
const char * crt_file ); const char * crt_file );
#endif #endif
/* Callbacks and Events functions */
aisl_status_t aisl_status_t
aisl_set_callback( aisl_instance_t instance, aisl_set_callback( aisl_t instance,
void * source, void * source,
aisl_event_t e_id, aisl_event_t event,
aisl_callback_t cb ); aisl_callback_t callback );
aisl_status_t
aisl_raise( aisl_t instance, void * source, aisl_event_t event, ... );
aisl_status_t
aisl_raise_vl( aisl_t instance,
void * source,
aisl_event_t event,
va_list args );
void
aisl_unset_callback_for( aisl_t instance, void * source );
/* Control functions */ /* Control functions */
aisl_status_t aisl_status_t
aisl_run_cycle( aisl_instance_t instance ); aisl_run_cycle( aisl_t instance );
const char * const char *
aisl_get_error( aisl_instance_t instance ); aisl_get_error( aisl_t instance );
aisl_status_t aisl_status_t
aisl_sleep( aisl_instance_t instance, uint32_t usec ); aisl_sleep( aisl_t instance, uint32_t usec );
aisl_status_t #endif /* !AISL_INSTANCE_H */
aisl_raise( aisl_instance_t instance, aisl_event_t event, ...);
aisl_status_t
aisl_raisev( aisl_instance_t instance, aisl_event_t event, va_list args);
#endif /* !INSTANCE_H */

View File

@ -10,9 +10,8 @@
#ifndef AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768 #ifndef AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768
#define AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768 #define AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768
typedef struct aisl_server * aisl_server_t;
#include <aisl/types.h>
#ifdef AISL_WITH_SSL #ifdef AISL_WITH_SSL
aisl_status_t aisl_status_t

View File

@ -1,29 +0,0 @@
/*
* <aisl/status.h>
*
* Copyright (c) 2017 by Löwenware Ltd.
*
* Project homepage: https://lowenware.com/aisl/
*
*/
#ifndef AISL_STATUS_H_BF7E4434_A711_4D7C_B3AE_1BA2E1A020EF
#define AISL_STATUS_H_BF7E4434_A711_4D7C_B3AE_1BA2E1A020EF
typedef enum
{
AISL_EXTCALL_ERROR = -3
, AISL_SYSCALL_ERROR = -2
, AISL_MALLOC_ERROR = -1
, AISL_SUCCESS = 0
, AISL_IDLE = 1
} aisl_status_t;
const char *
aisl_status_to_string(aisl_status_t status);
#endif /* !AISL_STATUS_H */

View File

@ -7,10 +7,13 @@
* *
*/ */
#ifndef STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC #ifndef AISL_STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC
#define STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC #define AISL_STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC
#include <stdint.h>
#include <stdarg.h>
#include <aisl/types.h>
typedef struct aisl_stream * aisl_stream_t;
/* Stream helpers */ /* Stream helpers */
@ -31,7 +34,7 @@ aisl_http_version_t
aisl_get_http_version( aisl_stream_t stream ); aisl_get_http_version( aisl_stream_t stream );
aisl_instance_t aisl_t
aisl_stream_get_instance( aisl_stream_t s ); aisl_stream_get_instance( aisl_stream_t s );

243
include/aisl/types.h Normal file
View File

@ -0,0 +1,243 @@
/*
* <aisl/types.h>
*
* Copyright (c) 2017-2019 by Löwenware Ltd.
*
* Project homepage: https://lowenware.com/aisl/
*
*/
#ifndef AISL_TYPES_H_86A9DBA7_C0E6_4CF4_8A64_DAAD4A81031B
#define AISL_TYPES_H_86A9DBA7_C0E6_4CF4_8A64_DAAD4A81031B
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
/* type casts */
#define AISL_CALLBACK(x) ((aisl_callback_t) x)
/* AISL Instance */
typedef struct aisl * aisl_t;
/* Event Identifier */
typedef uint32_t aisl_event_t;
/* HTTP(s) Server */
typedef struct aisl_server * aisl_server_t;
/* HTTP(s) Client */
typedef struct aisl_client * aisl_client_t;
/* Server<->Client Stream */
typedef struct aisl_stream * aisl_stream_t;
/* void type event callback */
typedef void
(* aisl_callback_t) (void);
/* status return codes */
typedef enum
{
AISL_EXTCALL_ERROR = -3
, AISL_SYSCALL_ERROR = -2
, AISL_MALLOC_ERROR = -1
, AISL_SUCCESS = 0
, AISL_IDLE = 1
} aisl_status_t;
#ifdef WITH_STRINGIFIERS
const char *
aisl_status_to_string(aisl_status_t status);
#endif
/* Generic HTTP Enumerations */
typedef enum
{
AISL_HTTP_1_0
, AISL_HTTP_1_1
, AISL_HTTP_2_0
} aisl_http_version_t;
#ifdef WITH_STRINGIFIERS
const char *
aisl_http_version_to_string( aisl_http_version_t version );
#endif
typedef enum
{
AISL_HTTP_GET
, AISL_HTTP_PUT
, AISL_HTTP_POST
, AISL_HTTP_HEAD
, AISL_HTTP_TRACE
, AISL_HTTP_DELETE
, AISL_HTTP_OPTIONS
, AISL_HTTP_CONNECT
, AISL_HTTP_PRI
} aisl_http_method_t;
#ifdef WITH_STRINGIFIERS
const char *
aisl_http_method_to_string( aisl_http_method_t method );
#endif
typedef enum
{
AISL_HTTP_CONTINUE = 100
, AISL_HTTP_SWITCHING_PROTOCOLS
, AISL_HTTP_OK = 200
, AISL_HTTP_CREATED
, AISL_HTTP_ACCEPTED
, AISL_HTTP_NON_AUTHORITATIVE_INFORMATION
, AISL_HTTP_NO_CONTENT
, AISL_HTTP_RESET_CONTENT
, AISL_HTTP_PARTIAL_CONTENT
, AISL_HTTP_MULTIPLE_CHOICES = 300
, AISL_HTTP_MOVED_PERMANENTLY
, AISL_HTTP_FOUND
, AISL_HTTP_SEE_OTHER
, AISL_HTTP_NOT_MODIFIED
, AISL_HTTP_USE_PROXY
, AISL_HTTP_UNUSED
, AISL_HTTP_TEMPORARY_REDIRECT
, AISL_HTTP_BAD_REQUEST = 400
, AISL_HTTP_UNAUTHORIZED
, AISL_HTTP_PAYMENT_REQUIRED
, AISL_HTTP_FORBIDDEN
, AISL_HTTP_NOT_FOUND
, AISL_HTTP_METHOD_NOT_ALLOWED
, AISL_HTTP_NOT_ACCEPTABLE
, AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED
, AISL_HTTP_REQUEST_TIMEOUT
, AISL_HTTP_CONFLICT
, AISL_HTTP_GONE
, AISL_HTTP_LENGTH_REQUIRED
, AISL_HTTP_PRECONDITION_FAILED
, AISL_HTTP_REQUEST_ENTITY_TOO_LARGE
, AISL_HTTP_REQUEST_URI_TOO_LONG
, AISL_HTTP_UNSUPPORTED_MEDIA_TYPE
, AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE
, AISL_HTTP_EXPECTATION_FAILED
, AISL_HTTP_INTERNAL_SERVER_ERROR = 500
, AISL_HTTP_NOT_IMPLEMENTED
, AISL_HTTP_BAD_GATEWAY
, AISL_HTTP_SERVICE_UNAVAILABLE
, AISL_HTTP_GATEWAY_TIMEOUT
, AISL_HTTP_VERSION_NOT_SUPPORTED
} aisl_http_response_t;
#ifdef WITH_STRINGIFIERS
const char *
aisl_http_response_to_string( aisl_http_response_t code );
#endif
#ifdef WITH_STRINGIFIERS
const char *
aisl_http_secure_to_string( bool is_secure );
#endif
/* Built-in Events IDs */
enum
{
AISL_EVENT_SERVER_OPEN = 100
, AISL_EVENT_SERVER_ERROR = 190
, AISL_EVENT_CLIENT_CONNECT = 200
, AISL_EVENT_CLIENT_DISCONNECT = 210
, AISL_EVENT_CLIENT_TIMEOUT = 220
, AISL_EVENT_STREAM_OPEN = 300
, AISL_EVENT_STREAM_HEADER = 310
, AISL_EVENT_STREAM_INPUT = 320
, AISL_EVENT_STREAM_REQUEST = 330
, AISL_EVENT_STREAM_OUTPUT = 340
, AISL_EVENT_STREAM_CLOSE = 350
, AISL_EVENT_STREAM_ERROR = 390
, AISL_EVENTS_CUSTOM = 1000
};
#ifdef WITH_STRINGIFIERS
const char *
aisl_event_to_string( aisl_event_t event );
#endif
/* real type event callbacks */
typedef bool
(*aisl_on_server_open_t)( aisl_server_t server );
typedef bool
(*aisl_on_server_error_t)( aisl_server_t server );
typedef bool
(*aisl_on_client_connect_t)( aisl_client_t client );
typedef bool
(*aisl_on_client_disconnect_t)( aisl_client_t client );
typedef bool
(*aisl_on_client_timeout_t)( aisl_client_t client );
typedef bool
(*aisl_on_stream_open_t)( aisl_stream_t stream,
aisl_http_method_t method,
const char * path,
const char * query );
typedef bool
(*aisl_on_stream_header_t)( aisl_stream_t stream,
const char * key,
const char * val );
typedef bool
(*aisl_on_stream_input_t)( aisl_stream_t stream, char * data, size_t len );
typedef bool
(*aisl_on_stream_request_t)( aisl_stream_t stream );
typedef bool
(*aisl_on_stream_output_t)( aisl_stream_t stream, size_t buffer_space );
typedef bool
(*aisl_on_stream_close_t)( aisl_stream_t stream );
typedef bool
(*aisl_on_stream_error_t)( aisl_stream_t stream );
typedef bool
(*aisl_on_custom_event_t)( void * source, va_list vl );
#endif /* !AISL_TYPES_H */

View File

@ -1,376 +0,0 @@
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>
#include <sys/time.h>
#include <aisl/aisl.h>
#include "aisl.h"
#include "list.h"
#include "str-utils.h"
#include "handle.h"
#include "client.h"
#include "server.h"
#include "globals.h"
#include "stream.h"
#include "buffer.h"
struct aisl_instance
{
list_t * servers;
#ifdef AISL_WITH_SSL
list_t * ssl;
#endif
list_t servers;
list_t clients;
list_t callbacks;
buffer_t buffer;
char * last_error;
int iterator;
int stage;
int flags;
uint32_t accept_limit;
};
#ifdef AISL_WITH_SSL
static uint32_t m_instances = 0;
#endif
/* Initialization functions */
__attribute__ ((visibility ("default") ))
aisl_t
aisl_new( aisl_config_t * config )
{
aisl_t self;
#ifdef AISL_WITH_SSL
if ((m_instances++) == 0)
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
#endif
if ( !(self = calloc(1, sizeof(struct aisl_instance))) )
goto finally;
if ( !(self->servers = list_new(config->servers_spool_size)) )
goto release;
if ( !(self->clients = list_new(config->clients_spool_size)) )
goto release;
if ( !(self->callbacks = list_new(config->callbacks_spool_size)) )
goto release;
if ( !(self->buffer = buffer_new(config->initial_buffer_size)) )
goto release;
#ifdef AISL_WITH_SSL
if ( !(self->ssl = list_new(config->ssl_spool_size)) )
goto release;
#endif
self->accept_limit = config->clients_accept_limit;
goto finally;
release:
aisl_free(self);
self = NULL;
finally:
return self;
}
__attribute__ ((visibility ("default") ))
void
aisl_free( aisl_t self )
{
if (self->clients)
list_free(self->clients, (list_destructor_t) client_free );
if (self->servers)
list_free(self->servers, (list_destructor_t) server_free );
if (self->callbacks)
list_free(self->callbacks, free);
if (self->buffer)
buffer_free(self->buffer);
if (self->ssl)
list_free(self->ssl, (list_destructor_t) crypter_free );
if (self->last_error)
free(self->last_error);
free(self);
#ifdef AISL_WITH_SSL
if ((--m_instances) == 0)
{
EVP_cleanup();
}
#endif
}
__attribute__ ((visibility ("default") ))
aisl_server_t
aisl_listen( aisl_instance_t instance,
const char * address,
uint16_t port )
{
aisl_server_t result;
if ( (result = aisl_server_new(address, port)) != NULL )
{
result->instance = instance;
if (list_append(instance->servers, result) == LIST_NAN)
{
server_free(result);
}
}
return result;
}
static char *
get_response_begin(stream_t stream)
{
char * r;
client_t cli = CLIENT(ASTREAM(stream)->client);
r = str_printf(
"%s %d %s\r\n"
"Server: AISL\r\n"
"Connection: %s\r\n\r\n",
aisl_http_version_to_string(cli->protocol),
stream->response,
aisl_http_response_to_string(stream->response),
((cli->flags & CLIENT_FLAG_KEEPALIVE) ? "keep-alive" : "close")
);
return r;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
const char *content_type,
uint32_t content_length)
{
char * pch;
int l;
/* check if those headers were already sent */
if (STREAM(stream)->state > STREAM_REQUEST_READY) return AISL_IDLE;
STREAM(stream)->response = status_code;
STREAM(stream)->c_type = content_type;
STREAM(stream)->c_length = content_length;
if ( !(pch = get_response_begin(STREAM(stream))) )
return AISL_MALLOC_ERROR;
l = strlen(pch);
STREAM(stream)->c_offset = l-2;
buffer_clear(STREAM(stream)->buffer, content_length);
l = buffer_add( STREAM(stream)->buffer, pch, l );
free(pch);
if (l == BUFFER_EOB) return AISL_MALLOC_ERROR;
if (content_length)
{
if (!aisl_header_printf( stream, "Content-Length", "%u", content_length ))
return AISL_MALLOC_ERROR;
}
if (content_type)
{
if (!aisl_header( stream, "Content-Type", content_type ))
return AISL_MALLOC_ERROR;
}
STREAM(stream)->state = STREAM_RESPONSE_HEADER;
return AISL_SUCCESS;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_flush(aisl_stream_t stream)
{
stream_t s = STREAM(stream);
if ( ! s->c_length )
{
s->c_length = s->buffer->size - s->c_offset - 2;
if (!aisl_header_printf(stream, "Content-Length", "%u", s->c_length))
return AISL_MALLOC_ERROR;
}
/*
fprintf(stdout, "(%lu bytes)------->\n", STREAM(stream)->buffer->size);
fwrite(STREAM(stream)->buffer->data, 1, STREAM(stream)->buffer->size, stdout);
fprintf(stdout, "<------\n");
*/
s->state = STREAM_RESPONSE_READY;
s->flags |= STREAM_FLAG_OUTPUT_READY;
return AISL_SUCCESS;
}
__attribute__ ((visibility ("default") ))
int
aisl_header(aisl_stream_t stream, const char *key, const char *value)
{
int ret;
char * pch;
if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL )
{
ret = strlen(pch);
if ( buffer_insert(
STREAM(stream)->buffer,
STREAM(stream)->c_offset,
pch,
ret
) == BUFFER_EOB )
{
ret = -1;
}
else
STREAM(stream)->c_offset += ret;
free(pch);
}
else
ret = -1;
return ret;
}
__attribute__ ((visibility ("default") ))
int
aisl_header_printf(aisl_stream_t stream, const char *key,
const char *f_value, ...)
{
int ret;
va_list arg;
va_start(arg, f_value);
ret = aisl_header_vprintf(stream, key, f_value, arg);
va_end(arg);
return ret;
}
__attribute__ ((visibility ("default") ))
int
aisl_header_vprintf(aisl_stream_t stream, const char *key,
const char *format,
va_list args)
{
int ret;
char * value;
if ( (value = str_vprintf(format, args)) != NULL )
{
ret = aisl_header( stream, key, value );
free(value);
}
else
ret = -1;
return ret;
}
__attribute__ ((visibility ("default") ))
int
aisl_printf(aisl_stream_t stream, const char *format, ...)
{
va_list arg;
va_start(arg, format);
int result = aisl_vprintf(stream, format, arg);
va_end(arg);
/* No need to update length there, because vprintf do that
*
* if (STREAM(stream)->c_length_unknown)
STREAM(stream)->c_length += result;
*/
return result;
}
__attribute__ ((visibility ("default") ))
int
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
{
int result;
char * r;
if ( (r = str_vprintf(format, args)) != NULL)
{
result = strlen(r);
if (buffer_add(STREAM(stream)->buffer, r, result) == BUFFER_EOB)
result = -1;
free(r);
}
else
result = -1;
return result;
}
__attribute__ ((visibility ("default") ))
int
aisl_write(aisl_stream_t stream, const char *data, int d_len)
{
if (d_len < 0)
d_len = strlen(data);
if (buffer_add(STREAM(stream)->buffer, data, d_len) == BUFFER_EOB)
d_len = -1;
return d_len;
}
__attribute__ ((visibility ("default") ))
int
aisl_puts(const char *str, aisl_stream_t stream)
{
return aisl_write( stream, str, strlen(str));
}

View File

@ -1,19 +0,0 @@
/*
* src/aisl.h
*
* Copyright (c) 2017 by Löwenware Ltd.
*
* Project homepage: https://lowenware.com/aisl/
*
*/
#ifndef AISL_H_F49DC34C_7EF3_44EF_8E4B_22F4CC1A665C
#define AISL_H_F49DC34C_7EF3_44EF_8E4B_22F4CC1A665C
bool
aisl_raise_event( aisl_instance_t instance,
void * source,
aisl_event_t e_id,
... );
#endif /* !AISL_H */

View File

@ -15,7 +15,22 @@
#ifndef OUTPUT_BUFFER_SIZE #ifndef OUTPUT_BUFFER_SIZE
#define OUTPUT_BUFFER_SIZE 4096 #define OUTPUT_BUFFER_SIZE 4096
#endif #endif
struct client
{
struct sockaddr_in address;
server_t server;
int fd;
int next_id; /* server id generator (even, starts from 2) */
int istream; /* input stream id */
int ostream; /* output stream id */
list_t streams;
SSL * ssl;
time_t timestamp;
aisl_http_version_t protocol;
int flags;
};
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
void void

View File

@ -1,67 +1,47 @@
#ifndef _AISL_CLIENT_H_ #ifndef AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
#define _AISL_CLIENT_H_ #define AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
#include <time.h> #include <time.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <aisl/aisl.h>
#include <aisl/http.h>
#include "list.h"
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <aisl/client.h>
#include "server.h" #include "server.h"
#include "list.h"
#define CLIENT_FLAG_KEEPALIVE (1<<0) #define CLIENT_FLAG_KEEPALIVE (1<<0)
#define CLIENT_FLAG_HANDSHAKE (1<<1) #define CLIENT_FLAG_HANDSHAKE (1<<1)
#define CLIENT(x) ((aisl_client_t)x)
struct client
{
struct sockaddr_in address;
server_t server;
int fd;
int next_id; /* server id generator (even, starts from 2) */
int istream; /* input stream id */
int ostream; /* output stream id */
list_t streams;
SSL * ssl;
time_t timestamp;
aisl_http_version_t protocol;
int flags;
};
typedef struct client * client_t;
#define CLIENT(x) ((client_t)x)
/* constructor -------------------------------------------------------------- */ /* constructor -------------------------------------------------------------- */
aisl_status_t aisl_status_t
client_accept(client_t * self, server_t server); aisl_client_accept(aisl_client_t * self, aisl_server_t server);
/* destructor --------------------------------------------------------------- */ /* destructor --------------------------------------------------------------- */
void void
client_free(client_t self); aisl_client_free(aisl_client_t self);
/* all regular client routines. return true if something happened ----------- */ /* all regular client routines. return true if something happened ----------- */
bool bool
client_touch(client_t self); aisl_client_touch(aisl_client_t self);
/* check if communication time with client is expired ----------------------- */ /* check if communication time with client is expired ----------------------- */
bool bool
client_is_timeout(client_t self); aisl_client_is_timeout(aisl_client_t self);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
void void
client_close(client_t self); aisl_client_close(aisl_client_t self);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
#endif
#endif /* !AISL_CLIENT_H */

View File

@ -1,9 +1,7 @@
#ifndef _AISL_GLOBALS_H_ #ifndef _AISL_GLOBALS_H_
#define _AISL_GLOBALS_H_ #define _AISL_GLOBALS_H_
#pragma GCC diagnostic ignored "-Wuninitialized" //#pragma GCC diagnostic ignored "-Wuninitialized"
#include <aisl/handle.h>
/* MACOS FIX AND OTHER OS */ /* MACOS FIX AND OTHER OS */
#ifndef SOCK_NONBLOCK #ifndef SOCK_NONBLOCK
@ -42,7 +40,4 @@
#define AISL_MAX_CLIENT_SILENCE 10 #define AISL_MAX_CLIENT_SILENCE 10
#endif #endif
extern aisl_handle_t gHandle;
#endif #endif

View File

@ -7,7 +7,579 @@
* *
*/ */
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>
#include <sys/time.h>
#include "list.h"
#include "str-utils.h"
#include "buffer.h"
#include "client.h"
#include "server.h"
//#include "globals.h"
//#include "stream.h"
#include "instance.h" #include "instance.h"
enum {
AISL_CYCLE_SERVER = 0
, AISL_CYCLE_CLIENT = 1
};
struct aisl
{
list_t servers;
list_t clients;
list_t callbacks;
#ifdef AISL_WITH_SSL
list_t ssl;
#endif
buffer_t buffer;
char * last_error;
int iterator;
int stage;
int flags;
uint32_t accept_limit;
};
#ifdef AISL_WITH_SSL
static uint32_t m_instances = 0;
#endif
/* Initialization functions */
__attribute__ ((visibility ("default") ))
aisl_t
aisl_new( aisl_config_t config )
{
aisl_t instance;
#ifdef AISL_WITH_SSL
if ((m_instances++) == 0)
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
#endif
if ( !(instance = calloc(1, sizeof(struct aisl))) )
goto finally;
if ( !(instance->servers = list_new(config->servers_spool_size)) )
goto release;
if ( !(instance->clients = list_new(config->clients_spool_size)) )
goto release;
if ( !(instance->callbacks = list_new(config->callbacks_spool_size)) )
goto release;
if ( !(instance->buffer = buffer_new(config->initial_buffer_size)) )
goto release;
#ifdef AISL_WITH_SSL
if ( !(instance->ssl = list_new(config->ssl_spool_size)) )
goto release;
#endif
instance->accept_limit = config->clients_accept_limit;
goto finally;
release:
aisl_free(instance);
instance = NULL;
finally:
return instance;
}
__attribute__ ((visibility ("default") ))
void
aisl_free( aisl_t instance )
{
if (instance->clients)
list_free(instance->clients, (list_destructor_t) aisl_client_free );
if (instance->servers)
list_free(instance->servers, (list_destructor_t) aisl_server_free );
if (instance->callbacks)
list_free(instance->callbacks, free);
if (instance->buffer)
buffer_free(instance->buffer);
if (instance->ssl)
list_free(instance->ssl, (list_destructor_t) ssl_free );
if (instance->last_error)
free(instance->last_error);
free(instance);
#ifdef AISL_WITH_SSL
if ((--m_instances) == 0)
{
EVP_cleanup();
}
#endif
}
__attribute__ ((visibility ("default") ))
aisl_server_t
aisl_listen( aisl_t instance, const char * address, uint16_t port )
{
aisl_server_t result;
if ( (result = aisl_server_new(address, port)) != NULL )
{
result->instance = instance;
if (list_append(instance->servers, result) == LIST_NAN)
{
aisl_server_free(result);
}
}
return result;
}
#ifdef AISL_WITH_SSL
static int
get_ssl_context( SSL * ssl, int * ptr, void * handle )
{
const char * server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
SSL_CTX * ctx = aisl_get_ssl_ctx( (aisl_t) handle, server_name );
if (ctx)
{
SSL_set_SSL_CTX(ssl, ctx);
}
return SSL_TLSEXT_ERR_OK;
}
/* -------------------------------------------------------------------------- */
static SSL_CTX *
create_ssl_context( aisl_t instance,
const char * key_file,
const char * crt_file )
{
const SSL_METHOD * method;
SSL_CTX * ctx;
method = SSLv23_server_method();
if ( !(ctx = SSL_CTX_new(method)) )
goto except;
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tlsext_servername_callback( ctx, get_ssl_context );
SSL_CTX_set_tlsext_servername_arg( ctx, (void *) instance );
if (!(SSL_CTX_use_certificate_file(ctx, crt_file, SSL_FILETYPE_PEM) > 0))
goto release;
if (!(SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) > 0))
goto release;
goto finally;
release:
SSL_CTX_free(ctx);
ctx = NULL;
except:
aisl_set_error( instance, ERR_error_string(ERR_get_error(),NULL) );
finally:
return ctx;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_ssl( aisl_t instance, const char * server_name,
const char * key_file,
const char * crt_file )
{
SSL_CTX * ssl_ctx = NULL;
int i;
crypter_t crypter;
/* lookup for existing contexts */
for (i=0; i<instance->crypters->count; i++)
{
crypter = list_index(instance->crypters, i);
if (crypter->keyFile && strcmp(crypter->keyFile, key_file)==0 &&
crypter->crtFile && strcmp(crypter->crtFile, crt_file)==0 )
{
ssl_ctx = crypter->sslCtx;
key_file = NULL;
crt_file = NULL;
break;
}
}
if (! (crypter = crypter_new(server_name, key_file, crt_file)) )
{
return AISL_MALLOC_ERROR;
}
if (! ssl_ctx)
{
if (!(ssl_ctx = create_ssl_context(instance, key_file, crt_file)))
{
crypter_free(crypter);
return AISL_EXTCALL_ERROR;
}
}
crypter->sslCtx = ssl_ctx;
if (list_append(instance->crypters, crypter)==-1)
{
crypter_free(crypter);
return AISL_MALLOC_ERROR;
}
return AISL_SUCCESS;
}
SSL_CTX *
aisl_get_ssl_ctx( aisl_t instance, const char * server_name )
{
int i;
crypter_t crypter;
for (i=0; i<instance->crypters->count; i++)
{
crypter = list_index(instance->crypters, i);
if (server_name)
{
if (strcmp(crypter->srvName, server_name)!=0)
continue;
}
return crypter->sslCtx;
}
return NULL;
}
#endif
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_callback( aisl_t instance,
void * source,
aisl_event_t e_id,
aisl_callback_t cb )
{
listener_t listener;
if (! (listener = listener_new(source, e_id, cb)) )
return AISL_MALLOC_ERROR;
if (list_append(instance->callbacks, listener) == -1)
{
free(listener);
return AISL_MALLOC_ERROR;
}
if (e_id == AISL_STREAM_OUTPUT) /* subscribtion for chunked output */
{
if (source)
{
( (stream_t) source )->flags |= STREAM_FLAG_OUTPUT_CHUNKED;
}
}
else if (e_id == AISL_STREAM_OPEN)
{
instance->flags |= AISL_HANDLE_HAS_STREAM_LISTENERS;
}
return AISL_SUCCESS;
}
__attribute__ ((visibility ("default") ))
void
aisl_unset_callback_for( aisl_t instance, void * source )
{
int i=instance->callbacks->count-1;
while ( !(i < 0) )
{
listener_t listener = list_index(instance->callbacks, i);
if ( listener->source == source )
{
free(listener);
list_remove_index(instance->callbacks, i);
}
i--;
}
}
__attribute__ ((visibility ("default") ))
bool
aisl_raise( aisl_t instance,
void * source,
aisl_event_t e_id,
... )
{
va_list vl;
bool result;
va_start(vl, e_id);
result = aisl_raise_vl(instance, source, e_id, vl);
va_end(vl);
return result;
}
__attribute__ ((visibility ("default") ))
bool
aisl_raise_vl( aisl_t instance,
void * source,
aisl_event_t e_id,
va_list vl )
{
int i,
i_val;
listener_t lst;
bool res = false;
char * c_ptr,
* c_ptr2;
for(i=instance->callbacks->count-1; i>=0; i--)
{
lst = list_index(instance->callbacks, i);
/*printf("AISL> raise %s:%s, %p:%p\n", _event_text(e_id), _event_text(lst->e_id), source, lst->source);*/
if (lst->e_id == e_id && (source == lst->source || lst->source == NULL))
{
/*
if (e_id == AISL_STREAM_HEADER)
fprintf(stderr,"FOUND HANDLER %d\n", i);
*/
/*printf(" catch\n");*/
switch(e_id)
{
/* server events */
case AISL_EVENT_SERVER_OPEN:
i_val = va_arg(vl, aisl_status_t);
res = ((aisl_on_server_open_t) lst->cb)( source, i_val );
break;
case AISL_EVENT_SERVER_ERROR:
i_val = va_arg(vl, aisl_status_t);
c_ptr = va_arg(vl, char *);
res = ((aisl_on_server_error_t) lst->cb)( source, i_val, c_ptr );
break;
/* client events */
case AISL_EVENT_CLIENT_CONNECT:
res = ((aisl_on_client_connect_t) lst->cb)(source, va_arg(vl, void *));
break;
case AISL_EVENT_CLIENT_DISCONNECT:
res = ((aisl_on_client_disconnect_t) lst->cb)(source, va_arg(vl, void*));
aisl_unset_callback_for( instance, source );
break;
case AISL_EVENT_CLIENT_TIMEOUT:
res = ((aisl_client_timeout_t) lst->cb)(source, va_arg(vl, void *));
break;
/* request events */
case AISL_EVENT_STREAM_OPEN:
i_val = va_arg(vl, int);
c_ptr = va_arg(vl, char *);
c_ptr2 = va_arg(vl, char *);
res = ((aisl_on_stream_open_t) lst->cb)(source, i_val, c_ptr, c_ptr2);
break;
case AISL_EVENT_STREAM_HEADER:
c_ptr = va_arg(vl, char *);
c_ptr2 = va_arg(vl, char *);
res = ((aisl_on_stream_header_t) lst->cb)(source, c_ptr, c_ptr2);
break;
case AISL_EVENT_STREAM_INPUT:
/*printf("AISL> raise AISL_STREAM_INPUT\n");*/
c_ptr = va_arg(vl, char *);
i_val = va_arg(vl, int );
res = ((aisl_on_stream_input_t) lst->cb)(source, c_ptr, i_val);
break;
case AISL_EVENT_STREAM_REQUEST:
/*printf("AISL> raise AISL_STREAM_REQUEST\n");*/
buffer_clear( STREAM(source)->buffer, 0);
res = ((aisl_on_stream_request_t) lst->cb)(source);
break;
case AISL_EVENT_STREAM_ERROR:
res = ((aisl_on_stream_error_t) lst->cb)( source, va_arg(vl, char *));
break;
/* response events */
case AISL_EVENT_STREAM_OUTPUT:
res = ((aisl_on_stream_output_t)lst->cb)(
source,
va_arg(vl, uint32_t)
);
break;
case AISL_EVENT_STREAM_CLOSE:
res = ((aisl_on_stream_close_t)lst->cb)( source );
aisl_unset_callback_for( instance, source );
((aisl_stream_t) source)->u_ptr=NULL;
break;
default:
res = ((aisl_on_custom_event_t) lst->cb)(source, vl);
}
if (res) break;
}
}
return res;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_run_cycle( aisl_t instance )
{
int max = instance->servers->count+instance->clients->count+instance->delays->count,
cnt = 0;
switch (instance->stage)
{
case STAGE_SERVER:
while (instance->iterator < instance->servers->count )
{
aisl_server_t srv = (server_t)list_index(instance->servers, instance->iterator++);
if ( aisl_server_touch(srv) != AISL_IDLE )
return AISL_SUCCESS;
if ( ! (++cnt < max) ) return AISL_IDLE;
}
if ( ! (instance->flags & AISL_HANDLE_HAS_STREAM_LISTENERS) )
return AISL_IDLE;
instance->iterator = 0;
instance->stage++;
case STAGE_CLIENT:
while (instance->iterator < instance->clients->count )
{
int i = instance->iterator++;
aisl_client_t cli = list_index(instance->clients, i);
bool r = aisl_client_touch( cli );
if (aisl_client_is_timeout( cli ) )
aisl_raise( instance, cli->server, AISL_CLIENT_TIMEOUT, cli );
if ( cli->fd == -1 )
{
aisl_client_free( cli );
list_remove_index(instance->clients, i);
}
if (r) return AISL_SUCCESS;
if ( ! (++cnt < max) ) return AISL_IDLE;
}
instance->iterator = 0;
instance->stage = 0;
}
return AISL_IDLE;
}
__attribute__ ((visibility ("default") ))
const char *
aisl_get_error( aisl_t instance )
{
return instance->last_error;
}
void
aisl_set_error( aisl_t instance, const char * err_msg )
{
if (instance->last_error)
free(instance->last_error);
instance->last_error = str_copy(err_msg);
}
__attribute__ ((visibility ("default") ))
int
aisl_sleep( aisl_t instance, unsigned long usec )
{
int maxfd=0,
sd;
size_t i;
struct timeval timeout = {0,usec};
memset(&timeout, 0, sizeof(struct timeval));
timeout.tv_usec = usec;
fd_set fs;
FD_ZERO (&fs);
for (i=0; i<instance->servers->count; i++)
{
aisl_server_t s = list_index(instance->servers, i);
sd = aisl_server_get_socket(s);
if (sd != -1)
{
FD_SET(sd, &fs);
if (sd > maxfd) maxfd = sd;
}
}
for (i=0; i<instance->clients->count; i++)
{
aisl_client_t c = list_index(instance->clients, i);
sd = aisl_client_get_socket(s);
if (sd != -1)
{
FD_SET(sd, &fs);
if (sd > maxfd) maxfd = sd;
}
}
return select(maxfd+1, &fs, NULL, NULL, &timeout);
}

View File

@ -10,7 +10,12 @@
#ifndef INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484 #ifndef INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
#define INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484 #define INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
#include <openssl/ssl.h>
#include <aisl/instance.h> #include <aisl/instance.h>
SSL_CTX *
aisl_get_ssl_ctx( aisl_t instance, const char * server_name );
void
aisl_set_error( aisl_t instance, const char * err_msg );
#endif /* !INSTANCE_H */ #endif /* !INSTANCE_H */

View File

@ -8,11 +8,27 @@
#include "server.h" #include "server.h"
#include "handle.h" #include "instance.h"
#include "client.h" #include "client.h"
#include "globals.h" #include "globals.h"
#include "str-utils.h" #include "str-utils.h"
#ifdef __APPLE__
#include <fcntl.h>
#include <sys/ioctl.h>
#endif
struct aisl_server
{
struct sockaddr_in address;
aisl_t instance;
char * host;
int fd;
int port;
int flags;
};
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
static bool static bool

View File

@ -1,47 +1,25 @@
#ifndef _AISL_SERVER_H_ #ifndef AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
#define _AISL_SERVER_H_ #define AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
#include <aisl/status.h>
#include <aisl/handle.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <aisl/types.h>
#include <aisl/instance.h>
#include <aisl/server.h>
#ifdef __APPLE__
#include <fcntl.h> #define SERVER(x) ((aisl_server_t) x)
#include <sys/ioctl.h>
#endif
/* types -------------------------------------------------------------------- */ aisl_server_t
struct server aisl_server_new(const char * address, int port);
{
struct sockaddr_in address;
aisl_handle_t owner;
char * host;
int fd;
int port;
int flags;
};
typedef struct server * server_t;
#define SERVER(x) ((server_t) x)
/* -------------------------------------------------------------------------- */
server_t
server_new(const char * address, int port);
/* -------------------------------------------------------------------------- */
void void
server_free(server_t self); aisl_server_free(aisl_server_t self);
/* -------------------------------------------------------------------------- */
bool bool
server_touch(server_t self); aisl_server_touch(aisl_server_t self);
/* -------------------------------------------------------------------------- */
#endif #endif /* !AISL_SERVER_H */

View File

@ -1,13 +1,31 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <aisl/status.h>
#include "stream.h" #include "stream.h"
#include "globals.h" #include "globals.h"
#include "client.h" #include "client.h"
#include "handle.h" #include "handle.h"
struct stream
{
struct aisl_stream _public;
/* private data */
list_t headers; /* request headers */
buffer_t buffer;
const char *c_type;
aisl_http_response_t response;
stream_state_t state;
uint32_t c_length;
uint32_t c_offset;
int id;
int flags;
bool c_length_unknown;
};
static void static void
pair_free( pair_t self ) pair_free( pair_t self )
{ {
@ -194,3 +212,235 @@ aisl_reject(aisl_stream_t s)
} }
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
static char *
get_response_begin(stream_t stream)
{
char * r;
client_t cli = CLIENT(ASTREAM(stream)->client);
r = str_printf(
"%s %d %s\r\n"
"Server: AISL\r\n"
"Connection: %s\r\n\r\n",
aisl_http_version_to_string(cli->protocol),
stream->response,
aisl_http_response_to_string(stream->response),
((cli->flags & CLIENT_FLAG_KEEPALIVE) ? "keep-alive" : "close")
);
return r;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
const char *content_type,
uint32_t content_length)
{
char * pch;
int l;
/* check if those headers were already sent */
if (STREAM(stream)->state > STREAM_REQUEST_READY) return AISL_IDLE;
STREAM(stream)->response = status_code;
STREAM(stream)->c_type = content_type;
STREAM(stream)->c_length = content_length;
if ( !(pch = get_response_begin(STREAM(stream))) )
return AISL_MALLOC_ERROR;
l = strlen(pch);
STREAM(stream)->c_offset = l-2;
buffer_clear(STREAM(stream)->buffer, content_length);
l = buffer_add( STREAM(stream)->buffer, pch, l );
free(pch);
if (l == BUFFER_EOB) return AISL_MALLOC_ERROR;
if (content_length)
{
if (!aisl_header_printf( stream, "Content-Length", "%u", content_length ))
return AISL_MALLOC_ERROR;
}
if (content_type)
{
if (!aisl_header( stream, "Content-Type", content_type ))
return AISL_MALLOC_ERROR;
}
STREAM(stream)->state = STREAM_RESPONSE_HEADER;
return AISL_SUCCESS;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_flush(aisl_stream_t stream)
{
stream_t s = STREAM(stream);
if ( ! s->c_length )
{
s->c_length = s->buffer->size - s->c_offset - 2;
if (!aisl_header_printf(stream, "Content-Length", "%u", s->c_length))
return AISL_MALLOC_ERROR;
}
/*
fprintf(stdout, "(%lu bytes)------->\n", STREAM(stream)->buffer->size);
fwrite(STREAM(stream)->buffer->data, 1, STREAM(stream)->buffer->size, stdout);
fprintf(stdout, "<------\n");
*/
s->state = STREAM_RESPONSE_READY;
s->flags |= STREAM_FLAG_OUTPUT_READY;
return AISL_SUCCESS;
}
__attribute__ ((visibility ("default") ))
int
aisl_header(aisl_stream_t stream, const char *key, const char *value)
{
int ret;
char * pch;
if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL )
{
ret = strlen(pch);
if ( buffer_insert(
STREAM(stream)->buffer,
STREAM(stream)->c_offset,
pch,
ret
) == BUFFER_EOB )
{
ret = -1;
}
else
STREAM(stream)->c_offset += ret;
free(pch);
}
else
ret = -1;
return ret;
}
__attribute__ ((visibility ("default") ))
int
aisl_header_printf(aisl_stream_t stream, const char *key,
const char *f_value, ...)
{
int ret;
va_list arg;
va_start(arg, f_value);
ret = aisl_header_vprintf(stream, key, f_value, arg);
va_end(arg);
return ret;
}
__attribute__ ((visibility ("default") ))
int
aisl_header_vprintf(aisl_stream_t stream, const char *key,
const char *format,
va_list args)
{
int ret;
char * value;
if ( (value = str_vprintf(format, args)) != NULL )
{
ret = aisl_header( stream, key, value );
free(value);
}
else
ret = -1;
return ret;
}
__attribute__ ((visibility ("default") ))
int
aisl_printf(aisl_stream_t stream, const char *format, ...)
{
va_list arg;
va_start(arg, format);
int result = aisl_vprintf(stream, format, arg);
va_end(arg);
/* No need to update length there, because vprintf do that
*
* if (STREAM(stream)->c_length_unknown)
STREAM(stream)->c_length += result;
*/
return result;
}
__attribute__ ((visibility ("default") ))
int
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
{
int result;
char * r;
if ( (r = str_vprintf(format, args)) != NULL)
{
result = strlen(r);
if (buffer_add(STREAM(stream)->buffer, r, result) == BUFFER_EOB)
result = -1;
free(r);
}
else
result = -1;
return result;
}
__attribute__ ((visibility ("default") ))
int
aisl_write(aisl_stream_t stream, const char *data, int d_len)
{
if (d_len < 0)
d_len = strlen(data);
if (buffer_add(STREAM(stream)->buffer, data, d_len) == BUFFER_EOB)
d_len = -1;
return d_len;
}
__attribute__ ((visibility ("default") ))
int
aisl_puts(const char *str, aisl_stream_t stream)
{
return aisl_write( stream, str, strlen(str));
}

View File

@ -1,5 +1,5 @@
#ifndef _AISL_STREAM_H__ #ifndef AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
#define _AISL_STREAM_H__ #define AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
#include <stdbool.h> #include <stdbool.h>
#include <aisl/stream.h> #include <aisl/stream.h>
@ -43,51 +43,32 @@ typedef enum {
STREAM_RESPONSE_CONTENT, STREAM_RESPONSE_CONTENT,
STREAM_RESPONSE_READY STREAM_RESPONSE_READY
} stream_state_t; } aisl_stream_state_t;
/* real wrapper for aisl_stream_t */ /* real wrapper for aisl_stream_t */
struct stream
{
struct aisl_stream _public;
/* private data */
list_t headers; /* request headers */
buffer_t buffer;
const char *c_type; typedef struct aisl_stream * aisl_stream_t;
aisl_http_response_t response;
stream_state_t state;
uint32_t c_length;
uint32_t c_offset;
int id;
int flags;
bool c_length_unknown;
};
typedef struct stream * stream_t;
#define STREAM(x) ((stream_t) x) #define STREAM(x) ((stream_t) x)
#define ASTREAM(x) ((aisl_stream_t) x) #define ASTREAM(x) ((aisl_stream_t) x)
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
stream_t aisl_stream_t
stream_new(struct sockaddr_in *client, int id, stream_state_t state); aisl_stream_new(struct sockaddr_in *client, int id, stream_state_t state);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
void void
stream_free(stream_t self); aisl_stream_free(aisl_stream_t self);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
stream_t aisl_stream_t
stream_reset(stream_t self); aisl_stream_reset(aisl_stream_t self);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
#endif #endif /* !AISL_STREAM_H */