Switch to new coding style
This commit is contained in:
parent
ee90cbc37c
commit
12be39c747
|
@ -24,14 +24,14 @@
|
|||
|
||||
|
||||
static void
|
||||
hello_world(aisl_evt_t const evt, void * p_ctx)
|
||||
hello_world(const struct aisl_evt *evt, void *p_ctx)
|
||||
{
|
||||
if (evt->code != AISL_EVENT_STREAM_REQUEST)
|
||||
return;
|
||||
|
||||
aisl_status_t status;
|
||||
AislStatus status;
|
||||
|
||||
aisl_stream_t s = evt->source;
|
||||
AislStream s = evt->source;
|
||||
|
||||
const char html[] =
|
||||
"<html>"
|
||||
|
@ -44,11 +44,11 @@ hello_world(aisl_evt_t const evt, void * p_ctx)
|
|||
"</body>"
|
||||
"</html>";
|
||||
|
||||
status = aisl_response(s, AISL_HTTP_OK, sizeof(html)-1);
|
||||
status = aisl_response(s, AISL_HTTP_OK, sizeof (html)-1);
|
||||
|
||||
if (status == AISL_SUCCESS)
|
||||
{
|
||||
if (aisl_write(s, html, sizeof(html)-1) != -1)
|
||||
if (aisl_write(s, html, sizeof (html)-1) != -1)
|
||||
{
|
||||
aisl_flush(s);
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ hello_world(aisl_evt_t const evt, void * p_ctx)
|
|||
int
|
||||
main(int argc, char ** argv)
|
||||
{
|
||||
aisl_t aisl; /**< AISL instance pointer */
|
||||
aisl_status_t status; /**< AISL status code */
|
||||
AislInstance aisl; /**< AISL instance pointer */
|
||||
AislStatus status; /**< AISL status code */
|
||||
struct aisl_cfg cfg = AISL_CFG_DEFAULT;
|
||||
struct aisl_cfg_srv srv = {
|
||||
.host = "0.0.0.0",
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
/*
|
||||
* <aisl/aisl.h>
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
* Project homepage: https://lowenware.com/aisl/
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file aisl/aisl.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Meta header file of AISL
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
||||
#ifndef AISL_H_17EF1616_A00F_49C9_92B6_273AB13BF279
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file aisl/client.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of #AislCLient functions
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
*
|
||||
* Project homepage: https://lowenware.com/aisl/
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
||||
#ifndef AISL_CLIENT_H_A6C37DCF_2183_4F22_A5A0_668311757A08
|
||||
|
@ -14,50 +20,50 @@
|
|||
|
||||
|
||||
/**
|
||||
* @brief Gets #aisl_server_t instance associated with client.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @return an associated #aisl_server_t pointer.
|
||||
* @brief Gets #AislServer instance associated with client.
|
||||
* @param client an #AislClient instance pointer.
|
||||
* @return an associated #AislServer pointer.
|
||||
*/
|
||||
aisl_server_t
|
||||
aisl_client_get_server(aisl_client_t client);
|
||||
AislServer
|
||||
aisl_client_get_server(AislClient client);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets security connection status.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @param client an #AislClient instance pointer.
|
||||
* @return true if SSL is enabled and false if disabled.
|
||||
*/
|
||||
bool
|
||||
aisl_client_is_secure(aisl_client_t client);
|
||||
aisl_client_is_secure(AislClient client);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets client's connection state.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @param client an #AislClient instance pointer.
|
||||
* @return true if client is online and false if is offline.
|
||||
*/
|
||||
bool
|
||||
aisl_client_is_online(aisl_client_t client);
|
||||
aisl_client_is_online(AislClient client);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Forcefully closes client's connection.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @param client an #AislClient instance pointer.
|
||||
*/
|
||||
void
|
||||
aisl_client_disconnect(aisl_client_t client);
|
||||
aisl_client_disconnect(AislClient client);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets HTTP protocol version.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @param client an #AislClient instance pointer.
|
||||
* @return HTTP protocol version
|
||||
*/
|
||||
aisl_http_version_t
|
||||
aisl_client_get_http_version(aisl_client_t client);
|
||||
AislHttpVersion
|
||||
aisl_client_get_http_version(AislClient client);
|
||||
|
||||
|
||||
void
|
||||
aisl_client_get_address( aisl_client_t client, struct sockaddr_in * address);
|
||||
aisl_client_get_address(AislClient client, struct sockaddr_in *address);
|
||||
|
||||
#endif /* !AISL_CLIENT_H */
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
/*
|
||||
* <aisl/config.h>
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
* Project homepage: https://lowenware.com/aisl/
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file aisl/config.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of AISL configuration structures
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
||||
#ifndef AISL_CONFIG_H_DB67A89B_5CAF_4A5F_AEB1_6DB9F84827D6
|
||||
|
@ -12,59 +18,49 @@
|
|||
|
||||
#include <aisl/types.h>
|
||||
|
||||
#define AISL_CFG_DEFAULT \
|
||||
{ \
|
||||
.callback = NULL \
|
||||
, .p_ctx = NULL \
|
||||
, .srv = NULL \
|
||||
, .ssl = NULL \
|
||||
, .srv_cnt = 0 \
|
||||
, .ssl_cnt = 0 \
|
||||
, .client_spool_size = 32 \
|
||||
, .initial_buffer_size = 16536 \
|
||||
, .client_accept_limit = 1024 \
|
||||
, .client_silence_timeout = 30 \
|
||||
#define AISL_CFG_DEFAULT { \
|
||||
.callback = NULL \
|
||||
, .p_ctx = NULL \
|
||||
, .srv = NULL \
|
||||
, .ssl = NULL \
|
||||
, .srv_cnt = 0 \
|
||||
, .ssl_cnt = 0 \
|
||||
, .client_spool_size = 32 \
|
||||
, .initial_buffer_size = 16536 \
|
||||
, .client_accept_limit = 1024 \
|
||||
, .client_silence_timeout = 30 \
|
||||
} \
|
||||
|
||||
|
||||
struct aisl_cfg_srv
|
||||
{
|
||||
const char * host;
|
||||
uint16_t port;
|
||||
bool secure;
|
||||
struct aisl_cfg_srv {
|
||||
const char * host;
|
||||
uint16_t port;
|
||||
bool secure;
|
||||
};
|
||||
|
||||
typedef struct aisl_cfg_srv * aisl_cfg_srv_t;
|
||||
|
||||
|
||||
struct aisl_cfg_ssl
|
||||
{
|
||||
const char * host;
|
||||
const char * key_file;
|
||||
const char * crt_file;
|
||||
struct aisl_cfg_ssl {
|
||||
const char * host;
|
||||
const char * key_file;
|
||||
const char * crt_file;
|
||||
};
|
||||
|
||||
typedef struct aisl_cfg_ssl * aisl_cfg_ssl_t;
|
||||
|
||||
|
||||
struct aisl_cfg
|
||||
{
|
||||
/* event handlers */
|
||||
aisl_callback_t callback;
|
||||
void * p_ctx;
|
||||
/* event handlers */
|
||||
AislCallback callback;
|
||||
void *p_ctx;
|
||||
|
||||
aisl_cfg_srv_t srv;
|
||||
aisl_cfg_ssl_t ssl;
|
||||
struct aisl_cfg_srv *srv;
|
||||
struct aisl_cfg_ssl *ssl;
|
||||
|
||||
int srv_cnt;
|
||||
int ssl_cnt;
|
||||
int srv_cnt;
|
||||
int ssl_cnt;
|
||||
|
||||
int client_spool_size;
|
||||
int initial_buffer_size;
|
||||
int client_accept_limit;
|
||||
int client_silence_timeout;
|
||||
int client_spool_size;
|
||||
int initial_buffer_size;
|
||||
int client_accept_limit;
|
||||
int client_silence_timeout;
|
||||
};
|
||||
|
||||
typedef struct aisl_cfg * aisl_cfg_t;
|
||||
|
||||
#endif /* !AISL_CONFIG_H */
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file aisl/instance.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of #AislInstance functions
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
*
|
||||
* Project homepage: https://lowenware.com/aisl/
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
|
||||
*/
|
||||
|
||||
#ifndef AISL_INSTANCE_H_60576F41_454C_4189_B91A_F40501132230
|
||||
|
@ -21,39 +28,39 @@
|
|||
* @brief Allocates new AISL instance.
|
||||
*
|
||||
* @param cfg a pointer to #aisl_cfg_t structure.
|
||||
* @return an #aisl_t instance pointer.
|
||||
* @return an #AislInstance instance pointer.
|
||||
*/
|
||||
aisl_t
|
||||
aisl_new( aisl_cfg_t cfg );
|
||||
AislInstance
|
||||
aisl_new(const struct aisl_cfg *cfg);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Frees previously allocated pointer of AISL instance.
|
||||
* @param instance a pointer to #aisl_t instance.
|
||||
* @param instance a pointer to #AislInstance instance.
|
||||
*/
|
||||
void
|
||||
aisl_free( aisl_t instance );
|
||||
aisl_free(AislInstance instance);
|
||||
|
||||
|
||||
/**
|
||||
* @brief A core function doing all the library routines.
|
||||
* Designed to be called inside application main loop
|
||||
* @param instance a pointer to #aisl_t instance.
|
||||
* @return #aisl_status_t code.
|
||||
* @param instance a pointer to #AislInstance instance.
|
||||
* @return #AislStatus code.
|
||||
*/
|
||||
aisl_status_t
|
||||
aisl_run_cycle( aisl_t instance );
|
||||
AislStatus
|
||||
aisl_run_cycle(AislInstance instance);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function to sleep CPU if nothing to do.
|
||||
* Calls select on all the opened sockets inside.
|
||||
* @param instance a pointer to #aisl_t instance.
|
||||
* @param instance a pointer to #AislInstance instance.
|
||||
* @param usec a number of miliseconds to wait for any data on sockets.
|
||||
* @return #aisl_status_t code.
|
||||
* @return #AislStatus code.
|
||||
*/
|
||||
aisl_status_t
|
||||
aisl_sleep( aisl_t instance, uint32_t usec );
|
||||
AislStatus
|
||||
aisl_sleep(AislInstance instance, uint32_t usec);
|
||||
|
||||
|
||||
#endif /* !AISL_INSTANCE_H */
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file aisl/server.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of #AislServer functions
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
*
|
||||
* Project homepage: https://lowenware.com/aisl/
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
||||
#ifndef AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768
|
||||
|
@ -15,28 +21,28 @@
|
|||
|
||||
/**
|
||||
* @brief Function to get appropriate AISL instance pointer from server pointer.
|
||||
* @param server an #aisl_server_t pointer.
|
||||
* @return an #aisl_t instance pointer.
|
||||
* @param server an #AislServer pointer.
|
||||
* @return an #AislInstance instance pointer.
|
||||
*/
|
||||
aisl_t
|
||||
aisl_server_get_instance( aisl_server_t server );
|
||||
AislInstance
|
||||
aisl_server_get_instance(AislServer server);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Copies server listen address information to sockaddr_in structure.
|
||||
* @param server an #aisl_server_t pointer.
|
||||
* @param server an #AislServer pointer.
|
||||
* @param address a pointer to sockaddr_in structure.
|
||||
*/
|
||||
void
|
||||
aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address);
|
||||
aisl_server_get_address(AislServer server, struct sockaddr_in *address);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function to get on and off status of SSL for the #aisl_server_t.
|
||||
* @param server an #aisl_server_t pointer.
|
||||
* @brief Function to get on and off status of SSL for the #AislServer.
|
||||
* @param server an #AislServer pointer.
|
||||
* @return a boolean value representing SSL enabled/disabled state.
|
||||
*/
|
||||
bool
|
||||
aisl_server_get_ssl( aisl_server_t server );
|
||||
aisl_server_get_ssl(AislServer server);
|
||||
|
||||
#endif /* !AISL_SERVER_H */
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
/*
|
||||
* <aisl/stream.h>
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
* Project homepage: https://lowenware.com/aisl/
|
||||
*
|
||||
*/
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file aisl/stream.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of #AislStream functions
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
#ifndef AISL_STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC
|
||||
#define AISL_STREAM_H_4D8EB622_3CE0_4F1B_AC1F_B27CCB5C2EDC
|
||||
|
||||
|
@ -15,96 +20,87 @@
|
|||
#include <aisl/types.h>
|
||||
|
||||
|
||||
|
||||
/* Stream helpers */
|
||||
|
||||
bool
|
||||
aisl_is_secure( aisl_stream_t stream );
|
||||
aisl_is_secure(AislStream stream);
|
||||
|
||||
|
||||
aisl_client_t
|
||||
aisl_get_client( aisl_stream_t stream );
|
||||
AislClient
|
||||
aisl_get_client(AislStream stream);
|
||||
|
||||
|
||||
aisl_server_t
|
||||
aisl_get_server( aisl_stream_t stream );
|
||||
AislServer
|
||||
aisl_get_server(AislStream stream);
|
||||
|
||||
|
||||
aisl_http_version_t
|
||||
aisl_get_http_version( aisl_stream_t stream );
|
||||
AislHttpVersion
|
||||
aisl_get_http_version(AislStream stream);
|
||||
|
||||
|
||||
aisl_t
|
||||
aisl_stream_get_instance( aisl_stream_t s );
|
||||
AislInstance
|
||||
aisl_stream_get_instance(AislStream s);
|
||||
|
||||
|
||||
/* Context functions */
|
||||
|
||||
void *
|
||||
aisl_get_context( aisl_stream_t stream );
|
||||
aisl_get_context(AislStream stream);
|
||||
|
||||
|
||||
void
|
||||
aisl_set_context( aisl_stream_t stream, void * context );
|
||||
aisl_set_context(AislStream stream, void *context);
|
||||
|
||||
|
||||
/* Stream control functions */
|
||||
|
||||
aisl_status_t
|
||||
aisl_flush( aisl_stream_t stream );
|
||||
AislStatus
|
||||
aisl_flush(AislStream stream);
|
||||
|
||||
|
||||
void
|
||||
aisl_reject( aisl_stream_t stream );
|
||||
aisl_reject(AislStream stream);
|
||||
|
||||
|
||||
/* Response functions */
|
||||
|
||||
aisl_status_t
|
||||
aisl_response( aisl_stream_t stream,
|
||||
aisl_http_response_t status_code,
|
||||
uint64_t content_length );
|
||||
AislStatus
|
||||
aisl_response(AislStream stream,
|
||||
AislHttpResponse status_code,
|
||||
uint64_t content_length);
|
||||
|
||||
|
||||
int
|
||||
aisl_header( aisl_stream_t stream, const char *key, const char *value );
|
||||
aisl_header(AislStream stream, const char *key, const char *value );
|
||||
|
||||
|
||||
int
|
||||
aisl_header_printf( aisl_stream_t stream,
|
||||
const char * key,
|
||||
const char * format,
|
||||
... );
|
||||
aisl_header_printf(AislStream stream,
|
||||
const char *key,
|
||||
const char *format,
|
||||
... );
|
||||
|
||||
|
||||
int
|
||||
aisl_header_vprintf( aisl_stream_t stream,
|
||||
const char * key,
|
||||
const char * format,
|
||||
va_list args );
|
||||
aisl_header_vprintf(AislStream stream,
|
||||
const char *key,
|
||||
const char *format,
|
||||
va_list args );
|
||||
|
||||
|
||||
int
|
||||
aisl_printf( aisl_stream_t stream, const char * format, ... );
|
||||
aisl_printf(AislStream stream, const char *format, ...);
|
||||
|
||||
|
||||
int
|
||||
aisl_vprintf( aisl_stream_t stream, const char * format, va_list args );
|
||||
aisl_vprintf(AislStream stream, const char *format, va_list args);
|
||||
|
||||
|
||||
int
|
||||
aisl_write( aisl_stream_t stream, const char * data, int d_len );
|
||||
aisl_write(AislStream stream, const char *data, int d_len);
|
||||
|
||||
|
||||
int
|
||||
aisl_puts( const char * str_data, aisl_stream_t stream );
|
||||
aisl_puts(const char *str_data, AislStream stream);
|
||||
|
||||
|
||||
void
|
||||
aisl_set_output_event(aisl_stream_t stream, bool value);
|
||||
aisl_set_output_event(AislStream stream, bool value);
|
||||
|
||||
|
||||
bool
|
||||
aisl_get_output_event(aisl_stream_t stream);
|
||||
aisl_get_output_event(AislStream stream);
|
||||
|
||||
#endif /* !AISL_STREAM_H */
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
/*
|
||||
* <aisl/types.h>
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
* Project homepage: https://lowenware.com/aisl/
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file aisl/types.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of AISL types
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
||||
#ifndef AISL_TYPES_H_86A9DBA7_C0E6_4CF4_8A64_DAAD4A81031B
|
||||
|
@ -20,206 +26,182 @@
|
|||
|
||||
#define AISL_AUTO_LENGTH (~0)
|
||||
|
||||
/* type casts */
|
||||
#define AISL_CALLBACK(x) ((aisl_callback_t) x)
|
||||
/** type casts */
|
||||
#define AISL_CALLBACK(x) ((AislCallback) x)
|
||||
|
||||
|
||||
/* AISL Instance */
|
||||
typedef struct aisl * aisl_t;
|
||||
/** AISL Instance */
|
||||
typedef struct aisl_instance * AislInstance;
|
||||
|
||||
/* HTTP(s) Server */
|
||||
typedef struct aisl_server * aisl_server_t;
|
||||
/** HTTP(s) Server */
|
||||
typedef struct aisl_server * AislServer;
|
||||
|
||||
/* HTTP(s) Client */
|
||||
typedef struct aisl_client * aisl_client_t;
|
||||
/** HTTP(s) Client */
|
||||
typedef struct aisl_client * AislClient;
|
||||
|
||||
/* Server<->Client Stream */
|
||||
typedef struct aisl_stream * aisl_stream_t;
|
||||
/** Server<->Client Stream */
|
||||
typedef struct aisl_stream * AislStream;
|
||||
|
||||
|
||||
/* status return codes */
|
||||
typedef enum
|
||||
{
|
||||
AISL_INPUT_ERROR = -4
|
||||
, AISL_EXTCALL_ERROR = -3
|
||||
, AISL_SYSCALL_ERROR = -2
|
||||
, AISL_MALLOC_ERROR = -1
|
||||
/** status return codes */
|
||||
typedef enum {
|
||||
AISL_INPUT_ERROR = -4
|
||||
, AISL_EXTCALL_ERROR = -3
|
||||
, AISL_SYSCALL_ERROR = -2
|
||||
, AISL_MALLOC_ERROR = -1
|
||||
|
||||
, AISL_SUCCESS = 0
|
||||
, AISL_IDLE = 1
|
||||
|
||||
} aisl_status_t;
|
||||
, AISL_SUCCESS = 0
|
||||
, AISL_IDLE = 1
|
||||
} AislStatus;
|
||||
|
||||
#ifndef WITHOUT_STRINGIFIERS
|
||||
|
||||
const char *
|
||||
aisl_status_to_string(aisl_status_t status);
|
||||
aisl_status_to_string(AislStatus status);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Generic HTTP Enumerations */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AISL_HTTP_0_9 = 0x0009
|
||||
, AISL_HTTP_1_0 = 0x0100
|
||||
, AISL_HTTP_1_1 = 0x0101
|
||||
, AISL_HTTP_2_0 = 0x0200
|
||||
|
||||
} aisl_http_version_t;
|
||||
/** Generic HTTP Enumerations */
|
||||
typedef enum {
|
||||
AISL_HTTP_0_9 = 0x0009
|
||||
, AISL_HTTP_1_0 = 0x0100
|
||||
, AISL_HTTP_1_1 = 0x0101
|
||||
, AISL_HTTP_2_0 = 0x0200
|
||||
} AislHttpVersion;
|
||||
|
||||
|
||||
const char *
|
||||
aisl_http_version_to_string( aisl_http_version_t version );
|
||||
aisl_http_version_to_string(AislHttpVersion version);
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AISL_HTTP_METHOD_UNKNOWN
|
||||
, 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_METHOD_UNKNOWN
|
||||
, 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
|
||||
} AislHttpMethod;
|
||||
|
||||
|
||||
const char *
|
||||
aisl_http_method_to_string( aisl_http_method_t method );
|
||||
aisl_http_method_to_string( AislHttpMethod method );
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AISL_HTTP_CONTINUE = 100
|
||||
, AISL_HTTP_SWITCHING_PROTOCOLS
|
||||
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_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_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_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;
|
||||
, 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
|
||||
} AislHttpResponse;
|
||||
|
||||
|
||||
const char *
|
||||
aisl_http_response_to_string( aisl_http_response_t code );
|
||||
aisl_http_response_to_string( AislHttpResponse code );
|
||||
|
||||
|
||||
/* Events */
|
||||
/** Codes of AISL events */
|
||||
typedef enum {
|
||||
AISL_EVENT_SERVER_READY = 100
|
||||
, AISL_EVENT_SERVER_ERROR = 190
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AISL_EVENT_SERVER_OPEN = 100
|
||||
, AISL_EVENT_SERVER_ERROR = 190
|
||||
, AISL_EVENT_CLIENT_CONNECT = 200
|
||||
, AISL_EVENT_CLIENT_DISCONNECT = 210
|
||||
|
||||
, AISL_EVENT_CLIENT_CONNECT = 200
|
||||
, AISL_EVENT_CLIENT_DISCONNECT = 210
|
||||
|
||||
, 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_evt_code_t;
|
||||
, 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
|
||||
} AislEvent;
|
||||
|
||||
|
||||
struct aisl_evt
|
||||
{
|
||||
void * source;
|
||||
aisl_evt_code_t code;
|
||||
aisl_status_t status;
|
||||
struct aisl_evt {
|
||||
void *source;
|
||||
AislEvent code;
|
||||
AislStatus status;
|
||||
};
|
||||
|
||||
typedef struct aisl_evt * aisl_evt_t;
|
||||
|
||||
|
||||
/* void type event callback */
|
||||
typedef void
|
||||
(* aisl_callback_t) (aisl_evt_t const evt, void * p_ctx);
|
||||
(* AislCallback) (const struct aisl_evt *evt, void *ctx);
|
||||
|
||||
|
||||
struct aisl_evt_stream_open
|
||||
{
|
||||
struct aisl_evt evt;
|
||||
const char * path;
|
||||
const char * query;
|
||||
aisl_http_method_t http_method;
|
||||
struct aisl_evt_open {
|
||||
struct aisl_evt evt;
|
||||
const char *path;
|
||||
const char *query;
|
||||
AislHttpMethod http_method;
|
||||
};
|
||||
|
||||
typedef struct aisl_evt_stream_open * aisl_evt_stream_open_t;
|
||||
|
||||
|
||||
struct aisl_evt_stream_header
|
||||
{
|
||||
struct aisl_evt evt;
|
||||
const char * key;
|
||||
const char * value;
|
||||
struct aisl_evt_header {
|
||||
struct aisl_evt evt;
|
||||
const char *key;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
typedef struct aisl_evt_stream_header * aisl_evt_stream_header_t;
|
||||
|
||||
|
||||
struct aisl_evt_stream_input
|
||||
{
|
||||
struct aisl_evt evt;
|
||||
const char * data;
|
||||
int32_t size;
|
||||
struct aisl_evt_input {
|
||||
struct aisl_evt evt;
|
||||
const char *data;
|
||||
int32_t size;
|
||||
};
|
||||
|
||||
typedef struct aisl_evt_stream_input * aisl_evt_stream_input_t;
|
||||
|
||||
#ifndef WITHOUT_STRINGIFIERS
|
||||
|
||||
const char *
|
||||
aisl_evt_code_to_string( aisl_evt_code_t evt_code );
|
||||
aisl_event_to_string(AislEvent evt);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,539 @@
|
|||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#include <aisl/aisl.h>
|
||||
#include "debug.h"
|
||||
#include "stream.h"
|
||||
#include "http.h"
|
||||
#include "server.h"
|
||||
#include "instance.h"
|
||||
#include "client.h"
|
||||
|
||||
#define FLAG_KEEPALIVE (1<<0)
|
||||
#define FLAG_HANDSHAKE (1<<1)
|
||||
#define FLAG_CAN_READ (1<<2)
|
||||
#define FLAG_CAN_WRITE (1<<3)
|
||||
|
||||
#define BUFFER_SIZE (16*1024)
|
||||
|
||||
|
||||
static void
|
||||
aisl_client_close(AislClient client, AislStatus status)
|
||||
{
|
||||
if (client->fd != -1)
|
||||
{
|
||||
aisl_raise(
|
||||
client->server->instance
|
||||
, (void *)client
|
||||
, AISL_EVENT_CLIENT_DISCONNECT
|
||||
, status
|
||||
);
|
||||
|
||||
close(client->fd);
|
||||
shutdown(client->fd, SHUT_RDWR);
|
||||
client->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static AislStatus
|
||||
aisl_client_parse(AislClient client, char * data, int32_t size)
|
||||
{
|
||||
AislStatus result = AISL_SUCCESS;
|
||||
AislStream s = client->stream;
|
||||
ParserStatus p = HTTP_PARSER_SUCCESS;
|
||||
|
||||
|
||||
int32_t bytes_left = size;
|
||||
|
||||
switch (client->http_version)
|
||||
{
|
||||
case AISL_HTTP_0_9:
|
||||
case AISL_HTTP_1_0:
|
||||
case AISL_HTTP_1_1:
|
||||
|
||||
/* s = client->stream; */
|
||||
|
||||
while ( p == HTTP_PARSER_SUCCESS )
|
||||
{
|
||||
|
||||
switch ( aisl_stream_get_state(s) )
|
||||
{
|
||||
case AISL_STREAM_STATE_IDLE:
|
||||
p = http_10_parse_request(data, &size, client->stream);
|
||||
break;
|
||||
|
||||
case AISL_STREAM_STATE_WAIT_HEADER:
|
||||
p = http_10_parse_header(data, &size, client->stream);
|
||||
break;
|
||||
|
||||
case AISL_STREAM_STATE_WAIT_BODY:
|
||||
p = http_10_parse_body(data, &size, client->stream);
|
||||
break;
|
||||
|
||||
default: /* has input data, but request was already parsed */
|
||||
p = HTTP_PARSER_ERROR;
|
||||
continue;
|
||||
}
|
||||
// size now has number of parsed bytes
|
||||
data += size;
|
||||
bytes_left -= size;
|
||||
size = bytes_left;
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case AISL_HTTP_2_0:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
switch(p)
|
||||
{
|
||||
case HTTP_PARSER_READY:
|
||||
client->flags &= ~FLAG_CAN_READ;
|
||||
client->flags |= FLAG_CAN_WRITE;
|
||||
|
||||
aisl_raise(
|
||||
client->server->instance
|
||||
, (void *) s
|
||||
, AISL_EVENT_STREAM_REQUEST
|
||||
, result
|
||||
);
|
||||
break;
|
||||
|
||||
case HTTP_PARSER_ERROR:
|
||||
/* reply Bad Request here */
|
||||
client->stream->http_response = AISL_HTTP_BAD_REQUEST;
|
||||
|
||||
aisl_raise(
|
||||
client->server->instance
|
||||
, (void *) s
|
||||
, AISL_EVENT_STREAM_ERROR
|
||||
, result
|
||||
);
|
||||
|
||||
aisl_client_close(client, result);
|
||||
|
||||
return result;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (size)
|
||||
buffer_shift(&client->in, client->in.used - size); /* reset buffer */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* In HTTP 2.0 client->stream will be NULL if stream related data was completely
|
||||
* parsed. If it is not NULL, then stream expects additional data -> same like
|
||||
* in mono stream HTTP 1.0
|
||||
*/
|
||||
static AislStatus
|
||||
aisl_client_input(AislClient client)
|
||||
{
|
||||
int l;
|
||||
|
||||
char * data = &client->in.data[ client->in.used ];
|
||||
int32_t size = client->in.size - client->in.used;
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
{
|
||||
DPRINTF("SSL_read");
|
||||
if ( !(client->flags & FLAG_HANDSHAKE) )
|
||||
{
|
||||
if ( (l = SSL_accept(client->ssl)) != 1 )
|
||||
{
|
||||
l = SSL_get_error(client->ssl, l);
|
||||
|
||||
if (l == SSL_ERROR_WANT_READ || l == SSL_ERROR_WANT_WRITE)
|
||||
return AISL_IDLE;
|
||||
|
||||
DPRINTF("SSL handshake fail: %s\n", ERR_error_string(l, NULL) );
|
||||
|
||||
aisl_client_close(client, AISL_EXTCALL_ERROR);
|
||||
return AISL_EXTCALL_ERROR;
|
||||
}
|
||||
|
||||
client->flags &= ~FLAG_HANDSHAKE;
|
||||
}
|
||||
|
||||
l = SSL_read(client->ssl, data, size) ;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
l = recv( client->fd, data, size, 0);
|
||||
|
||||
if (l > 0)
|
||||
{
|
||||
DPRINTF("%d bytes received from client", l);
|
||||
|
||||
data = client->in.data;
|
||||
size = client->in.used + l;
|
||||
|
||||
client->in.used = size;
|
||||
|
||||
return aisl_client_parse(client, data, size);
|
||||
}
|
||||
else if (l<0)
|
||||
{
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
{
|
||||
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
|
||||
return AISL_IDLE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if(errno == EWOULDBLOCK)
|
||||
return AISL_IDLE;
|
||||
|
||||
DPRINTF("client - %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* both: client disconnect + on read error */
|
||||
/* todo: raise client error here */
|
||||
aisl_client_close(client, AISL_SYSCALL_ERROR);
|
||||
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static AislStatus
|
||||
aisl_client_output(AislClient client)
|
||||
{
|
||||
int l;
|
||||
char * data;
|
||||
|
||||
AislStream s = client->stream;
|
||||
|
||||
/* while stream is not flushed, we should raise event */
|
||||
if( aisl_get_output_event(s) )
|
||||
{
|
||||
/* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
|
||||
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
|
||||
* buffer->size will be used to carry amount of stored bytes
|
||||
* */
|
||||
l = aisl_stream_get_buffer_space(s);
|
||||
|
||||
/*
|
||||
if (bsz < OUTPUT_BUFFER_SIZE)
|
||||
{
|
||||
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
|
||||
return false;
|
||||
|
||||
s->buffer->size = bsz;
|
||||
bsz = OUTPUT_BUFFER_SIZE;
|
||||
}
|
||||
*/
|
||||
|
||||
if ( !(l < aisl_stream_get_buffer_size(s) / 2) )
|
||||
{
|
||||
aisl_raise(
|
||||
client->server->instance
|
||||
, (void*)s
|
||||
, AISL_EVENT_STREAM_OUTPUT
|
||||
, AISL_SUCCESS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
data = aisl_stream_get_data(s, &l);
|
||||
|
||||
if ( !l )
|
||||
return AISL_IDLE;
|
||||
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
l = send( client->fd, data, l, 0);
|
||||
#else
|
||||
l = (client->ssl) ?
|
||||
SSL_write(client->ssl, data, l) :
|
||||
send( client->fd, data, l, 0);
|
||||
#endif
|
||||
|
||||
if (l > 0)
|
||||
{
|
||||
aisl_stream_shift(s, l);
|
||||
|
||||
/*
|
||||
if (s->state == STREAM_RESPONSE_READY && / * flushed * /
|
||||
s->buffer->size == 0) / * all sent * /
|
||||
*/
|
||||
if ( aisl_stream_is_done(s) )
|
||||
{
|
||||
/* buffer_clear(s->buffer, 0); */
|
||||
|
||||
/* data has been sent */
|
||||
|
||||
if (client->flags & FLAG_KEEPALIVE)
|
||||
{
|
||||
aisl_stream_free(s);
|
||||
|
||||
client->stream = aisl_stream_new(client, client->next_id++);
|
||||
if (client->stream != NULL )
|
||||
return AISL_SUCCESS;
|
||||
|
||||
/* in case of malloc error it will not be error as long as request was
|
||||
* handled and we just close the connection.
|
||||
*/
|
||||
}
|
||||
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
}
|
||||
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
/* l < 0 */
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
{
|
||||
if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE )
|
||||
return AISL_IDLE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (errno == EWOULDBLOCK)
|
||||
return AISL_IDLE;
|
||||
}
|
||||
|
||||
aisl_client_close(client, AISL_SYSCALL_ERROR);
|
||||
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
AislClient
|
||||
aisl_client_new( AislServer server,
|
||||
int fd,
|
||||
struct sockaddr_in * addr )
|
||||
{
|
||||
AislClient client;
|
||||
AislStream stream;
|
||||
|
||||
if ( (client = calloc(1, sizeof (struct aisl_client))) != NULL )
|
||||
{
|
||||
DPRINTF("client alocated");
|
||||
memcpy(&client->address, addr, sizeof (struct sockaddr_in));
|
||||
client->server = server;
|
||||
client->fd = fd;
|
||||
client->next_id = 2;
|
||||
client->http_version = AISL_HTTP_1_0;
|
||||
client->timestamp = time(NULL);
|
||||
client->flags = FLAG_KEEPALIVE | FLAG_HANDSHAKE | FLAG_CAN_READ;
|
||||
|
||||
if (buffer_init(&client->in, 2*BUFFER_SIZE) != -1)
|
||||
{
|
||||
DPRINTF("client buffer alocated");
|
||||
memcpy(&client->out, &client->in, sizeof (struct buffer));
|
||||
|
||||
stream = aisl_stream_new(client, 0);
|
||||
|
||||
if (stream != NULL)
|
||||
{
|
||||
client->stream = stream;
|
||||
|
||||
DPRINTF("client stream alocated");
|
||||
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
|
||||
return client;
|
||||
|
||||
#else
|
||||
|
||||
SSL_CTX * ssl_ctx;
|
||||
|
||||
if ( !server->ssl )
|
||||
return client;
|
||||
|
||||
ssl_ctx = aisl_get_ssl_ctx(server->instance, NULL);
|
||||
|
||||
if ((client->ssl = SSL_new(ssl_ctx)) != NULL )
|
||||
{
|
||||
SSL_set_fd(client->ssl, fd);
|
||||
return client;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
aisl_client_free(client);
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_client_free(AislClient client)
|
||||
{
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
SSL_free(client->ssl);
|
||||
#endif
|
||||
|
||||
if (client->in.data)
|
||||
free(client->in.data);
|
||||
|
||||
/* out buffer is a shared part of input buffer, so no need to free it */
|
||||
|
||||
if (client->stream)
|
||||
aisl_stream_free(client->stream);
|
||||
|
||||
free(client);
|
||||
}
|
||||
|
||||
|
||||
AislStatus
|
||||
AislClientouch(AislClient client, int32_t timeout)
|
||||
{
|
||||
AislStatus result = AISL_IDLE,
|
||||
status = AISL_IDLE;
|
||||
|
||||
/* input */
|
||||
if (client->flags & FLAG_CAN_READ)
|
||||
{
|
||||
if ( (result = aisl_client_input(client)) < 0 )
|
||||
return result;
|
||||
}
|
||||
|
||||
/* output */
|
||||
if (client->flags & FLAG_CAN_WRITE)
|
||||
{
|
||||
if ( (status = aisl_client_output(client)) < 0 )
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if ((client->http_version==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
|
||||
(client_input(client)) ) result = true;
|
||||
*/
|
||||
/* output */
|
||||
/*
|
||||
s = list_index(client->streams, client->ostream);
|
||||
|
||||
if ( s->flags & (STREAM_FLAG_OUTPUT_READY | STREAM_FLAG_OUTPUT_CHUNKED) )
|
||||
result = client_output(client);
|
||||
*/
|
||||
/* update timestamp */
|
||||
|
||||
if (result == AISL_IDLE)
|
||||
result = status;
|
||||
|
||||
if (result == AISL_SUCCESS)
|
||||
client->timestamp = time(NULL);
|
||||
else
|
||||
{
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
if ( !(now - client->timestamp < timeout) )
|
||||
{
|
||||
aisl_client_close(client, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
aisl_client_get_socket(AislClient client)
|
||||
{
|
||||
return client->fd;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
aisl_client_get_keepalive(AislClient client)
|
||||
{
|
||||
return (client->flags & FLAG_KEEPALIVE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_client_set_keepalive(AislClient client, bool value)
|
||||
{
|
||||
if (value)
|
||||
client->flags |= FLAG_KEEPALIVE;
|
||||
else
|
||||
client->flags &= ~FLAG_KEEPALIVE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* API Level ---------------------------------------------------------------- */
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
AislServer
|
||||
aisl_client_get_server(AislClient client)
|
||||
{
|
||||
return client->server;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
bool
|
||||
aisl_client_is_secure(AislClient client)
|
||||
{
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
return false;
|
||||
#else
|
||||
return (client->ssl == NULL) ? false : true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
bool
|
||||
aisl_client_is_online(AislClient client)
|
||||
{
|
||||
return (client->fd == -1) ? false : true;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_client_disconnect(AislClient client)
|
||||
{
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
AislHttpVersion
|
||||
aisl_client_get_http_version(AislClient client)
|
||||
{
|
||||
return client->http_version;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_client_get_address( AislClient client, struct sockaddr_in * address)
|
||||
{
|
||||
memcpy(address, &client->address, sizeof (struct sockaddr_in));
|
||||
}
|
202
src/buffer.c
202
src/buffer.c
|
@ -19,169 +19,157 @@
|
|||
|
||||
|
||||
static int32_t
|
||||
buffer_set_size(buffer_t buffer, int32_t new_size)
|
||||
buffer_set_size(struct buffer *buffer, int32_t new_size)
|
||||
{
|
||||
if ( new_size != buffer->size )
|
||||
{
|
||||
if (new_size)
|
||||
{
|
||||
int32_t s = new_size / 1024;
|
||||
if (new_size != buffer->size) {
|
||||
char *data;
|
||||
|
||||
if ( new_size % 1024 )
|
||||
{
|
||||
new_size = (s+1) * 1024;
|
||||
}
|
||||
}
|
||||
else
|
||||
new_size = 16*1024;
|
||||
if (new_size) {
|
||||
int32_t s = new_size / 1024;
|
||||
|
||||
char * data = realloc(buffer->data, new_size);
|
||||
if ( new_size % 1024 ) {
|
||||
new_size = (s+1) * 1024;
|
||||
}
|
||||
} else {
|
||||
new_size = 16*1024;
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
buffer->data = data;
|
||||
buffer->size = new_size;
|
||||
}
|
||||
else
|
||||
new_size = -1;
|
||||
}
|
||||
if ((data = realloc(buffer->data, new_size)) != NULL) {
|
||||
buffer->data = data;
|
||||
buffer->size = new_size;
|
||||
} else {
|
||||
new_size = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return new_size;
|
||||
return new_size;
|
||||
}
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_init( buffer_t buffer, int32_t size )
|
||||
buffer_init(struct buffer *buffer, int32_t size)
|
||||
{
|
||||
if ( (size = buffer_set_size(buffer, size)) != -1)
|
||||
buffer->used = 0;
|
||||
if ( (size = buffer_set_size(buffer, size)) != -1)
|
||||
buffer->used = 0;
|
||||
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
buffer_release( buffer_t buffer )
|
||||
buffer_release(struct buffer *buffer)
|
||||
{
|
||||
if (buffer->data)
|
||||
{
|
||||
free(buffer->data);
|
||||
buffer->data = NULL;
|
||||
}
|
||||
if (buffer->data) {
|
||||
free(buffer->data);
|
||||
buffer->data = NULL;
|
||||
}
|
||||
|
||||
buffer->used = 0;
|
||||
buffer->size = 0;
|
||||
buffer->used = 0;
|
||||
buffer->size = 0;
|
||||
}
|
||||
|
||||
|
||||
static int32_t
|
||||
buffer_move_offset( buffer_t buffer, int32_t offset, int32_t size )
|
||||
buffer_move_offset(struct buffer *buffer, int32_t offset, int32_t size)
|
||||
{
|
||||
int32_t to_move = buffer->used - offset;
|
||||
int32_t to_move = buffer->used - offset;
|
||||
|
||||
if (to_move < 0)
|
||||
return -1;
|
||||
else if (to_move)
|
||||
memmove(&buffer->data[offset+size], &buffer->data[offset], to_move);
|
||||
if (to_move < 0) {
|
||||
return -1;
|
||||
} else if (to_move) {
|
||||
memmove(&buffer->data[offset+size], &buffer->data[offset], to_move);
|
||||
}
|
||||
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
int32_t
|
||||
buffer_insert( buffer_t buffer
|
||||
, int32_t offset
|
||||
, const char * data
|
||||
, int32_t size )
|
||||
buffer_insert(struct buffer *buffer,
|
||||
int32_t offset,
|
||||
const char *data,
|
||||
int32_t size)
|
||||
{
|
||||
int32_t result;
|
||||
int32_t result;
|
||||
|
||||
if ( (result = buffer_set_size(buffer, size)) != -1)
|
||||
{
|
||||
if ((result = buffer_move_offset(buffer, offset, size)) != -1)
|
||||
{
|
||||
memcpy(&buffer->data[offset], data, size);
|
||||
buffer->used += result;
|
||||
}
|
||||
}
|
||||
if ( (result = buffer_set_size(buffer, size)) != -1) {
|
||||
if ((result = buffer_move_offset(buffer, offset, size)) != -1) {
|
||||
memcpy(&buffer->data[offset], data, size);
|
||||
buffer->used += result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_append_printf( buffer_t buffer, const char * format, ... )
|
||||
buffer_append_printf(struct buffer *buffer, const char *format, ...)
|
||||
{
|
||||
int32_t result;
|
||||
va_list args;
|
||||
int32_t result;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
result = buffer_append_vprintf( buffer, format, args);
|
||||
va_end(args);
|
||||
va_start(args, format);
|
||||
result = buffer_append_vprintf(buffer, format, args);
|
||||
va_end(args);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t
|
||||
buffer_append_vprintf( buffer_t buffer, const char * format, va_list args )
|
||||
buffer_append_vprintf(struct buffer *buffer, const char *format, va_list args)
|
||||
{
|
||||
int32_t space = buffer->size - buffer->used,
|
||||
result;
|
||||
int32_t space, result;
|
||||
va_list cp_args;
|
||||
|
||||
va_list cp_args;
|
||||
va_copy(cp_args, args);
|
||||
va_copy(cp_args, args);
|
||||
space = buffer->size - buffer->used,
|
||||
result = vsnprintf(&buffer->data[buffer->used], space, format, args);
|
||||
|
||||
result = vsnprintf( &buffer->data[buffer->used], space, format, args );
|
||||
if (result < space) { /* enough space */
|
||||
buffer->used += result;
|
||||
} else {
|
||||
result = buffer_set_size(buffer, buffer->size + result - space);
|
||||
if (result != -1)
|
||||
result = buffer_append_vprintf(buffer, format, cp_args);
|
||||
}
|
||||
va_end(cp_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;
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t
|
||||
buffer_append( buffer_t buffer, const char * data, int32_t size )
|
||||
buffer_append(struct buffer *buffer, const char *data, int32_t size)
|
||||
{
|
||||
int32_t used = buffer->used,
|
||||
space = buffer->size - used;
|
||||
int32_t used, space;
|
||||
|
||||
if ( size > space ) /* enough space */
|
||||
{
|
||||
if ( buffer_set_size(buffer, buffer->size + size - space) == -1)
|
||||
return -1;
|
||||
}
|
||||
used = buffer->used,
|
||||
space = buffer->size - used;
|
||||
|
||||
memcpy(&buffer->data[used], data, size);
|
||||
buffer->used += size;
|
||||
if (size > space) { /* enough space */
|
||||
if (buffer_set_size(buffer, buffer->size + size - space) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return size;
|
||||
memcpy(&buffer->data[used], data, size);
|
||||
buffer->used += size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_shift( buffer_t buffer, int32_t offset )
|
||||
buffer_shift(struct buffer *buffer, int32_t offset)
|
||||
{
|
||||
int32_t used = buffer->used - 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;
|
||||
if (offset > 0) {
|
||||
if (offset < used) {
|
||||
memmove(buffer->data, &buffer->data[offset], used);
|
||||
} else {
|
||||
used = 0;
|
||||
}
|
||||
buffer->used = used;
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
|
|
29
src/buffer.h
29
src/buffer.h
|
@ -6,9 +6,9 @@
|
|||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file buffer.h
|
||||
* @file src/buffer.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Buffer module header file
|
||||
* @brief Declarations of struct buffer and functions
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
@ -20,42 +20,39 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
|
||||
struct buffer
|
||||
{
|
||||
char * data;
|
||||
int32_t size;
|
||||
int32_t used;
|
||||
struct buffer {
|
||||
char *data;
|
||||
int32_t size;
|
||||
int32_t used;
|
||||
};
|
||||
|
||||
typedef struct buffer * buffer_t;
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_init( buffer_t buffer, int32_t size );
|
||||
buffer_init(struct buffer *bs, int32_t size);
|
||||
|
||||
|
||||
void
|
||||
buffer_release( buffer_t buffer );
|
||||
buffer_release(struct buffer *bs );
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_insert(buffer_t buffer, int32_t offset, const char * data, int32_t size);
|
||||
buffer_insert(struct buffer *bs, int32_t offset, const char *data, int32_t size);
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_append_printf( buffer_t buffer, const char * format, ... );
|
||||
buffer_append_printf(struct buffer *bs, const char *format, ...);
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_append_vprintf( buffer_t buffer, const char * format, va_list args );
|
||||
buffer_append_vprintf(struct buffer *bs, const char *format, va_list args);
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_append( buffer_t buffer, const char * data, int32_t size );
|
||||
buffer_append(struct buffer *bs, const char *data, int32_t size);
|
||||
|
||||
|
||||
int32_t
|
||||
buffer_shift( buffer_t buffer, int32_t size );
|
||||
buffer_shift(struct buffer *bs, int32_t size);
|
||||
|
||||
|
||||
|
||||
|
|
651
src/client.c
651
src/client.c
|
@ -27,115 +27,87 @@
|
|||
|
||||
|
||||
static void
|
||||
aisl_client_close(aisl_client_t client, aisl_status_t status)
|
||||
aisl_client_close(AislClient client, AislStatus status)
|
||||
{
|
||||
if (client->fd != -1)
|
||||
{
|
||||
aisl_raise(
|
||||
client->server->instance
|
||||
, (void *)client
|
||||
, AISL_EVENT_CLIENT_DISCONNECT
|
||||
, status
|
||||
);
|
||||
if (client->fd != -1) {
|
||||
aisl_raise(client->server->instance, (void *)client,
|
||||
AISL_EVENT_CLIENT_DISCONNECT, status );
|
||||
|
||||
close(client->fd);
|
||||
shutdown(client->fd, SHUT_RDWR);
|
||||
client->fd = -1;
|
||||
}
|
||||
close(client->fd);
|
||||
shutdown(client->fd, SHUT_RDWR);
|
||||
client->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static aisl_status_t
|
||||
aisl_client_parse(aisl_client_t client, char * data, int32_t size)
|
||||
static AislStatus
|
||||
aisl_client_parse(AislClient client, char *data, int32_t size)
|
||||
{
|
||||
aisl_status_t result = AISL_SUCCESS;
|
||||
aisl_stream_t s = client->stream;
|
||||
http_parser_t p = HTTP_PARSER_SUCCESS;
|
||||
AislStatus result = AISL_SUCCESS;
|
||||
AislStream s = client->stream;
|
||||
ParserStatus p = HTTP_PARSER_SUCCESS;
|
||||
|
||||
int32_t bytes_left = size;
|
||||
|
||||
int32_t bytes_left = size;
|
||||
switch (client->http_version) {
|
||||
case AISL_HTTP_0_9:
|
||||
case AISL_HTTP_1_0:
|
||||
case AISL_HTTP_1_1:
|
||||
while (p == HTTP_PARSER_SUCCESS) {
|
||||
switch (aisl_stream_get_state(s)) {
|
||||
case AISL_STREAM_STATE_IDLE:
|
||||
p = http_10_parse_request(data, &size, client->stream);
|
||||
break;
|
||||
|
||||
switch (client->http_version)
|
||||
{
|
||||
case AISL_HTTP_0_9:
|
||||
case AISL_HTTP_1_0:
|
||||
case AISL_HTTP_1_1:
|
||||
case AISL_STREAM_STATE_WAIT_HEADER:
|
||||
p = http_10_parse_header(data, &size, client->stream);
|
||||
break;
|
||||
|
||||
/* s = client->stream; */
|
||||
case AISL_STREAM_STATE_WAIT_BODY:
|
||||
p = http_10_parse_body(data, &size, client->stream);
|
||||
break;
|
||||
|
||||
while ( p == HTTP_PARSER_SUCCESS )
|
||||
{
|
||||
default: /* has input data, but request was already parsed */
|
||||
p = HTTP_PARSER_ERROR;
|
||||
continue;
|
||||
}
|
||||
// size now has number of parsed bytes
|
||||
data += size;
|
||||
bytes_left -= size;
|
||||
size = bytes_left;
|
||||
}
|
||||
break;
|
||||
|
||||
switch ( aisl_stream_get_state(s) )
|
||||
{
|
||||
case AISL_STREAM_STATE_IDLE:
|
||||
p = http_10_parse_request(data, &size, client->stream);
|
||||
break;
|
||||
case AISL_HTTP_2_0:
|
||||
break;
|
||||
}
|
||||
|
||||
case AISL_STREAM_STATE_WAIT_HEADER:
|
||||
p = http_10_parse_header(data, &size, client->stream);
|
||||
break;
|
||||
switch(p) {
|
||||
case HTTP_PARSER_READY:
|
||||
client->flags &= ~FLAG_CAN_READ;
|
||||
client->flags |= FLAG_CAN_WRITE;
|
||||
|
||||
case AISL_STREAM_STATE_WAIT_BODY:
|
||||
p = http_10_parse_body(data, &size, client->stream);
|
||||
break;
|
||||
aisl_raise(client->server->instance, (void *)s, AISL_EVENT_STREAM_REQUEST,
|
||||
result);
|
||||
break;
|
||||
|
||||
default: /* has input data, but request was already parsed */
|
||||
p = HTTP_PARSER_ERROR;
|
||||
continue;
|
||||
}
|
||||
// size now has number of parsed bytes
|
||||
data += size;
|
||||
bytes_left -= size;
|
||||
size = bytes_left;
|
||||
}
|
||||
case HTTP_PARSER_ERROR:
|
||||
/* reply Bad Request here */
|
||||
client->stream->http_response = AISL_HTTP_BAD_REQUEST;
|
||||
aisl_raise(client->server->instance, (void *)s, AISL_EVENT_STREAM_ERROR,
|
||||
result);
|
||||
|
||||
aisl_client_close(client, result);
|
||||
return result;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
if (size)
|
||||
buffer_shift(&client->in, client->in.used - size); /* reset buffer */
|
||||
|
||||
case AISL_HTTP_2_0:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
switch(p)
|
||||
{
|
||||
case HTTP_PARSER_READY:
|
||||
client->flags &= ~FLAG_CAN_READ;
|
||||
client->flags |= FLAG_CAN_WRITE;
|
||||
|
||||
aisl_raise(
|
||||
client->server->instance
|
||||
, (void *) s
|
||||
, AISL_EVENT_STREAM_REQUEST
|
||||
, result
|
||||
);
|
||||
break;
|
||||
|
||||
case HTTP_PARSER_ERROR:
|
||||
/* reply Bad Request here */
|
||||
client->stream->http_response = AISL_HTTP_BAD_REQUEST;
|
||||
|
||||
aisl_raise(
|
||||
client->server->instance
|
||||
, (void *) s
|
||||
, AISL_EVENT_STREAM_ERROR
|
||||
, result
|
||||
);
|
||||
|
||||
aisl_client_close(client, result);
|
||||
|
||||
return result;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (size)
|
||||
buffer_shift(&client->in, client->in.used - size); /* reset buffer */
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -143,344 +115,279 @@ aisl_client_parse(aisl_client_t client, char * data, int32_t size)
|
|||
* parsed. If it is not NULL, then stream expects additional data -> same like
|
||||
* in mono stream HTTP 1.0
|
||||
*/
|
||||
static aisl_status_t
|
||||
aisl_client_input(aisl_client_t client)
|
||||
static AislStatus
|
||||
aisl_client_input(AislClient client)
|
||||
{
|
||||
int l;
|
||||
int l;
|
||||
char *data = &client->in.data[ client->in.used ];
|
||||
int32_t size = client->in.size - client->in.used;
|
||||
|
||||
char * data = &client->in.data[ client->in.used ];
|
||||
int32_t size = client->in.size - client->in.used;
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl) {
|
||||
DPRINTF("SSL_read");
|
||||
if (!(client->flags & FLAG_HANDSHAKE)) {
|
||||
if ( (l = SSL_accept(client->ssl)) != 1 ) {
|
||||
l = SSL_get_error(client->ssl, l);
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
{
|
||||
DPRINTF("SSL_read");
|
||||
if ( !(client->flags & FLAG_HANDSHAKE) )
|
||||
{
|
||||
if ( (l = SSL_accept(client->ssl)) != 1 )
|
||||
{
|
||||
l = SSL_get_error(client->ssl, l);
|
||||
if (l == SSL_ERROR_WANT_READ || l == SSL_ERROR_WANT_WRITE)
|
||||
return AISL_IDLE;
|
||||
|
||||
if (l == SSL_ERROR_WANT_READ || l == SSL_ERROR_WANT_WRITE)
|
||||
return AISL_IDLE;
|
||||
DPRINTF("SSL handshake fail: %s\n", ERR_error_string(l, NULL) );
|
||||
|
||||
DPRINTF("SSL handshake fail: %s\n", ERR_error_string(l, NULL) );
|
||||
aisl_client_close(client, AISL_EXTCALL_ERROR);
|
||||
return AISL_EXTCALL_ERROR;
|
||||
}
|
||||
client->flags &= ~FLAG_HANDSHAKE;
|
||||
}
|
||||
l = SSL_read(client->ssl, data, size);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
l = recv( client->fd, data, size, 0);
|
||||
}
|
||||
|
||||
aisl_client_close(client, AISL_EXTCALL_ERROR);
|
||||
return AISL_EXTCALL_ERROR;
|
||||
}
|
||||
if (l > 0) {
|
||||
DPRINTF("%d bytes received from client", l);
|
||||
|
||||
client->flags &= ~FLAG_HANDSHAKE;
|
||||
}
|
||||
data = client->in.data;
|
||||
size = client->in.used + l;
|
||||
client->in.used = size;
|
||||
return aisl_client_parse(client, data, size);
|
||||
} else if (l<0) {
|
||||
|
||||
l = SSL_read(client->ssl, data, size) ;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
l = recv( client->fd, data, size, 0);
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl) {
|
||||
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
|
||||
return AISL_IDLE;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
||||
if (l > 0)
|
||||
{
|
||||
DPRINTF("%d bytes received from client", l);
|
||||
if(errno == EWOULDBLOCK)
|
||||
return AISL_IDLE;
|
||||
DPRINTF("client - %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
data = client->in.data;
|
||||
size = client->in.used + l;
|
||||
/* both: client disconnect + on read error */
|
||||
/* todo: raise client error here */
|
||||
aisl_client_close(client, AISL_SYSCALL_ERROR);
|
||||
|
||||
client->in.used = size;
|
||||
|
||||
return aisl_client_parse(client, data, size);
|
||||
}
|
||||
else if (l<0)
|
||||
{
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
{
|
||||
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
|
||||
return AISL_IDLE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if(errno == EWOULDBLOCK)
|
||||
return AISL_IDLE;
|
||||
|
||||
DPRINTF("client - %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* both: client disconnect + on read error */
|
||||
/* todo: raise client error here */
|
||||
aisl_client_close(client, AISL_SYSCALL_ERROR);
|
||||
|
||||
return AISL_SYSCALL_ERROR;
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static aisl_status_t
|
||||
aisl_client_output(aisl_client_t client)
|
||||
static AislStatus
|
||||
aisl_client_output(AislClient client)
|
||||
{
|
||||
int l;
|
||||
char * data;
|
||||
int l;
|
||||
char *data;
|
||||
|
||||
aisl_stream_t s = client->stream;
|
||||
AislStream s = client->stream;
|
||||
|
||||
/* while stream is not flushed, we should raise event */
|
||||
if( aisl_get_output_event(s) )
|
||||
{
|
||||
/* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
|
||||
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
|
||||
* buffer->size will be used to carry amount of stored bytes
|
||||
* */
|
||||
l = aisl_stream_get_buffer_space(s);
|
||||
/* while stream is not flushed, we should raise event */
|
||||
if(aisl_get_output_event(s)) {
|
||||
/* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
|
||||
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
|
||||
* buffer->size will be used to carry amount of stored bytes
|
||||
* */
|
||||
l = aisl_stream_get_buffer_space(s);
|
||||
|
||||
/*
|
||||
if (bsz < OUTPUT_BUFFER_SIZE)
|
||||
{
|
||||
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
|
||||
return false;
|
||||
/*
|
||||
if (bsz < OUTPUT_BUFFER_SIZE)
|
||||
{
|
||||
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
|
||||
return false;
|
||||
|
||||
s->buffer->size = bsz;
|
||||
bsz = OUTPUT_BUFFER_SIZE;
|
||||
}
|
||||
*/
|
||||
s->buffer->size = bsz;
|
||||
bsz = OUTPUT_BUFFER_SIZE;
|
||||
}
|
||||
*/
|
||||
|
||||
if ( !(l < aisl_stream_get_buffer_size(s) / 2) )
|
||||
{
|
||||
aisl_raise(
|
||||
client->server->instance
|
||||
, (void*)s
|
||||
, AISL_EVENT_STREAM_OUTPUT
|
||||
, AISL_SUCCESS
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!(l < aisl_stream_get_buffer_size(s) / 2)) {
|
||||
aisl_raise(client->server->instance, (void*)s, AISL_EVENT_STREAM_OUTPUT,
|
||||
AISL_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
data = aisl_stream_get_data(s, &l);
|
||||
data = aisl_stream_get_data(s, &l);
|
||||
|
||||
if ( !l )
|
||||
return AISL_IDLE;
|
||||
if ( !l )
|
||||
return AISL_IDLE;
|
||||
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
l = send( client->fd, data, l, 0);
|
||||
#else
|
||||
l = (client->ssl) ?
|
||||
SSL_write(client->ssl, data, l) :
|
||||
send( client->fd, data, l, 0);
|
||||
#endif
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
l = send( client->fd, data, l, 0);
|
||||
#else
|
||||
l = (client->ssl) ?
|
||||
SSL_write(client->ssl, data, l) :
|
||||
send( client->fd, data, l, 0);
|
||||
#endif
|
||||
|
||||
if (l > 0)
|
||||
{
|
||||
aisl_stream_shift(s, l);
|
||||
if (l > 0) {
|
||||
aisl_stream_shift(s, l);
|
||||
if ( aisl_stream_is_done(s) ) {
|
||||
/* data has been sent */
|
||||
if (client->flags & FLAG_KEEPALIVE) {
|
||||
aisl_stream_free(s);
|
||||
|
||||
/*
|
||||
if (s->state == STREAM_RESPONSE_READY && / * flushed * /
|
||||
s->buffer->size == 0) / * all sent * /
|
||||
*/
|
||||
if ( aisl_stream_is_done(s) )
|
||||
{
|
||||
/* buffer_clear(s->buffer, 0); */
|
||||
client->stream = aisl_stream_new(client, client->next_id++);
|
||||
if (client->stream != NULL )
|
||||
return AISL_SUCCESS;
|
||||
|
||||
/* data has been sent */
|
||||
/* in case of malloc error it will not be error as long as request was
|
||||
* handled and we just close the connection.
|
||||
*/
|
||||
}
|
||||
|
||||
if (client->flags & FLAG_KEEPALIVE)
|
||||
{
|
||||
aisl_stream_free(s);
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
}
|
||||
|
||||
client->stream = aisl_stream_new(client, client->next_id++);
|
||||
if (client->stream != NULL )
|
||||
return AISL_SUCCESS;
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
/* in case of malloc error it will not be error as long as request was
|
||||
* handled and we just close the connection.
|
||||
*/
|
||||
}
|
||||
/* l < 0 */
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl) {
|
||||
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE)
|
||||
return AISL_IDLE;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (errno == EWOULDBLOCK)
|
||||
return AISL_IDLE;
|
||||
}
|
||||
aisl_client_close(client, AISL_SYSCALL_ERROR);
|
||||
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
}
|
||||
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
/* l < 0 */
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
{
|
||||
if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE )
|
||||
return AISL_IDLE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (errno == EWOULDBLOCK)
|
||||
return AISL_IDLE;
|
||||
}
|
||||
|
||||
aisl_client_close(client, AISL_SYSCALL_ERROR);
|
||||
|
||||
return AISL_SYSCALL_ERROR;
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
aisl_client_t
|
||||
aisl_client_new( aisl_server_t server,
|
||||
int fd,
|
||||
struct sockaddr_in * addr )
|
||||
AislClient
|
||||
aisl_client_new(AislServer server, int fd, struct sockaddr_in *addr)
|
||||
{
|
||||
aisl_client_t client;
|
||||
aisl_stream_t stream;
|
||||
AislClient client;
|
||||
AislStream stream;
|
||||
|
||||
if ( (client = calloc(1, sizeof(struct aisl_client))) != NULL )
|
||||
{
|
||||
DPRINTF("client alocated");
|
||||
memcpy(&client->address, addr, sizeof(struct sockaddr_in));
|
||||
client->server = server;
|
||||
client->fd = fd;
|
||||
client->next_id = 2;
|
||||
client->http_version = AISL_HTTP_1_0;
|
||||
client->timestamp = time(NULL);
|
||||
client->flags = FLAG_KEEPALIVE | FLAG_HANDSHAKE | FLAG_CAN_READ;
|
||||
if ((client = calloc(1, sizeof (struct aisl_client))) != NULL) {
|
||||
DPRINTF("client alocated");
|
||||
memcpy(&client->address, addr, sizeof (struct sockaddr_in));
|
||||
client->server = server;
|
||||
client->fd = fd;
|
||||
client->next_id = 2;
|
||||
client->http_version = AISL_HTTP_1_0;
|
||||
client->timestamp = time(NULL);
|
||||
client->flags = FLAG_KEEPALIVE | FLAG_HANDSHAKE | FLAG_CAN_READ;
|
||||
|
||||
if (buffer_init(&client->in, 2*BUFFER_SIZE) != -1)
|
||||
{
|
||||
DPRINTF("client buffer alocated");
|
||||
memcpy(&client->out, &client->in, sizeof(struct buffer));
|
||||
if (buffer_init(&client->in, 2*BUFFER_SIZE) != -1) {
|
||||
DPRINTF("client buffer alocated");
|
||||
memcpy(&client->out, &client->in, sizeof (struct buffer));
|
||||
|
||||
stream = aisl_stream_new(client, 0);
|
||||
stream = aisl_stream_new(client, 0);
|
||||
|
||||
if (stream != NULL)
|
||||
{
|
||||
client->stream = stream;
|
||||
if (stream != NULL) {
|
||||
client->stream = stream;
|
||||
DPRINTF("client stream alocated");
|
||||
|
||||
DPRINTF("client stream alocated");
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (server->ssl) {
|
||||
SSL_CTX * ssl_ctx = aisl_get_ssl_ctx(server->instance, NULL);
|
||||
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
|
||||
return client;
|
||||
|
||||
#else
|
||||
|
||||
SSL_CTX * ssl_ctx;
|
||||
|
||||
if ( !server->ssl )
|
||||
return client;
|
||||
|
||||
ssl_ctx = aisl_get_ssl_ctx(server->instance, NULL);
|
||||
|
||||
if ((client->ssl = SSL_new(ssl_ctx)) != NULL )
|
||||
{
|
||||
SSL_set_fd(client->ssl, fd);
|
||||
return client;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
aisl_client_free(client);
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
if ((client->ssl = SSL_new(ssl_ctx)) != NULL ) {
|
||||
SSL_set_fd(client->ssl, fd);
|
||||
return client;
|
||||
}
|
||||
} else {
|
||||
return client;
|
||||
}
|
||||
#else
|
||||
return client;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
aisl_client_free(client);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_client_free(aisl_client_t client)
|
||||
aisl_client_free(AislClient client)
|
||||
{
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
SSL_free(client->ssl);
|
||||
#endif
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
SSL_free(client->ssl);
|
||||
#endif
|
||||
|
||||
if (client->in.data)
|
||||
free(client->in.data);
|
||||
if (client->in.data)
|
||||
free(client->in.data);
|
||||
|
||||
/* out buffer is a shared part of input buffer, so no need to free it */
|
||||
if (client->stream)
|
||||
aisl_stream_free(client->stream);
|
||||
|
||||
if (client->stream)
|
||||
aisl_stream_free(client->stream);
|
||||
|
||||
free(client);
|
||||
free(client);
|
||||
}
|
||||
|
||||
|
||||
aisl_status_t
|
||||
aisl_client_touch(aisl_client_t client, int32_t timeout)
|
||||
AislStatus
|
||||
aisl_client_touch(AislClient client, int32_t timeout)
|
||||
{
|
||||
aisl_status_t result = AISL_IDLE,
|
||||
status = AISL_IDLE;
|
||||
AislStatus result, status;
|
||||
|
||||
/* input */
|
||||
if (client->flags & FLAG_CAN_READ)
|
||||
{
|
||||
if ( (result = aisl_client_input(client)) < 0 )
|
||||
return result;
|
||||
}
|
||||
result = AISL_IDLE;
|
||||
status = AISL_IDLE;
|
||||
|
||||
/* output */
|
||||
if (client->flags & FLAG_CAN_WRITE)
|
||||
{
|
||||
if ( (status = aisl_client_output(client)) < 0 )
|
||||
return status;
|
||||
}
|
||||
/* input */
|
||||
if (client->flags & FLAG_CAN_READ) {
|
||||
if ( (result = aisl_client_input(client)) < 0 )
|
||||
return result;
|
||||
}
|
||||
|
||||
/* output */
|
||||
if (client->flags & FLAG_CAN_WRITE) {
|
||||
if ( (status = aisl_client_output(client)) < 0 )
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
if ((client->http_version==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
|
||||
(client_input(client)) ) result = true;
|
||||
*/
|
||||
/* output */
|
||||
/*
|
||||
s = list_index(client->streams, client->ostream);
|
||||
if (result == AISL_IDLE)
|
||||
result = status;
|
||||
|
||||
if ( s->flags & (STREAM_FLAG_OUTPUT_READY | STREAM_FLAG_OUTPUT_CHUNKED) )
|
||||
result = client_output(client);
|
||||
*/
|
||||
/* update timestamp */
|
||||
if (result != AISL_SUCCESS) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
if (result == AISL_IDLE)
|
||||
result = status;
|
||||
|
||||
if (result == AISL_SUCCESS)
|
||||
client->timestamp = time(NULL);
|
||||
else
|
||||
{
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
if ( !(now - client->timestamp < timeout) )
|
||||
{
|
||||
aisl_client_close(client, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
if (!(now - client->timestamp < timeout)) {
|
||||
aisl_client_close(client, result);
|
||||
}
|
||||
} else {
|
||||
client->timestamp = time(NULL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
aisl_client_get_socket(aisl_client_t client)
|
||||
aisl_client_get_socket(AislClient client)
|
||||
{
|
||||
return client->fd;
|
||||
return client->fd;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
aisl_client_get_keepalive(aisl_client_t client)
|
||||
aisl_client_get_keepalive(AislClient client)
|
||||
{
|
||||
return (client->flags & FLAG_KEEPALIVE);
|
||||
return (client->flags & FLAG_KEEPALIVE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_client_set_keepalive(aisl_client_t client, bool value)
|
||||
aisl_client_set_keepalive(AislClient client, bool value)
|
||||
{
|
||||
if (value)
|
||||
client->flags |= FLAG_KEEPALIVE;
|
||||
else
|
||||
client->flags &= ~FLAG_KEEPALIVE;
|
||||
if (value)
|
||||
client->flags |= FLAG_KEEPALIVE;
|
||||
else
|
||||
client->flags &= ~FLAG_KEEPALIVE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -488,52 +395,52 @@ aisl_client_set_keepalive(aisl_client_t client, bool value)
|
|||
/* API Level ---------------------------------------------------------------- */
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_server_t
|
||||
aisl_client_get_server(aisl_client_t client)
|
||||
AislServer
|
||||
aisl_client_get_server(AislClient client)
|
||||
{
|
||||
return client->server;
|
||||
return client->server;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
bool
|
||||
aisl_client_is_secure(aisl_client_t client)
|
||||
aisl_client_is_secure(AislClient client)
|
||||
{
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
return false;
|
||||
#else
|
||||
return (client->ssl == NULL) ? false : true;
|
||||
#endif
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
return false;
|
||||
#else
|
||||
return (client->ssl == NULL) ? false : true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
bool
|
||||
aisl_client_is_online(aisl_client_t client)
|
||||
aisl_client_is_online(AislClient client)
|
||||
{
|
||||
return (client->fd == -1) ? false : true;
|
||||
return (client->fd == -1) ? false : true;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_client_disconnect(aisl_client_t client)
|
||||
aisl_client_disconnect(AislClient client)
|
||||
{
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
aisl_client_close(client, AISL_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_http_version_t
|
||||
aisl_client_get_http_version(aisl_client_t client)
|
||||
AislHttpVersion
|
||||
aisl_client_get_http_version(AislClient client)
|
||||
{
|
||||
return client->http_version;
|
||||
return client->http_version;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_client_get_address( aisl_client_t client, struct sockaddr_in * address)
|
||||
aisl_client_get_address(AislClient client, struct sockaddr_in *address)
|
||||
{
|
||||
memcpy(address, &client->address, sizeof(struct sockaddr_in));
|
||||
memcpy(address, &client->address, sizeof (struct sockaddr_in));
|
||||
}
|
||||
|
|
87
src/client.h
87
src/client.h
|
@ -1,3 +1,17 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file client.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of aisl_client structure and functions
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
#ifndef AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
|
||||
#define AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
|
||||
|
||||
|
@ -6,86 +20,83 @@
|
|||
#include <aisl/client.h>
|
||||
#include "buffer.h"
|
||||
|
||||
#define AISL_CLIENT(x) ((aisl_client_t) x)
|
||||
#define AISL_CLIENT(x) ((AislClient) x)
|
||||
|
||||
|
||||
struct aisl_client
|
||||
{
|
||||
struct sockaddr_in address; /**< Client's address structure. */
|
||||
aisl_server_t server; /**< Server instance. */
|
||||
struct buffer in; /**< Client's input buffer. */
|
||||
struct buffer out; /**< Client's output buffer. */
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
SSL * ssl; /**< SSL pointer for HTTPS. */
|
||||
#endif
|
||||
time_t timestamp; /**< Last communication timestamp. */
|
||||
|
||||
aisl_stream_t stream; /**< Pending client's stream. */
|
||||
int next_id; /**< Stream id generator (even). */
|
||||
int flags; /**< Client's flag bitmask. */
|
||||
int fd; /**< Client's socket descriptor. */
|
||||
|
||||
aisl_http_version_t http_version; /**< Client's http_version version. */
|
||||
struct aisl_client {
|
||||
struct sockaddr_in address; /**< Client's address structure. */
|
||||
struct buffer in; /**< Client's input buffer. */
|
||||
struct buffer out; /**< Client's output buffer. */
|
||||
AislServer server; /**< Server instance. */
|
||||
AislStream stream; /**< Pending client's stream. */
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
SSL *ssl; /**< SSL pointer for HTTPS. */
|
||||
#endif
|
||||
time_t timestamp; /**< Last communication timestamp. */
|
||||
int next_id; /**< Stream id generator (even). */
|
||||
int flags; /**< Client's flag bitmask. */
|
||||
int fd; /**< Client's socket descriptor. */
|
||||
AislHttpVersion http_version; /**< Client's http_version version. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor for #aisl_client_t instance.
|
||||
* @param server an #aisl_server_t instance pointer.
|
||||
* @brief Constructor for #AislClient instance.
|
||||
* @param server an #AislServer instance pointer.
|
||||
* @param fd a client socket descriptor.
|
||||
* @param addr a pointer to client's address structure.
|
||||
* @param ssl_ctx a pointer to SSL context or NULL if encryption is disabled
|
||||
*/
|
||||
aisl_client_t
|
||||
aisl_client_new( aisl_server_t server,
|
||||
int fd,
|
||||
struct sockaddr_in * addr );
|
||||
AislClient
|
||||
aisl_client_new(AislServer server,
|
||||
int fd,
|
||||
struct sockaddr_in *addr );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destructor for #aisl_client_t instance.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @brief Destructor for #AislClient instance.
|
||||
* @param client an #AislClient instance pointer.
|
||||
*/
|
||||
void
|
||||
aisl_client_free(aisl_client_t client);
|
||||
aisl_client_free(AislClient client);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does all HTTP client routines.
|
||||
* Reads and parses requests, writes responses.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @param client an #AislClient instance pointer.
|
||||
* @param timeout an allowed client silence time in seconds.
|
||||
* @return #aisl_status_t code.
|
||||
* @return #AislStatus code.
|
||||
*/
|
||||
aisl_status_t
|
||||
aisl_client_touch(aisl_client_t client, int32_t timeout);
|
||||
AislStatus
|
||||
aisl_client_touch(AislClient client, int32_t timeout);
|
||||
|
||||
|
||||
/**
|
||||
* @Brief Checks if client is about to keep connection alive.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @param client an #AislClient instance pointer.
|
||||
* @return true if keepalive mode is on, otherwise false.
|
||||
*/
|
||||
bool
|
||||
aisl_client_get_keepalive(aisl_client_t client);
|
||||
aisl_client_get_keepalive(AislClient client);
|
||||
|
||||
|
||||
/**
|
||||
* @Brief Sets if connection with client must be kept alive.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @param client an #AislClient instance pointer.
|
||||
* @param value a true to enable keepalive mode, false to disable.
|
||||
*/
|
||||
void
|
||||
aisl_client_set_keepalive(aisl_client_t client, bool value);
|
||||
aisl_client_set_keepalive(AislClient client, bool value);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets socket descriptor associated with #aisl_client_t instance.
|
||||
* @param client an #aisl_client_t instance pointer.
|
||||
* @brief Gets socket descriptor associated with #AislClient instance.
|
||||
* @param client an #AislClient instance pointer.
|
||||
* @return a client socket descriptor.
|
||||
*/
|
||||
int
|
||||
aisl_client_get_socket(aisl_client_t client);
|
||||
aisl_client_get_socket(AislClient client);
|
||||
|
||||
|
||||
#endif /* !AISL_CLIENT_H */
|
||||
|
|
634
src/http.c
634
src/http.c
|
@ -20,319 +20,277 @@
|
|||
#include "debug.h"
|
||||
#include "http.h"
|
||||
|
||||
struct http_request
|
||||
|
||||
static AislHttpMethod
|
||||
http_method_from_string(const char *method, int32_t length)
|
||||
{
|
||||
char * method;
|
||||
char * schema;
|
||||
char * host;
|
||||
char * port;
|
||||
char * path;
|
||||
char * version;
|
||||
char * newline;
|
||||
int32_t method_len;
|
||||
int32_t schema_len;
|
||||
int32_t host_len;
|
||||
int32_t port_len;
|
||||
int32_t path_len;
|
||||
int32_t version_len;
|
||||
};
|
||||
int i;
|
||||
AislHttpMethod methods[3] = {0, 0, 0};
|
||||
|
||||
typedef struct http_request * http_request_t;
|
||||
switch(length) {
|
||||
case 3:
|
||||
methods[0] = AISL_HTTP_GET;
|
||||
methods[1] = AISL_HTTP_PUT;
|
||||
methods[2] = AISL_HTTP_PRI;
|
||||
break;
|
||||
|
||||
static aisl_http_method_t
|
||||
http_method_from_string( const char * method, int32_t length )
|
||||
{
|
||||
int i;
|
||||
aisl_http_method_t methods[3] = {0, 0, 0};
|
||||
case 4:
|
||||
methods[0] = AISL_HTTP_POST;
|
||||
methods[1] = AISL_HTTP_HEAD;
|
||||
break;
|
||||
|
||||
switch(length)
|
||||
{
|
||||
case 3:
|
||||
methods[0] = AISL_HTTP_GET;
|
||||
methods[1] = AISL_HTTP_PUT;
|
||||
methods[2] = AISL_HTTP_PRI;
|
||||
break;
|
||||
case 5:
|
||||
methods[0] = AISL_HTTP_TRACE;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
methods[0] = AISL_HTTP_POST;
|
||||
methods[1] = AISL_HTTP_HEAD;
|
||||
break;
|
||||
case 6:
|
||||
methods[0] = AISL_HTTP_DELETE;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
methods[0] = AISL_HTTP_TRACE;
|
||||
break;
|
||||
case 7:
|
||||
methods[0] = AISL_HTTP_OPTIONS;
|
||||
methods[1] = AISL_HTTP_CONNECT;
|
||||
break;
|
||||
}
|
||||
|
||||
case 6:
|
||||
methods[0] = AISL_HTTP_DELETE;
|
||||
break;
|
||||
for (i=0; i<sizeof (methods)/sizeof (AislHttpMethod); i++) {
|
||||
if (!(methods[i]))
|
||||
break;
|
||||
|
||||
case 7:
|
||||
methods[0] = AISL_HTTP_OPTIONS;
|
||||
methods[1] = AISL_HTTP_CONNECT;
|
||||
break;
|
||||
}
|
||||
if (strcmp(method, aisl_http_method_to_string(methods[i]))==0)
|
||||
return methods[i];
|
||||
}
|
||||
|
||||
for (i=0; i<sizeof(methods)/sizeof(aisl_http_method_t); i++)
|
||||
{
|
||||
if (!(methods[i]))
|
||||
break;
|
||||
|
||||
if (strcmp(method, aisl_http_method_to_string(methods[i]))==0)
|
||||
return methods[i];
|
||||
}
|
||||
|
||||
return AISL_HTTP_METHOD_UNKNOWN;
|
||||
return AISL_HTTP_METHOD_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
static aisl_http_version_t
|
||||
http_version_from_string(const char * version_string)
|
||||
static AislHttpVersion
|
||||
http_version_from_string(const char *version_string)
|
||||
{
|
||||
if (strncmp(version_string, "HTTP/", 5)==0)
|
||||
{
|
||||
if (strncmp(&version_string[5], "0.9", 3)==0) return AISL_HTTP_0_9;
|
||||
if (strncmp(&version_string[5], "1.0", 3)==0) return AISL_HTTP_1_0;
|
||||
if (strncmp(&version_string[5], "1.1", 3)==0) return AISL_HTTP_1_1;
|
||||
if (strncmp(&version_string[5], "2.0", 3)==0) return AISL_HTTP_2_0;
|
||||
}
|
||||
if (strncmp(version_string, "HTTP/", 5)==0) {
|
||||
if (strncmp(&version_string[5], "0.9", 3)==0) return AISL_HTTP_0_9;
|
||||
if (strncmp(&version_string[5], "1.0", 3)==0) return AISL_HTTP_1_0;
|
||||
if (strncmp(&version_string[5], "1.1", 3)==0) return AISL_HTTP_1_1;
|
||||
if (strncmp(&version_string[5], "2.0", 3)==0) return AISL_HTTP_2_0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Library Level */
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_request(char * data, int32_t * p_size, aisl_stream_t stream)
|
||||
ParserStatus
|
||||
http_10_parse_request(char *data, int32_t *p_size, AislStream stream)
|
||||
{
|
||||
/* STEP 1. Split data according to HTTP request format
|
||||
*
|
||||
* GET http://lowenware.com:80/index.html?param=value HTTP/1.1\r\n
|
||||
* ^ ^ ^ ^ ^ ^ ^ ^
|
||||
* | | | | | | | |
|
||||
* | | | | | | | +--- newline
|
||||
* | | | | | | +------------- version
|
||||
* | | | | | +------------------------- query
|
||||
* | | | | +------------------------------------- path
|
||||
* | | | +--------------------------------------- port
|
||||
* | | +----------------------------------------------------- host
|
||||
* | +------------------------------------------------------------ uri
|
||||
* +---------------------------------------------------------------- method
|
||||
*/
|
||||
char * uri = NULL,
|
||||
* uri_end = NULL,
|
||||
* host = NULL,
|
||||
* port = NULL,
|
||||
* path = NULL,
|
||||
* query = NULL,
|
||||
* version = NULL,
|
||||
* newline = NULL,
|
||||
* method = data,
|
||||
* method_end = NULL;
|
||||
/* STEP 1. Split data according to HTTP request format
|
||||
*
|
||||
* GET http://lowenware.com:80/index.html?param=value HTTP/1.1\r\n
|
||||
* ^ ^ ^ ^ ^ ^ ^ ^
|
||||
* | | | | | | | |
|
||||
* | | | | | | | +--- newline
|
||||
* | | | | | | +------------- version
|
||||
* | | | | | +------------------------- query
|
||||
* | | | | +------------------------------------- path
|
||||
* | | | +--------------------------------------- port
|
||||
* | | +----------------------------------------------------- host
|
||||
* | +------------------------------------------------------------ uri
|
||||
* +---------------------------------------------------------------- method
|
||||
*/
|
||||
char *uri = NULL,
|
||||
*uri_end = NULL,
|
||||
*host = NULL,
|
||||
*port = NULL,
|
||||
*path = NULL,
|
||||
*query = NULL,
|
||||
*version = NULL,
|
||||
*newline = NULL,
|
||||
*method = data,
|
||||
*method_end = NULL;
|
||||
|
||||
aisl_http_method_t http_method;
|
||||
aisl_http_version_t http_version;
|
||||
AislHttpMethod http_method;
|
||||
AislHttpVersion http_version;
|
||||
|
||||
int32_t size = *p_size;
|
||||
int32_t size = *p_size;
|
||||
|
||||
while(!newline && size--)
|
||||
{
|
||||
switch(*data)
|
||||
{
|
||||
case ' ':
|
||||
if (!method_end)
|
||||
method_end = data;
|
||||
else if (path && !uri_end)
|
||||
uri_end = data;
|
||||
break;
|
||||
while(!newline && size--) {
|
||||
switch(*data)
|
||||
{
|
||||
case ' ':
|
||||
if (!method_end)
|
||||
method_end = data;
|
||||
else if (path && !uri_end)
|
||||
uri_end = data;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if (uri && !host)
|
||||
host = data+3;
|
||||
else if (host && !port)
|
||||
port = data+1;
|
||||
else if (version)
|
||||
return HTTP_PARSER_ERROR;
|
||||
break;
|
||||
case ':':
|
||||
if (uri && !host)
|
||||
host = data+3;
|
||||
else if (host && !port)
|
||||
port = data+1;
|
||||
else if (version)
|
||||
return HTTP_PARSER_ERROR;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
if (!path && data > host)
|
||||
{
|
||||
path = data;
|
||||
if (!uri)
|
||||
uri = path;
|
||||
}
|
||||
else if (version && data-version != 4)
|
||||
return HTTP_PARSER_ERROR;
|
||||
break;
|
||||
case '/':
|
||||
if (!path && data > host) {
|
||||
path = data;
|
||||
if (!uri)
|
||||
uri = path;
|
||||
} else if (version && data-version != 4) {
|
||||
return HTTP_PARSER_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
if (!query)
|
||||
query = data+1;
|
||||
else if (version)
|
||||
return HTTP_PARSER_ERROR;
|
||||
break;
|
||||
case '?':
|
||||
if (!query)
|
||||
query = data+1;
|
||||
else if (version)
|
||||
return HTTP_PARSER_ERROR;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
newline = data;
|
||||
break;
|
||||
case '\n':
|
||||
newline = data;
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
if (!version)
|
||||
return HTTP_PARSER_ERROR;
|
||||
break;
|
||||
case '\r':
|
||||
if (!version)
|
||||
return HTTP_PARSER_ERROR;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!uri && method_end)
|
||||
uri = data;
|
||||
else if (!version && uri_end)
|
||||
version = data;
|
||||
else if (version && data-version > 7)
|
||||
return HTTP_PARSER_ERROR;
|
||||
default:
|
||||
if (!uri && method_end)
|
||||
uri = data;
|
||||
else if (!version && uri_end)
|
||||
version = data;
|
||||
else if (version && data-version > 7)
|
||||
return HTTP_PARSER_ERROR;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
}
|
||||
data++;
|
||||
}
|
||||
/* STEP 2. Verifly splitting was completed */
|
||||
|
||||
/* Was request sent? */
|
||||
if (!newline)
|
||||
return HTTP_PARSER_HUNGRY;
|
||||
|
||||
/* STEP 2. Verifly splitting was completed */
|
||||
/* Check mandatory parts presence */
|
||||
if (!method_end || !path || !uri_end || !version)
|
||||
return HTTP_PARSER_ERROR;
|
||||
|
||||
/* Was request sent? */
|
||||
if (!newline)
|
||||
return HTTP_PARSER_HUNGRY;
|
||||
*method_end = 0;
|
||||
*newline = 0;
|
||||
*uri_end = 0;
|
||||
|
||||
http_method = http_method_from_string(method, method_end - method);
|
||||
if (http_method == AISL_HTTP_METHOD_UNKNOWN)
|
||||
return HTTP_PARSER_ERROR;
|
||||
|
||||
/* Check mandatory parts presence */
|
||||
if (!method_end || !path || !uri_end || !version)
|
||||
return HTTP_PARSER_ERROR;
|
||||
if ((http_version = http_version_from_string(version))==0)
|
||||
return HTTP_PARSER_ERROR;
|
||||
|
||||
*method_end = 0;
|
||||
*newline = 0;
|
||||
*uri_end = 0;
|
||||
if (query) {
|
||||
*(query-1)=0;
|
||||
} else {
|
||||
query = uri_end;
|
||||
}
|
||||
|
||||
http_method = http_method_from_string(method, method_end - method);
|
||||
if (http_method == AISL_HTTP_METHOD_UNKNOWN)
|
||||
return HTTP_PARSER_ERROR;
|
||||
if (host) {
|
||||
if (strncmp(uri, "http://", 7) || strncmp(uri, "https://", 8))
|
||||
return HTTP_PARSER_ERROR;
|
||||
|
||||
if ((http_version = http_version_from_string(version))==0)
|
||||
return HTTP_PARSER_ERROR;
|
||||
if (port)
|
||||
*(port-1)=0;
|
||||
}
|
||||
|
||||
if (query)
|
||||
{
|
||||
*(query-1)=0;
|
||||
}
|
||||
else
|
||||
query = uri_end;
|
||||
stream->client->http_version = http_version;
|
||||
aisl_stream_set_request(stream, http_method, path, query);
|
||||
|
||||
if (host)
|
||||
{
|
||||
if (strncmp(uri, "http://", 7) || strncmp(uri, "https://", 8))
|
||||
return HTTP_PARSER_ERROR;
|
||||
|
||||
if (port)
|
||||
*(port-1)=0;
|
||||
}
|
||||
|
||||
stream->client->http_version = http_version;
|
||||
|
||||
aisl_stream_set_request(stream, http_method, path, query);
|
||||
|
||||
if (host)
|
||||
aisl_stream_set_header(stream, "host", host);
|
||||
|
||||
/* how many characters has been read */
|
||||
*(p_size)-=size;
|
||||
return HTTP_PARSER_SUCCESS;
|
||||
if (host)
|
||||
aisl_stream_set_header(stream, "host", host);
|
||||
/* how many characters has been read */
|
||||
*(p_size)-=size;
|
||||
return HTTP_PARSER_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_header(char * data, int32_t * p_size, aisl_stream_t stream)
|
||||
ParserStatus
|
||||
http_10_parse_header(char *data, int32_t *p_size, AislStream stream)
|
||||
{
|
||||
int32_t size = *p_size;
|
||||
char * key = data,
|
||||
* colon = NULL,
|
||||
* val = NULL,
|
||||
* val_end = NULL,
|
||||
* newline = NULL;
|
||||
int32_t size = *p_size;
|
||||
char *key = data,
|
||||
*colon = NULL,
|
||||
*val = NULL,
|
||||
*val_end = NULL,
|
||||
*newline = NULL;
|
||||
|
||||
while(!newline && size-- )
|
||||
{
|
||||
switch(*data)
|
||||
{
|
||||
case ' ':
|
||||
if (val && !val_end)
|
||||
val_end = data;
|
||||
break;
|
||||
while(!newline && size-- ) {
|
||||
switch(*data) {
|
||||
case ' ':
|
||||
if (val && !val_end)
|
||||
val_end = data;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if (!colon)
|
||||
{
|
||||
if (colon == key)
|
||||
return HTTP_PARSER_ERROR;
|
||||
case ':':
|
||||
if (!colon) {
|
||||
if (colon == key)
|
||||
return HTTP_PARSER_ERROR;
|
||||
|
||||
colon = data;
|
||||
}
|
||||
break;
|
||||
colon = data;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
newline = data;
|
||||
case '\n':
|
||||
newline = data;
|
||||
|
||||
case '\r':
|
||||
if (!val_end && val)
|
||||
val_end = data;
|
||||
break;
|
||||
case '\r':
|
||||
if (!val_end && val)
|
||||
val_end = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!colon)
|
||||
{
|
||||
*data = tolower(*data);
|
||||
}
|
||||
else if (!val)
|
||||
{
|
||||
if (colon)
|
||||
val = data;
|
||||
}
|
||||
default:
|
||||
if (!colon) {
|
||||
*data = tolower(*data);
|
||||
} else if (!val) {
|
||||
if (colon)
|
||||
val = data;
|
||||
}
|
||||
|
||||
if (val_end)
|
||||
val_end = NULL;
|
||||
if (val_end)
|
||||
val_end = NULL;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
}
|
||||
data++;
|
||||
}
|
||||
if (!newline)
|
||||
return HTTP_PARSER_HUNGRY;
|
||||
|
||||
if (!newline)
|
||||
return HTTP_PARSER_HUNGRY;
|
||||
|
||||
if (colon && val && val_end)
|
||||
{
|
||||
*colon = 0;
|
||||
*val_end = 0;
|
||||
|
||||
aisl_stream_set_header(stream, key, val);
|
||||
|
||||
*p_size -= size;
|
||||
|
||||
return HTTP_PARSER_SUCCESS;
|
||||
}
|
||||
else if (newline == key || (newline == key+1 && *key == '\r'))
|
||||
{
|
||||
return (aisl_stream_set_end_of_headers(stream) == 0) ? HTTP_PARSER_READY :
|
||||
HTTP_PARSER_SUCCESS;
|
||||
}
|
||||
|
||||
return HTTP_PARSER_ERROR;
|
||||
if (colon && val && val_end) {
|
||||
*colon = 0;
|
||||
*val_end = 0;
|
||||
aisl_stream_set_header(stream, key, val);
|
||||
*p_size -= size;
|
||||
return HTTP_PARSER_SUCCESS;
|
||||
} else if (newline == key || (newline == key+1 && *key == '\r')) {
|
||||
return (aisl_stream_set_end_of_headers(stream) == 0) ?
|
||||
HTTP_PARSER_READY : HTTP_PARSER_SUCCESS;
|
||||
}
|
||||
return HTTP_PARSER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_body(char * data, int32_t * p_size, aisl_stream_t stream)
|
||||
ParserStatus
|
||||
http_10_parse_body(char *data, int32_t *p_size, AislStream stream)
|
||||
{
|
||||
switch (aisl_stream_set_body(stream, data, *p_size))
|
||||
{
|
||||
case 0: return HTTP_PARSER_READY;
|
||||
case -1: return HTTP_PARSER_ERROR;
|
||||
default: return HTTP_PARSER_SUCCESS;
|
||||
}
|
||||
switch (aisl_stream_set_body(stream, data, *p_size)) {
|
||||
case 0:
|
||||
return HTTP_PARSER_READY;
|
||||
case -1:
|
||||
return HTTP_PARSER_ERROR;
|
||||
default:
|
||||
return HTTP_PARSER_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,102 +298,94 @@ http_10_parse_body(char * data, int32_t * p_size, aisl_stream_t stream)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
const char *
|
||||
aisl_http_version_to_string(aisl_http_version_t version)
|
||||
aisl_http_version_to_string(AislHttpVersion version)
|
||||
{
|
||||
switch (version)
|
||||
{
|
||||
case AISL_HTTP_0_9: return "HTTP/0.9";
|
||||
case AISL_HTTP_1_0: return "HTTP/1.0";
|
||||
case AISL_HTTP_1_1: return "HTTP/1.1";
|
||||
case AISL_HTTP_2_0: return "HTTP/2.0";
|
||||
}
|
||||
return "";
|
||||
switch (version) {
|
||||
case AISL_HTTP_0_9:
|
||||
return "HTTP/0.9";
|
||||
case AISL_HTTP_1_0:
|
||||
return "HTTP/1.0";
|
||||
case AISL_HTTP_1_1:
|
||||
return "HTTP/1.1";
|
||||
case AISL_HTTP_2_0:
|
||||
return "HTTP/2.0";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
const char *
|
||||
aisl_http_response_to_string(aisl_http_response_t code)
|
||||
aisl_http_response_to_string(AislHttpResponse code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
/* most common for faster behavior */
|
||||
case AISL_HTTP_OK: return "OK";
|
||||
case AISL_HTTP_MOVED_PERMANENTLY: return "Moved Permanently";
|
||||
|
||||
/* informational */
|
||||
case AISL_HTTP_CONTINUE: return "Continue";
|
||||
case AISL_HTTP_SWITCHING_PROTOCOLS: return "Switching Protocols";
|
||||
/* Successful */
|
||||
case AISL_HTTP_CREATED: return "Created";
|
||||
case AISL_HTTP_ACCEPTED: return "Accepted";
|
||||
case AISL_HTTP_NON_AUTHORITATIVE_INFORMATION: return "Non-Authoritative Information";
|
||||
case AISL_HTTP_NO_CONTENT: return "No Content";
|
||||
case AISL_HTTP_RESET_CONTENT: return "Reset Content";
|
||||
case AISL_HTTP_PARTIAL_CONTENT: return "Partial Content";
|
||||
/* redirection */
|
||||
case AISL_HTTP_MULTIPLE_CHOICES: return "Multiple Choices";
|
||||
case AISL_HTTP_FOUND: return "Found";
|
||||
case AISL_HTTP_SEE_OTHER: return "See other";
|
||||
case AISL_HTTP_NOT_MODIFIED: return "Not Modified";
|
||||
case AISL_HTTP_USE_PROXY: return "Use Proxy";
|
||||
case AISL_HTTP_UNUSED: return "(unused)";
|
||||
case AISL_HTTP_TEMPORARY_REDIRECT: return "Temporary Redirect";
|
||||
/* client error */
|
||||
case AISL_HTTP_BAD_REQUEST: return "Bad Request";
|
||||
case AISL_HTTP_UNAUTHORIZED: return "Unauthorized";
|
||||
case AISL_HTTP_PAYMENT_REQUIRED: return "Payment Required";
|
||||
case AISL_HTTP_FORBIDDEN: return "Forbidden";
|
||||
case AISL_HTTP_NOT_FOUND: return "Not Found";
|
||||
case AISL_HTTP_METHOD_NOT_ALLOWED: return "Method Not Allowed";
|
||||
case AISL_HTTP_NOT_ACCEPTABLE: return "Not Acceptable";
|
||||
case AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED: return "Proxy Authentication Required";
|
||||
case AISL_HTTP_REQUEST_TIMEOUT: return "Request Timeout";
|
||||
case AISL_HTTP_CONFLICT: return "Conflict";
|
||||
case AISL_HTTP_GONE: return "Gone";
|
||||
case AISL_HTTP_LENGTH_REQUIRED: return "Length Required";
|
||||
case AISL_HTTP_PRECONDITION_FAILED: return "Precondition Failed";
|
||||
case AISL_HTTP_REQUEST_ENTITY_TOO_LARGE: return "Request Entity Too Large";
|
||||
case AISL_HTTP_REQUEST_URI_TOO_LONG: return "Request-URI Too Long";
|
||||
case AISL_HTTP_UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type";
|
||||
case AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: return "Requested Range Not Satisfiable";
|
||||
case AISL_HTTP_EXPECTATION_FAILED: return "Expectation Failed";
|
||||
/* server error */
|
||||
case AISL_HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
|
||||
case AISL_HTTP_NOT_IMPLEMENTED: return "Not Implemented";
|
||||
case AISL_HTTP_BAD_GATEWAY: return "Bad Gateway";
|
||||
case AISL_HTTP_SERVICE_UNAVAILABLE: return "Service Unavailable";
|
||||
case AISL_HTTP_GATEWAY_TIMEOUT: return "Gateway Timeout";
|
||||
case AISL_HTTP_VERSION_NOT_SUPPORTED: return "HTTP Version Not Supported";
|
||||
|
||||
}
|
||||
return "";
|
||||
|
||||
switch (code) {
|
||||
/* most common for faster behavior */
|
||||
case AISL_HTTP_OK: return "OK";
|
||||
case AISL_HTTP_MOVED_PERMANENTLY: return "Moved Permanently";
|
||||
/* informational */
|
||||
case AISL_HTTP_CONTINUE: return "Continue";
|
||||
case AISL_HTTP_SWITCHING_PROTOCOLS: return "Switching Protocols";
|
||||
/* Successful */
|
||||
case AISL_HTTP_CREATED: return "Created";
|
||||
case AISL_HTTP_ACCEPTED: return "Accepted";
|
||||
case AISL_HTTP_NON_AUTHORITATIVE_INFORMATION: return "Non-Authoritative Information";
|
||||
case AISL_HTTP_NO_CONTENT: return "No Content";
|
||||
case AISL_HTTP_RESET_CONTENT: return "Reset Content";
|
||||
case AISL_HTTP_PARTIAL_CONTENT: return "Partial Content";
|
||||
/* redirection */
|
||||
case AISL_HTTP_MULTIPLE_CHOICES: return "Multiple Choices";
|
||||
case AISL_HTTP_FOUND: return "Found";
|
||||
case AISL_HTTP_SEE_OTHER: return "See other";
|
||||
case AISL_HTTP_NOT_MODIFIED: return "Not Modified";
|
||||
case AISL_HTTP_USE_PROXY: return "Use Proxy";
|
||||
case AISL_HTTP_UNUSED: return "(unused)";
|
||||
case AISL_HTTP_TEMPORARY_REDIRECT: return "Temporary Redirect";
|
||||
/* client error */
|
||||
case AISL_HTTP_BAD_REQUEST: return "Bad Request";
|
||||
case AISL_HTTP_UNAUTHORIZED: return "Unauthorized";
|
||||
case AISL_HTTP_PAYMENT_REQUIRED: return "Payment Required";
|
||||
case AISL_HTTP_FORBIDDEN: return "Forbidden";
|
||||
case AISL_HTTP_NOT_FOUND: return "Not Found";
|
||||
case AISL_HTTP_METHOD_NOT_ALLOWED: return "Method Not Allowed";
|
||||
case AISL_HTTP_NOT_ACCEPTABLE: return "Not Acceptable";
|
||||
case AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED: return "Proxy Authentication Required";
|
||||
case AISL_HTTP_REQUEST_TIMEOUT: return "Request Timeout";
|
||||
case AISL_HTTP_CONFLICT: return "Conflict";
|
||||
case AISL_HTTP_GONE: return "Gone";
|
||||
case AISL_HTTP_LENGTH_REQUIRED: return "Length Required";
|
||||
case AISL_HTTP_PRECONDITION_FAILED: return "Precondition Failed";
|
||||
case AISL_HTTP_REQUEST_ENTITY_TOO_LARGE: return "Request Entity Too Large";
|
||||
case AISL_HTTP_REQUEST_URI_TOO_LONG: return "Request-URI Too Long";
|
||||
case AISL_HTTP_UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type";
|
||||
case AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: return "Requested Range Not Satisfiable";
|
||||
case AISL_HTTP_EXPECTATION_FAILED: return "Expectation Failed";
|
||||
/* server error */
|
||||
case AISL_HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
|
||||
case AISL_HTTP_NOT_IMPLEMENTED: return "Not Implemented";
|
||||
case AISL_HTTP_BAD_GATEWAY: return "Bad Gateway";
|
||||
case AISL_HTTP_SERVICE_UNAVAILABLE: return "Service Unavailable";
|
||||
case AISL_HTTP_GATEWAY_TIMEOUT: return "Gateway Timeout";
|
||||
case AISL_HTTP_VERSION_NOT_SUPPORTED: return "HTTP Version Not Supported";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
const char *
|
||||
aisl_http_method_to_string( aisl_http_method_t method )
|
||||
aisl_http_method_to_string( AislHttpMethod method )
|
||||
{
|
||||
switch(method)
|
||||
{
|
||||
case AISL_HTTP_GET: return "GET";
|
||||
case AISL_HTTP_PUT: return "PUT";
|
||||
case AISL_HTTP_POST: return "POST";
|
||||
case AISL_HTTP_HEAD: return "HEAD";
|
||||
case AISL_HTTP_TRACE: return "TRACE";
|
||||
case AISL_HTTP_DELETE: return "DELETE";
|
||||
case AISL_HTTP_OPTIONS: return "OPTIONS";
|
||||
case AISL_HTTP_CONNECT: return "CONNECT";
|
||||
|
||||
case AISL_HTTP_PRI: return "PRI";
|
||||
|
||||
case AISL_HTTP_METHOD_UNKNOWN: break;
|
||||
}
|
||||
|
||||
return "";
|
||||
switch(method) {
|
||||
case AISL_HTTP_GET: return "GET";
|
||||
case AISL_HTTP_PUT: return "PUT";
|
||||
case AISL_HTTP_POST: return "POST";
|
||||
case AISL_HTTP_HEAD: return "HEAD";
|
||||
case AISL_HTTP_TRACE: return "TRACE";
|
||||
case AISL_HTTP_DELETE: return "DELETE";
|
||||
case AISL_HTTP_OPTIONS: return "OPTIONS";
|
||||
case AISL_HTTP_CONNECT: return "CONNECT";
|
||||
case AISL_HTTP_PRI: return "PRI";
|
||||
case AISL_HTTP_METHOD_UNKNOWN: break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
26
src/http.h
26
src/http.h
|
@ -18,26 +18,24 @@
|
|||
|
||||
#include <aisl/types.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HTTP_PARSER_SUCCESS
|
||||
, HTTP_PARSER_READY
|
||||
, HTTP_PARSER_HUNGRY
|
||||
, HTTP_PARSER_ERROR
|
||||
|
||||
} http_parser_t;
|
||||
typedef enum {
|
||||
HTTP_PARSER_SUCCESS
|
||||
, HTTP_PARSER_READY
|
||||
, HTTP_PARSER_HUNGRY
|
||||
, HTTP_PARSER_ERROR
|
||||
} ParserStatus;
|
||||
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_request(char * data, int32_t * size, aisl_stream_t stream);
|
||||
ParserStatus
|
||||
http_10_parse_request(char *data, int32_t *size, AislStream stream);
|
||||
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_header(char * data, int32_t * size, aisl_stream_t stream);
|
||||
ParserStatus
|
||||
http_10_parse_header(char *data, int32_t *size, AislStream stream);
|
||||
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_body(char * data, int32_t * size, aisl_stream_t stream);
|
||||
ParserStatus
|
||||
http_10_parse_body(char *data, int32_t *size, AislStream stream);
|
||||
|
||||
|
||||
#endif /* !AISL_HTTP_H */
|
||||
|
|
393
src/instance.c
393
src/instance.c
|
@ -22,10 +22,8 @@
|
|||
#include "debug.h"
|
||||
#include "str-utils.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "server.h"
|
||||
//#include "globals.h"
|
||||
#include "stream.h"
|
||||
#include "instance.h"
|
||||
|
||||
|
@ -34,42 +32,35 @@
|
|||
|
||||
static uint32_t m_instances = 0;
|
||||
|
||||
|
||||
static const aisl_ssl_t
|
||||
aisl_new_ssl( aisl_t instance, const aisl_cfg_ssl_t cfg_ssl)
|
||||
static struct aisl_ssl *
|
||||
aisl_new_ssl(AislInstance instance, const struct aisl_cfg_ssl *cfg_ssl)
|
||||
{
|
||||
SSL_CTX * ssl_ctx = NULL;
|
||||
aisl_ssl_t * list = instance->ssl,
|
||||
ssl;
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
struct aisl_ssl **list, *ssl;
|
||||
|
||||
/* lookup for existing contexts */
|
||||
while( (ssl = *list) )
|
||||
{
|
||||
if (ssl->key_file && strcmp(ssl->key_file, cfg_ssl->key_file)==0 &&
|
||||
ssl->crt_file && strcmp(ssl->crt_file, cfg_ssl->crt_file)==0 )
|
||||
{
|
||||
ssl_ctx = ssl->ctx;
|
||||
break;
|
||||
}
|
||||
list = instance->ssl;
|
||||
|
||||
list++;
|
||||
}
|
||||
/* lookup for existing contexts */
|
||||
while ((ssl = *list)) {
|
||||
if (ssl->key_file && strcmp(ssl->key_file, cfg_ssl->key_file)==0 &&
|
||||
ssl->crt_file && strcmp(ssl->crt_file, cfg_ssl->crt_file)==0
|
||||
) {
|
||||
ssl_ctx = ssl->ctx;
|
||||
break;
|
||||
}
|
||||
list++;
|
||||
}
|
||||
|
||||
ssl = aisl_ssl_new( cfg_ssl->host,
|
||||
cfg_ssl->key_file,
|
||||
cfg_ssl->crt_file,
|
||||
ssl_ctx );
|
||||
ssl = aisl_ssl_new(cfg_ssl->host, cfg_ssl->key_file, cfg_ssl->crt_file,
|
||||
ssl_ctx);
|
||||
|
||||
if (ssl)
|
||||
{
|
||||
if ( !ssl_ctx && !aisl_ssl_get_ctx(ssl, (void*) instance))
|
||||
{
|
||||
aisl_ssl_free(ssl);
|
||||
ssl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ssl;
|
||||
if (ssl) {
|
||||
if (!ssl_ctx && !aisl_ssl_get_ctx(ssl, (void*) instance)) {
|
||||
aisl_ssl_free(ssl);
|
||||
ssl = NULL;
|
||||
}
|
||||
}
|
||||
return ssl;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -78,265 +69,233 @@ aisl_new_ssl( aisl_t instance, const aisl_cfg_ssl_t cfg_ssl)
|
|||
/* Initialization functions */
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_t
|
||||
aisl_new( aisl_cfg_t cfg )
|
||||
AislInstance
|
||||
aisl_new(const struct aisl_cfg *cfg)
|
||||
{
|
||||
aisl_t instance;
|
||||
int i;
|
||||
AislInstance instance;
|
||||
|
||||
/* allocate root structure */
|
||||
if ( !(instance = calloc(1, sizeof(struct aisl))) )
|
||||
goto finally;
|
||||
/* allocate root structure */
|
||||
if (!(instance = calloc(1, sizeof (struct aisl_instance))))
|
||||
goto finally;
|
||||
|
||||
/* allocate servers */
|
||||
if ( !(instance->srv = calloc(cfg->srv_cnt+1, sizeof(aisl_server_t))) )
|
||||
goto release;
|
||||
/* allocate servers */
|
||||
if (!(instance->srv = calloc(cfg->srv_cnt+1, sizeof (AislServer))))
|
||||
goto release;
|
||||
|
||||
for (int i=0; i<cfg->srv_cnt; i++)
|
||||
{
|
||||
DPRINTF("new srv %d", i);
|
||||
if (!(instance->srv[i] = aisl_server_new(&cfg->srv[i], instance)))
|
||||
goto release;
|
||||
}
|
||||
for (i = 0; i < cfg->srv_cnt; i++) {
|
||||
DPRINTF("new srv %d", i);
|
||||
if (!(instance->srv[i] = aisl_server_new(&cfg->srv[i], instance)))
|
||||
goto release;
|
||||
}
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if ((m_instances++) == 0)
|
||||
{
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_ssl_algorithms();
|
||||
}
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if ((m_instances++) == 0) {
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_ssl_algorithms();
|
||||
}
|
||||
|
||||
if ( !(instance->ssl = calloc(cfg->ssl_cnt+1, sizeof(aisl_ssl_t))) )
|
||||
goto release;
|
||||
if (!(instance->ssl = calloc(cfg->ssl_cnt+1, sizeof (struct aisl_ssl))))
|
||||
goto release;
|
||||
|
||||
for (int i=0; i<cfg->ssl_cnt; i++)
|
||||
{
|
||||
DPRINTF("new ssl %d", i);
|
||||
if (!(instance->ssl[i] = aisl_new_ssl(instance, &cfg->ssl[i])))
|
||||
goto release;
|
||||
}
|
||||
#endif
|
||||
for (i=0; i<cfg->ssl_cnt; i++) {
|
||||
DPRINTF("new ssl %d", i);
|
||||
if (!(instance->ssl[i] = aisl_new_ssl(instance, &cfg->ssl[i])))
|
||||
goto release;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( list_init(&instance->client_spool, cfg->client_spool_size) == -1 )
|
||||
goto release;
|
||||
if (list_init(&instance->client_spool, cfg->client_spool_size) == -1)
|
||||
goto release;
|
||||
|
||||
instance->accept_limit = cfg->client_accept_limit;
|
||||
instance->silence_timeout = cfg->client_silence_timeout;
|
||||
instance->callback = cfg->callback;
|
||||
instance->p_ctx = cfg->p_ctx;
|
||||
instance->accept_limit = cfg->client_accept_limit;
|
||||
instance->silence_timeout = cfg->client_silence_timeout;
|
||||
instance->callback = cfg->callback;
|
||||
instance->p_ctx = cfg->p_ctx;
|
||||
|
||||
goto finally;
|
||||
goto finally;
|
||||
|
||||
release:
|
||||
aisl_free(instance);
|
||||
instance = NULL;
|
||||
aisl_free(instance);
|
||||
instance = NULL;
|
||||
|
||||
finally:
|
||||
return instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_free( aisl_t instance )
|
||||
aisl_free(AislInstance instance)
|
||||
{
|
||||
if (instance->srv)
|
||||
{
|
||||
aisl_server_t * srv = instance->srv;
|
||||
if (instance->srv) {
|
||||
AislServer * srv = instance->srv;
|
||||
|
||||
while (*srv)
|
||||
{
|
||||
aisl_server_free(*srv);
|
||||
srv++;
|
||||
}
|
||||
while (*srv) {
|
||||
aisl_server_free(*(srv++));
|
||||
}
|
||||
|
||||
free(instance->srv);
|
||||
}
|
||||
free(instance->srv);
|
||||
}
|
||||
|
||||
list_release(&instance->client_spool, (list_destructor_t) aisl_client_free );
|
||||
list_release(&instance->client_spool, (list_destructor_t)aisl_client_free);
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (instance->ssl)
|
||||
{
|
||||
aisl_ssl_t * ssl = instance->ssl;
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (instance->ssl) {
|
||||
struct aisl_ssl **ssl = instance->ssl;
|
||||
|
||||
while (*ssl)
|
||||
{
|
||||
aisl_ssl_free(*ssl);
|
||||
ssl++;
|
||||
}
|
||||
while (*ssl) {
|
||||
aisl_ssl_free(*(ssl++));
|
||||
}
|
||||
free(instance->ssl);
|
||||
}
|
||||
|
||||
free(instance->ssl);
|
||||
}
|
||||
if ((--m_instances) == 0) {
|
||||
EVP_cleanup();
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((--m_instances) == 0)
|
||||
{
|
||||
EVP_cleanup();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
free(instance);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
|
||||
SSL_CTX *
|
||||
aisl_get_ssl_ctx( aisl_t instance, const char * host )
|
||||
aisl_get_ssl_ctx(AislInstance instance, const char * host)
|
||||
{
|
||||
aisl_ssl_t * list = instance->ssl,
|
||||
ssl;
|
||||
struct aisl_ssl **list, *ssl;
|
||||
|
||||
if (host)
|
||||
{
|
||||
while ( (ssl = *list) )
|
||||
{
|
||||
if (str_cmpi(ssl->host, host) == 0)
|
||||
{
|
||||
return ssl->ctx;
|
||||
}
|
||||
list = instance->ssl;
|
||||
|
||||
list++;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
if (host) {
|
||||
while ((ssl = *list)) {
|
||||
if (str_cmpi(ssl->host, host) == 0) {
|
||||
return ssl->ctx;
|
||||
}
|
||||
list++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
aisl_raise_evt( aisl_t instance, aisl_evt_t const evt )
|
||||
aisl_raise_evt(AislInstance instance, const struct aisl_evt *evt)
|
||||
{
|
||||
#ifdef AISL_WITHOUT_STRINGIFIERS
|
||||
DPRINTF("! %d", evt->code);
|
||||
#else
|
||||
DPRINTF("! %s", aisl_evt_code_to_string(evt->code));
|
||||
#endif
|
||||
#ifdef AISL_WITHOUT_STRINGIFIERS
|
||||
DPRINTF("! %d", evt->code);
|
||||
#else
|
||||
DPRINTF("! %s", aisl_event_to_string(evt->code));
|
||||
#endif
|
||||
|
||||
if (instance->callback)
|
||||
instance->callback(evt, instance->p_ctx);
|
||||
if (instance->callback)
|
||||
instance->callback(evt, instance->p_ctx);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_raise( aisl_t instance,
|
||||
void * source,
|
||||
aisl_evt_code_t code,
|
||||
aisl_status_t status )
|
||||
aisl_raise(AislInstance instance,
|
||||
void *source,
|
||||
AislEvent code,
|
||||
AislStatus status)
|
||||
{
|
||||
struct aisl_evt evt;
|
||||
struct aisl_evt evt;
|
||||
|
||||
evt.source = source;
|
||||
evt.code = code;
|
||||
evt.status = status;
|
||||
evt.source = source;
|
||||
evt.code = code;
|
||||
evt.status = status;
|
||||
|
||||
aisl_raise_evt(instance, &evt);
|
||||
aisl_raise_evt(instance, &evt);
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_status_t
|
||||
aisl_run_cycle( aisl_t instance )
|
||||
AislStatus
|
||||
aisl_run_cycle(AislInstance instance)
|
||||
{
|
||||
aisl_status_t result = AISL_IDLE;
|
||||
AislStatus result = AISL_IDLE;
|
||||
AislServer *list, srv;
|
||||
AislClient cli;
|
||||
int32_t i;
|
||||
|
||||
aisl_server_t * list = instance->srv,
|
||||
srv;
|
||||
aisl_client_t cli;
|
||||
list = instance->srv;
|
||||
|
||||
while ( (srv = *list) )
|
||||
{
|
||||
cli = NULL;
|
||||
while ((srv = *list)) {
|
||||
cli = NULL;
|
||||
|
||||
if (aisl_server_touch(srv, &cli) != AISL_IDLE)
|
||||
result = AISL_SUCCESS;
|
||||
if (aisl_server_touch(srv, &cli) != AISL_IDLE)
|
||||
result = AISL_SUCCESS;
|
||||
|
||||
if (cli)
|
||||
{
|
||||
DPRINTF("Accepted %p", (void*)cli);
|
||||
if ( list_append(&instance->client_spool, cli) == -1 )
|
||||
aisl_client_free(cli);
|
||||
}
|
||||
if (cli) {
|
||||
DPRINTF("Accepted %p", (void*)cli);
|
||||
if (list_append(&instance->client_spool, cli) == -1)
|
||||
aisl_client_free(cli);
|
||||
}
|
||||
list++;
|
||||
}
|
||||
|
||||
list++;
|
||||
}
|
||||
for (i=0; i < instance->client_spool.count; i++) {
|
||||
cli = LIST_INDEX(instance->client_spool, i);
|
||||
|
||||
for (int32_t i=0; i < instance->client_spool.count; i++)
|
||||
{
|
||||
cli = LIST_INDEX(instance->client_spool, i);
|
||||
if (aisl_client_touch(cli, instance->silence_timeout) != AISL_IDLE)
|
||||
result = AISL_SUCCESS;
|
||||
|
||||
if (aisl_client_touch(cli, instance->silence_timeout) != AISL_IDLE)
|
||||
result = AISL_SUCCESS;
|
||||
|
||||
/* if (aisl_client_is_timed_out( c, instance->silence_timeout ) )
|
||||
aisl_raise( instance, c, AISL_EVENT_CLIENT_TIMEOUT );
|
||||
*/
|
||||
|
||||
if ( !aisl_client_is_online(cli) )
|
||||
{
|
||||
aisl_client_free( cli );
|
||||
list_remove_index(&instance->client_spool, i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
if (!aisl_client_is_online(cli)) {
|
||||
aisl_client_free( cli );
|
||||
list_remove_index(&instance->client_spool, i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_status_t
|
||||
aisl_sleep( aisl_t instance, uint32_t usec )
|
||||
AislStatus
|
||||
aisl_sleep(AislInstance instance, uint32_t usec)
|
||||
{
|
||||
int maxfd=0,
|
||||
sd;
|
||||
size_t i;
|
||||
struct timeval timeout = {0,usec};
|
||||
AislServer *list, srv;
|
||||
int sd, maxfd = 0;
|
||||
size_t i;
|
||||
struct timeval timeout = {0,usec};
|
||||
|
||||
memset(&timeout, 0, sizeof(struct timeval));
|
||||
timeout.tv_usec = usec;
|
||||
memset(&timeout, 0, sizeof (struct timeval));
|
||||
timeout.tv_usec = usec;
|
||||
|
||||
fd_set fs;
|
||||
FD_ZERO (&fs);
|
||||
fd_set fs;
|
||||
FD_ZERO (&fs);
|
||||
|
||||
aisl_server_t * list = instance->srv,
|
||||
srv;
|
||||
list = instance->srv;
|
||||
|
||||
while ( (srv = *list) )
|
||||
{
|
||||
sd = aisl_server_get_socket(srv);
|
||||
while ((srv = *list)) {
|
||||
sd = aisl_server_get_socket(srv);
|
||||
|
||||
if (sd != -1)
|
||||
{
|
||||
FD_SET(sd, &fs);
|
||||
if (sd > maxfd) maxfd = sd;
|
||||
}
|
||||
if (sd != -1) {
|
||||
FD_SET(sd, &fs);
|
||||
if (sd > maxfd) maxfd = sd;
|
||||
}
|
||||
list++;
|
||||
}
|
||||
|
||||
list++;
|
||||
}
|
||||
for (i=0; i<instance->client_spool.count; i++) {
|
||||
AislClient c = LIST_INDEX(instance->client_spool, i);
|
||||
sd = aisl_client_get_socket(c);
|
||||
if (sd != -1) {
|
||||
FD_SET(sd, &fs);
|
||||
if (sd > maxfd) maxfd = sd;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<instance->client_spool.count; i++)
|
||||
{
|
||||
aisl_client_t c = LIST_INDEX(instance->client_spool, i);
|
||||
sd = aisl_client_get_socket(c);
|
||||
if (sd != -1)
|
||||
{
|
||||
FD_SET(sd, &fs);
|
||||
if (sd > maxfd) maxfd = sd;
|
||||
}
|
||||
}
|
||||
switch (select(maxfd+1, &fs, NULL, NULL, &timeout)) {
|
||||
case -1:
|
||||
return AISL_SYSCALL_ERROR;
|
||||
|
||||
switch ( select(maxfd+1, &fs, NULL, NULL, &timeout) )
|
||||
{
|
||||
case -1:
|
||||
return AISL_SYSCALL_ERROR;
|
||||
case 0:
|
||||
return AISL_IDLE;
|
||||
|
||||
case 0:
|
||||
return AISL_IDLE;
|
||||
|
||||
default:
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
default:
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
/*
|
||||
* src/instance.h
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2019 Ilja Kartašov <ik@lowenware.com>
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
* Project homepage: https://lowenware.com/aisl/
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file src/instance.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of aisl_instance structure and functions
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
||||
#ifndef AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
||||
|
@ -19,47 +25,46 @@
|
|||
#include "list.h"
|
||||
|
||||
|
||||
struct aisl
|
||||
{
|
||||
aisl_server_t * srv;
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
aisl_ssl_t * ssl;
|
||||
#endif
|
||||
struct list client_spool;
|
||||
aisl_callback_t callback;
|
||||
void * p_ctx;
|
||||
struct aisl_instance {
|
||||
AislServer *srv;
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
struct aisl_ssl * *ssl;
|
||||
#endif
|
||||
struct list client_spool;
|
||||
AislCallback callback;
|
||||
void *p_ctx;
|
||||
|
||||
uint32_t accept_limit;
|
||||
uint32_t silence_timeout;
|
||||
uint32_t buffer_size;
|
||||
uint32_t accept_limit;
|
||||
uint32_t silence_timeout;
|
||||
uint32_t buffer_size;
|
||||
};
|
||||
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
/**
|
||||
* @brief Gets SSL context for appropriate server name.
|
||||
* @param instance a pointer to #aisl_t instance.
|
||||
* @param instance a pointer to #AislInstance instance.
|
||||
* @param server_name a null-terminated string with server name or NULL.
|
||||
* @return a pointer to SSL context
|
||||
*/
|
||||
SSL_CTX *
|
||||
aisl_get_ssl_ctx( aisl_t instance, const char * server_name );
|
||||
aisl_get_ssl_ctx(AislInstance instance, const char *server_name);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Raises event from source.
|
||||
* @param instance a pointer to #aisl_t instance.
|
||||
* @param instance a pointer to #AislInstance instance.
|
||||
* @param evt a pointer to event structure.
|
||||
*/
|
||||
void
|
||||
aisl_raise_evt( aisl_t instance, aisl_evt_t const evt );
|
||||
aisl_raise_evt(AislInstance instance, const struct aisl_evt *evt);
|
||||
|
||||
|
||||
void
|
||||
aisl_raise( aisl_t instance,
|
||||
void * source,
|
||||
aisl_evt_code_t code,
|
||||
aisl_status_t status );
|
||||
aisl_raise(AislInstance instance,
|
||||
void *source,
|
||||
AislEvent code,
|
||||
AislStatus status);
|
||||
|
||||
#endif /* !AISL_INSTANCE_H */
|
||||
|
|
103
src/list.c
103
src/list.c
|
@ -18,87 +18,80 @@
|
|||
#include "list.h"
|
||||
|
||||
int32_t
|
||||
list_init(list_t list, int32_t size)
|
||||
list_init(struct list *list, int32_t size)
|
||||
{
|
||||
if ((list->data = calloc(size, sizeof(void*))) != NULL)
|
||||
{
|
||||
list->size = size;
|
||||
list->count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if ((list->data = calloc(size, sizeof (void*))) != NULL) {
|
||||
list->size = size;
|
||||
list->count = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
list_release(list_t list, list_destructor_t destructor)
|
||||
list_release(struct list *list, list_destructor_t destructor)
|
||||
{
|
||||
if (list->data)
|
||||
{
|
||||
if (destructor)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; i<list->count; i++)
|
||||
{
|
||||
void * ptr;
|
||||
if (list->data) {
|
||||
if (destructor) {
|
||||
int32_t i;
|
||||
|
||||
if ( (ptr = list->data[i]) != NULL)
|
||||
destructor( list->data[i] );
|
||||
}
|
||||
}
|
||||
free(list->data);
|
||||
}
|
||||
for (i=0; i<list->count; i++) {
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = list->data[i]) != NULL)
|
||||
destructor(list->data[i]);
|
||||
}
|
||||
}
|
||||
free(list->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32_t
|
||||
list_append(list_t list, void * entry)
|
||||
list_append(struct list *list, void *entry)
|
||||
{
|
||||
int32_t pos = list->count;
|
||||
int32_t pos = list->count;
|
||||
|
||||
DPRINTF("pos = %d", pos);
|
||||
DPRINTF("pos = %d", pos);
|
||||
|
||||
if ( !(pos < list->size) )
|
||||
{
|
||||
DPRINTF("extending, size = %d", list->size);
|
||||
void ** new_list;
|
||||
int32_t new_size = pos + 1;
|
||||
if (!(pos < list->size)) {
|
||||
DPRINTF("extending, size = %d", list->size);
|
||||
void **new_list;
|
||||
int32_t new_size = pos + 1;
|
||||
|
||||
DPRINTF("extending, ptr = %p", (void*)list->data);
|
||||
if ( (new_list = realloc( list->data, new_size*sizeof(void*) )) == NULL )
|
||||
return -1;
|
||||
DPRINTF("extending, ptr = %p", (void*)list->data);
|
||||
if ((new_list = realloc( list->data, new_size*sizeof (void*) )) == NULL)
|
||||
return -1;
|
||||
|
||||
list->data = new_list;
|
||||
list->size = new_size;
|
||||
}
|
||||
list->data = new_list;
|
||||
list->size = new_size;
|
||||
}
|
||||
|
||||
list->data[pos]=entry;
|
||||
list->count++;
|
||||
list->data[pos]=entry;
|
||||
list->count++;
|
||||
|
||||
return pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
list_remove_index(list_t list, int32_t index)
|
||||
list_remove_index(struct list *list, int32_t index)
|
||||
{
|
||||
void * result;
|
||||
void *result;
|
||||
|
||||
if (index < list->count)
|
||||
{
|
||||
int32_t i, c = --list->count;
|
||||
if (index < list->count) {
|
||||
int32_t i, c = --list->count;
|
||||
|
||||
result = list->data[index];
|
||||
result = list->data[index];
|
||||
|
||||
for (i=index; i<c; i++)
|
||||
{
|
||||
list->data[i]=list->data[i+1];
|
||||
}
|
||||
}
|
||||
else
|
||||
result = NULL;
|
||||
for (i = index; i<c; i++) {
|
||||
list->data[i]=list->data[i+1];
|
||||
}
|
||||
}
|
||||
else
|
||||
result = NULL;
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
25
src/list.h
25
src/list.h
|
@ -6,11 +6,11 @@
|
|||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file list.h
|
||||
* @file src/list.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief List module header file
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
||||
#ifndef AISL_LIST_H_21495B65_111D_40F7_840F_CC50D9D324A1
|
||||
|
@ -21,34 +21,31 @@
|
|||
#define LIST_INDEX(L, I) ( L.data[ I ] )
|
||||
|
||||
|
||||
struct list
|
||||
{
|
||||
void ** data;
|
||||
int32_t size;
|
||||
int32_t count;
|
||||
struct list {
|
||||
void **data;
|
||||
int32_t size;
|
||||
int32_t count;
|
||||
};
|
||||
|
||||
typedef struct list * list_t;
|
||||
|
||||
|
||||
typedef void
|
||||
(* list_destructor_t)(void * list_item);
|
||||
(* list_destructor_t)(void *list_item);
|
||||
|
||||
|
||||
int32_t
|
||||
list_init(list_t list, int32_t size);
|
||||
list_init(struct list *lst, int32_t size);
|
||||
|
||||
|
||||
void
|
||||
list_release(list_t list, list_destructor_t destructor);
|
||||
list_release(struct list *lst, list_destructor_t destructor);
|
||||
|
||||
|
||||
int32_t
|
||||
list_append(list_t list, void * entry);
|
||||
list_append(struct list *lst, void * entry);
|
||||
|
||||
|
||||
void *
|
||||
list_remove_index(list_t list, int32_t index);
|
||||
list_remove_index(struct list *lst, int32_t index);
|
||||
|
||||
|
||||
#endif /* !AISL_LIST_H */
|
||||
|
|
198
src/server.c
198
src/server.c
|
@ -6,15 +6,12 @@
|
|||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "str-utils.h"
|
||||
#include "instance.h"
|
||||
|
@ -24,151 +21,128 @@
|
|||
|
||||
/**
|
||||
* @brief Creates TCP server socket, binds to address and starts to listen.
|
||||
* @param server a pointer to #aisl_server_t instance.
|
||||
* @return #aisl_status_t code.
|
||||
* @param server a pointer to #AislServer instance.
|
||||
* @return #AislStatus code.
|
||||
*/
|
||||
static aisl_status_t
|
||||
aisl_server_open(aisl_server_t server)
|
||||
static AislStatus
|
||||
aisl_server_open(AislServer server)
|
||||
{
|
||||
int fd, s_opt = 1;
|
||||
int fd, s_opt = 1;
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&s_opt, sizeof(int));
|
||||
if (fd != -1) {
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&s_opt,
|
||||
sizeof (int));
|
||||
|
||||
#ifdef __APPLE__
|
||||
ioctl(fd, FIONBIO, (char *)&s_opt);
|
||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
ioctl(fd, FIONBIO, (char *)&s_opt);
|
||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
s_opt = sizeof(struct sockaddr_in);
|
||||
s_opt = sizeof (struct sockaddr_in);
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &server->address, s_opt)==0)
|
||||
{
|
||||
if (listen(fd, SOMAXCONN) == 0)
|
||||
{
|
||||
server->fd = fd;
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (bind(fd, (struct sockaddr *) &server->address, s_opt) == 0) {
|
||||
if (listen(fd, SOMAXCONN) == 0) {
|
||||
server->fd = fd;
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return AISL_SYSCALL_ERROR;
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Tries to accept a new client.
|
||||
* @param server a pointer to #aisl_server_t instance.
|
||||
* @param p_client a pointer to store #aisl_client_t instance pointer.
|
||||
* @return #aisl_status_t code.
|
||||
* @param server a pointer to #AislServer instance.
|
||||
* @param p_client a pointer to store #AislClient instance pointer.
|
||||
* @return #AislStatus code.
|
||||
*/
|
||||
static aisl_status_t
|
||||
aisl_server_accept( aisl_server_t server,
|
||||
aisl_client_t * p_client )
|
||||
static AislStatus
|
||||
aisl_server_accept(AislServer server, AislClient *p_client )
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(struct sockaddr_in);
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof (struct sockaddr_in);
|
||||
|
||||
fd = accept(server->fd, (struct sockaddr *) &addr, &len);
|
||||
fd = accept(server->fd, (struct sockaddr *)&addr, &len);
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
int flags;
|
||||
if (fd != -1) {
|
||||
int flags;
|
||||
|
||||
DPRINTF("accepted fd=%d", fd);
|
||||
DPRINTF("accepted fd=%d", fd);
|
||||
|
||||
if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
|
||||
{
|
||||
flags |= O_NONBLOCK;
|
||||
if ((flags = fcntl(fd, F_GETFL, 0)) != -1) {
|
||||
flags |= O_NONBLOCK;
|
||||
|
||||
if (fcntl(fd, F_SETFL, flags) == 0)
|
||||
{
|
||||
return (!(*p_client = aisl_client_new(server, fd, &addr))) ?
|
||||
AISL_MALLOC_ERROR : AISL_SUCCESS;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
else if (errno == EWOULDBLOCK)
|
||||
return AISL_IDLE;
|
||||
|
||||
return AISL_SYSCALL_ERROR;
|
||||
if (fcntl(fd, F_SETFL, flags) == 0) {
|
||||
return (!(*p_client = aisl_client_new(server, fd, &addr))) ?
|
||||
AISL_MALLOC_ERROR : AISL_SUCCESS;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
} else if (errno == EWOULDBLOCK) {
|
||||
return AISL_IDLE;
|
||||
}
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
/* Library Level ------------------------------------------------------------ */
|
||||
|
||||
aisl_status_t
|
||||
aisl_server_touch( aisl_server_t server,
|
||||
aisl_client_t * p_client )
|
||||
AislStatus
|
||||
aisl_server_touch(AislServer server, AislClient *p_client)
|
||||
{
|
||||
aisl_status_t result;
|
||||
AislStatus result;
|
||||
|
||||
if (server->fd == -1)
|
||||
{
|
||||
|
||||
if ((result = aisl_server_open(server)) != AISL_IDLE)
|
||||
{
|
||||
aisl_raise(
|
||||
server->instance,
|
||||
server,
|
||||
((result == AISL_SUCCESS) ? AISL_EVENT_SERVER_OPEN
|
||||
: AISL_EVENT_SERVER_ERROR),
|
||||
result
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
result = aisl_server_accept(server, p_client);
|
||||
|
||||
return result;
|
||||
if (server->fd == -1) {
|
||||
if ((result = aisl_server_open(server)) != AISL_IDLE) {
|
||||
aisl_raise(server->instance, server, ((result == AISL_SUCCESS) ?
|
||||
AISL_EVENT_SERVER_READY : AISL_EVENT_SERVER_ERROR), result);
|
||||
}
|
||||
} else {
|
||||
result = aisl_server_accept(server, p_client);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
aisl_server_get_socket( aisl_server_t server )
|
||||
aisl_server_get_socket(AislServer server)
|
||||
{
|
||||
return server->fd;
|
||||
return server->fd;
|
||||
}
|
||||
|
||||
|
||||
aisl_server_t
|
||||
aisl_server_new(aisl_cfg_srv_t const cfg_srv, aisl_t instance)
|
||||
AislServer
|
||||
aisl_server_new(const struct aisl_cfg_srv *cfg_srv, AislInstance instance)
|
||||
{
|
||||
aisl_server_t server;
|
||||
AislServer server;
|
||||
|
||||
if ( (server = calloc(1, sizeof(struct aisl_server))) != NULL )
|
||||
{
|
||||
server->instance = instance;
|
||||
server->fd = -1;
|
||||
server->address.sin_family = AF_INET;
|
||||
server->address.sin_addr.s_addr = inet_addr(cfg_srv->host);
|
||||
server->address.sin_port = htons(cfg_srv->port);
|
||||
server->ssl = cfg_srv->secure;
|
||||
}
|
||||
|
||||
return server;
|
||||
if ((server = calloc(1, sizeof (struct aisl_server))) != NULL) {
|
||||
server->instance = instance;
|
||||
server->fd = -1;
|
||||
server->address.sin_family = AF_INET;
|
||||
server->address.sin_addr.s_addr = inet_addr(cfg_srv->host);
|
||||
server->address.sin_port = htons(cfg_srv->port);
|
||||
server->ssl = cfg_srv->secure;
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_server_free(aisl_server_t server)
|
||||
aisl_server_free(AislServer server)
|
||||
{
|
||||
if (server)
|
||||
{
|
||||
if ( server->fd != -1)
|
||||
{
|
||||
close(server->fd);
|
||||
server->fd=-1;
|
||||
}
|
||||
|
||||
free(server);
|
||||
}
|
||||
if (server) {
|
||||
if ( server->fd != -1) {
|
||||
close(server->fd);
|
||||
server->fd=-1;
|
||||
}
|
||||
free(server);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,9 +151,9 @@ aisl_server_free(aisl_server_t server)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address)
|
||||
aisl_server_get_address(AislServer server, struct sockaddr_in *address)
|
||||
{
|
||||
memcpy(address, &server->address, sizeof(struct sockaddr_in));
|
||||
memcpy(address, &server->address, sizeof (struct sockaddr_in));
|
||||
}
|
||||
|
||||
|
||||
|
@ -187,9 +161,9 @@ aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
bool
|
||||
aisl_server_get_ssl( aisl_server_t server )
|
||||
aisl_server_get_ssl(AislServer server)
|
||||
{
|
||||
return server->ssl;
|
||||
return server->ssl;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
61
src/server.h
61
src/server.h
|
@ -1,4 +1,17 @@
|
|||
/*
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file dummy.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*//*
|
||||
* @file src/server.h
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
|
@ -13,60 +26,58 @@
|
|||
#include <aisl/config.h>
|
||||
#include <aisl/server.h>
|
||||
|
||||
#define AISL_SERVER(x) ((aisl_server_t) x)
|
||||
#define AISL_SERVER(x) ((AislServer) x)
|
||||
|
||||
/**
|
||||
* @brief HTTP(s) server data structure represented by #aisl_server_t pointer.
|
||||
* @brief HTTP(s) server data structure represented by #AislServer pointer.
|
||||
*/
|
||||
struct aisl_server
|
||||
{
|
||||
struct sockaddr_in address; /**< TCP server address to listen to. */
|
||||
aisl_t instance; /**< Associated AISL instance pointer. */
|
||||
int fd; /**< System socket descriptor. */
|
||||
bool ssl; /**< SSL enabled/disabled flag. */
|
||||
struct aisl_server {
|
||||
struct sockaddr_in address; /**< TCP server address to listen to. */
|
||||
AislInstance instance; /**< Associated AISL instance pointer. */
|
||||
int fd; /**< System socket descriptor. */
|
||||
bool ssl; /**< SSL enabled/disabled flag. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allocates and instance of #aisl_server_t.
|
||||
* @brief Allocates and instance of #AislServer.
|
||||
* @param cfg_srv a pointer to server configuration structure.
|
||||
* @param instance a pointer to #aisl_t instance.
|
||||
* @return a pointer to #aisl_server_t instance.
|
||||
* @param instance a pointer to #AislInstance instance.
|
||||
* @return a pointer to #AislServer instance.
|
||||
*/
|
||||
aisl_server_t
|
||||
aisl_server_new(aisl_cfg_srv_t const cfg_srv, aisl_t instance);
|
||||
AislServer
|
||||
aisl_server_new(const struct aisl_cfg_srv *cfg_srv, AislInstance instance);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Frees memory allocated for #aisl_server_t instance.
|
||||
* @param server a pointer to #aisl_server_t instance.
|
||||
* @brief Frees memory allocated for #AislServer instance.
|
||||
* @param server a pointer to #AislServer instance.
|
||||
*/
|
||||
void
|
||||
aisl_server_free(aisl_server_t server);
|
||||
aisl_server_free(AislServer server);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does server routines.
|
||||
* Tries to open server if it was not opened yet, otherwise tries to accept a
|
||||
* new client connecting to the server.
|
||||
* @param server a pointer to #aisl_server_t instance.
|
||||
* @param p_client a pointer to store #aisl_client_t instance pointer.
|
||||
* @return #aisl_status_t code:
|
||||
* @param server a pointer to #AislServer instance.
|
||||
* @param p_client a pointer to store #AislClient instance pointer.
|
||||
* @return #AislStatus code:
|
||||
* - AISL_SUCCESS if client connected,
|
||||
* - AISL_IDLE if there is no client to connect,
|
||||
* - AISL_SYSCALL_ERROR if error occured.
|
||||
*/
|
||||
aisl_status_t
|
||||
aisl_server_touch( aisl_server_t server,
|
||||
aisl_client_t * p_client );
|
||||
AislStatus
|
||||
aisl_server_touch(AislServer server, AislClient *p_client);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets a socket descriptor associated with HTTP client.
|
||||
* @param server a pointer to #aisl_server_t instance.
|
||||
* @param server a pointer to #AislServer instance.
|
||||
* @return a client socket descriptor.
|
||||
*/
|
||||
int
|
||||
aisl_server_get_socket(aisl_server_t server);
|
||||
aisl_server_get_socket(AislServer server);
|
||||
|
||||
|
||||
#endif /* !AISL_SERVER_H */
|
||||
|
|
123
src/ssl.c
123
src/ssl.c
|
@ -15,103 +15,88 @@
|
|||
|
||||
|
||||
static int
|
||||
aisl_ssl_on_get_ctx( SSL * ssl, int * ptr, void * instance )
|
||||
aisl_ssl_on_get_ctx(SSL *ssl, int *ptr, void *instance )
|
||||
{
|
||||
const char * server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
const char *server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
SSL_CTX *ctx = aisl_get_ssl_ctx((AislInstance) instance, server_name);
|
||||
|
||||
SSL_CTX * ctx = aisl_get_ssl_ctx( (aisl_t) instance, server_name );
|
||||
if (ctx)
|
||||
SSL_set_SSL_CTX(ssl, ctx);
|
||||
|
||||
if (ctx)
|
||||
{
|
||||
SSL_set_SSL_CTX(ssl, ctx);
|
||||
}
|
||||
(void)ptr;
|
||||
|
||||
(void)ptr;
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
SSL_CTX *
|
||||
aisl_ssl_get_ctx(aisl_ssl_t ssl, void * p_instance)
|
||||
aisl_ssl_get_ctx(struct aisl_ssl *ssl, void *p_instance)
|
||||
{
|
||||
SSL_CTX * ctx;
|
||||
SSL_CTX * ctx;
|
||||
|
||||
if ( (ctx = SSL_CTX_new(SSLv23_server_method())) != NULL )
|
||||
{
|
||||
SSL_CTX_set_ecdh_auto(ctx, 1);
|
||||
if ((ctx = SSL_CTX_new(SSLv23_server_method())) != NULL) {
|
||||
SSL_CTX_set_ecdh_auto(ctx, 1);
|
||||
SSL_CTX_set_tlsext_servername_callback( ctx, aisl_ssl_on_get_ctx );
|
||||
SSL_CTX_set_tlsext_servername_arg( ctx, p_instance );
|
||||
|
||||
SSL_CTX_set_tlsext_servername_callback( ctx, aisl_ssl_on_get_ctx );
|
||||
SSL_CTX_set_tlsext_servername_arg( ctx, p_instance );
|
||||
if (!(SSL_CTX_use_certificate_file(ctx, ssl->crt_file, SSL_FILETYPE_PEM)>0))
|
||||
goto except;
|
||||
|
||||
if (!(SSL_CTX_use_certificate_file(ctx, ssl->crt_file, SSL_FILETYPE_PEM)>0))
|
||||
goto except;
|
||||
if (!(SSL_CTX_use_PrivateKey_file(ctx, ssl->key_file, SSL_FILETYPE_PEM)>0))
|
||||
goto except;
|
||||
|
||||
if (!(SSL_CTX_use_PrivateKey_file(ctx, ssl->key_file, SSL_FILETYPE_PEM)>0))
|
||||
goto except;
|
||||
ssl->ctx = ctx;
|
||||
|
||||
ssl->ctx = ctx;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
except:
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aisl_ssl_t
|
||||
aisl_ssl_new( const char * key_file,
|
||||
const char * crt_file,
|
||||
const char * host,
|
||||
SSL_CTX * ctx )
|
||||
struct aisl_ssl *
|
||||
aisl_ssl_new(const char *key_file,
|
||||
const char *crt_file,
|
||||
const char *host,
|
||||
SSL_CTX *ctx)
|
||||
{
|
||||
aisl_ssl_t ssl;
|
||||
struct aisl_ssl *ssl;
|
||||
|
||||
if ((ssl = calloc(1, sizeof(struct aisl_ssl))) != NULL)
|
||||
{
|
||||
if ((ssl->host = str_copy( host ? host : "*" )) != NULL)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
ssl->ctx = ctx;
|
||||
return ssl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((ssl->key_file = str_copy(key_file)) != NULL)
|
||||
{
|
||||
if ((ssl->crt_file = str_copy(crt_file)) != NULL)
|
||||
{
|
||||
return ssl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
aisl_ssl_free(ssl);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
if ((ssl = calloc(1, sizeof (struct aisl_ssl))) != NULL) {
|
||||
if ((ssl->host = str_copy( host ? host : "*" )) != NULL) {
|
||||
if (ctx) {
|
||||
ssl->ctx = ctx;
|
||||
return ssl;
|
||||
} else {
|
||||
if ((ssl->key_file = str_copy(key_file)) != NULL) {
|
||||
if ((ssl->crt_file = str_copy(crt_file)) != NULL) {
|
||||
return ssl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
aisl_ssl_free(ssl);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_ssl_free( aisl_ssl_t ssl )
|
||||
aisl_ssl_free( struct aisl_ssl *ssl )
|
||||
{
|
||||
if (ssl->host)
|
||||
free(ssl->host);
|
||||
if (ssl->host)
|
||||
free(ssl->host);
|
||||
|
||||
if (ssl->key_file)
|
||||
{
|
||||
free(ssl->key_file);
|
||||
SSL_CTX_free(ssl->ctx);
|
||||
}
|
||||
if (ssl->key_file) {
|
||||
free(ssl->key_file);
|
||||
SSL_CTX_free(ssl->ctx);
|
||||
}
|
||||
|
||||
if (ssl->crt_file)
|
||||
free(ssl->crt_file);
|
||||
if (ssl->crt_file)
|
||||
free(ssl->crt_file);
|
||||
|
||||
free(ssl);
|
||||
free(ssl);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
42
src/ssl.h
42
src/ssl.h
|
@ -1,4 +1,17 @@
|
|||
/*
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file dummy.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*//*
|
||||
* src/ssl.h
|
||||
*
|
||||
* Copyright (C) 2019 Ilja Kartašov <ik@lowenware.com>
|
||||
|
@ -15,30 +28,27 @@
|
|||
#include <openssl/ssl.h>
|
||||
|
||||
|
||||
struct aisl_ssl
|
||||
{
|
||||
char * key_file;
|
||||
char * crt_file;
|
||||
char * host;
|
||||
SSL_CTX * ctx;
|
||||
struct aisl_ssl {
|
||||
char *key_file;
|
||||
char *crt_file;
|
||||
char *host;
|
||||
SSL_CTX *ctx;
|
||||
};
|
||||
|
||||
typedef struct aisl_ssl * aisl_ssl_t;
|
||||
|
||||
|
||||
aisl_ssl_t
|
||||
aisl_ssl_new( const char * key_file,
|
||||
const char * crt_file,
|
||||
const char * host,
|
||||
SSL_CTX * ctx );
|
||||
struct aisl_ssl *
|
||||
aisl_ssl_new( const char *key_file,
|
||||
const char *crt_file,
|
||||
const char *host,
|
||||
SSL_CTX *ctx );
|
||||
|
||||
|
||||
SSL_CTX *
|
||||
aisl_ssl_get_ctx(aisl_ssl_t ssl, void * p_instance);
|
||||
aisl_ssl_get_ctx(struct aisl_ssl *ssl, void *p_instance);
|
||||
|
||||
|
||||
void
|
||||
aisl_ssl_free( aisl_ssl_t ssl );
|
||||
aisl_ssl_free(struct aisl_ssl *ssl);
|
||||
|
||||
|
||||
#endif /* !AISL_SSL_H */
|
||||
|
|
|
@ -20,34 +20,33 @@
|
|||
|
||||
|
||||
char *
|
||||
str_copy(const char * source)
|
||||
str_copy(const char *source)
|
||||
{
|
||||
int l = strlen(source);
|
||||
int l = strlen(source);
|
||||
|
||||
char * result = malloc(l+1);
|
||||
char *result = malloc(l+1);
|
||||
|
||||
if (result)
|
||||
strcpy(result, source);
|
||||
if (result)
|
||||
strcpy(result, source);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
str_cmpi(const char * s1, const char * s2)
|
||||
str_cmpi(const char *s1, const char *s2)
|
||||
{
|
||||
char c1, c2, r = 0;
|
||||
char c1, c2, r = 0;
|
||||
|
||||
do
|
||||
{
|
||||
c1 = tolower(*(s1++));
|
||||
c2 = tolower(*(s2++));
|
||||
do {
|
||||
c1 = tolower(*(s1++));
|
||||
c2 = tolower(*(s2++));
|
||||
|
||||
if ((r = c1-c2) != 0)
|
||||
break;
|
||||
if ((r = c1-c2) != 0)
|
||||
break;
|
||||
|
||||
} while (c1 != 0);
|
||||
} while (c1 != 0);
|
||||
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
|
||||
|
||||
char *
|
||||
str_copy(const char * source);
|
||||
str_copy(const char *source);
|
||||
|
||||
int
|
||||
str_cmpi(const char * anycase, const char * lowcase);
|
||||
str_cmpi(const char *anycase, const char *lowcase);
|
||||
|
||||
#endif /* !STR_UTILS_H */
|
||||
|
|
731
src/stream.c
731
src/stream.c
|
@ -21,657 +21,580 @@
|
|||
/* Library level */
|
||||
|
||||
static void
|
||||
aisl_stream_reset(aisl_stream_t stream, bool initial)
|
||||
aisl_stream_reset(AislStream stream, bool initial)
|
||||
{
|
||||
if (!initial)
|
||||
{
|
||||
aisl_raise(
|
||||
aisl_stream_get_instance(stream)
|
||||
, (void*) stream
|
||||
, AISL_EVENT_STREAM_CLOSE
|
||||
, AISL_SUCCESS
|
||||
);
|
||||
}
|
||||
if (!initial) {
|
||||
aisl_raise(aisl_stream_get_instance(stream), (void*) stream,
|
||||
AISL_EVENT_STREAM_CLOSE, AISL_SUCCESS);
|
||||
}
|
||||
|
||||
buffer_release(&stream->buffer);
|
||||
buffer_release(&stream->buffer);
|
||||
|
||||
stream->u_ptr = NULL;
|
||||
stream->content_length = AISL_AUTO_LENGTH;
|
||||
stream->head_offset = 0;
|
||||
stream->flags = 0;
|
||||
stream->state = AISL_STREAM_STATE_IDLE;
|
||||
stream->http_response = AISL_HTTP_OK;
|
||||
stream->u_ptr = NULL;
|
||||
stream->content_length = AISL_AUTO_LENGTH;
|
||||
stream->head_offset = 0;
|
||||
stream->flags = 0;
|
||||
stream->state = AISL_STREAM_STATE_IDLE;
|
||||
stream->http_response = AISL_HTTP_OK;
|
||||
}
|
||||
|
||||
|
||||
aisl_stream_t
|
||||
aisl_stream_new(aisl_client_t client, int id)
|
||||
AislStream
|
||||
aisl_stream_new(AislClient client, int id)
|
||||
{
|
||||
aisl_stream_t stream = calloc(1, sizeof(struct aisl_stream));
|
||||
AislStream stream = calloc(1, sizeof (struct aisl_stream));
|
||||
|
||||
if (stream)
|
||||
{
|
||||
stream->id = id;
|
||||
stream->client = client;
|
||||
aisl_stream_reset(stream, true);
|
||||
}
|
||||
|
||||
return stream;
|
||||
if (stream) {
|
||||
stream->id = id;
|
||||
stream->client = client;
|
||||
aisl_stream_reset(stream, true);
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_free(aisl_stream_t stream)
|
||||
aisl_stream_free(AislStream stream)
|
||||
{
|
||||
aisl_stream_reset(stream, false);
|
||||
free(stream);
|
||||
aisl_stream_reset(stream, false);
|
||||
free(stream);
|
||||
}
|
||||
|
||||
|
||||
int32_t
|
||||
aisl_stream_get_buffer_space(aisl_stream_t stream)
|
||||
aisl_stream_get_buffer_space(AislStream stream)
|
||||
{
|
||||
return stream->buffer.size - stream->buffer.used;
|
||||
return stream->buffer.size - stream->buffer.used;
|
||||
}
|
||||
|
||||
|
||||
int32_t
|
||||
aisl_stream_get_buffer_size(aisl_stream_t stream)
|
||||
aisl_stream_get_buffer_size(AislStream stream)
|
||||
{
|
||||
return stream->buffer.size;
|
||||
return stream->buffer.size;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
aisl_stream_get_data(aisl_stream_t stream, int32_t * p_length)
|
||||
aisl_stream_get_data(AislStream stream, int32_t *p_length)
|
||||
{
|
||||
*p_length = stream->buffer.used;
|
||||
*p_length = stream->buffer.used;
|
||||
|
||||
return stream->buffer.data;
|
||||
return stream->buffer.data;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_shift(aisl_stream_t stream, int32_t offset)
|
||||
aisl_stream_shift(AislStream stream, int32_t offset)
|
||||
{
|
||||
buffer_shift(&stream->buffer, offset);
|
||||
buffer_shift(&stream->buffer, offset);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
aisl_stream_is_done(aisl_stream_t stream)
|
||||
aisl_stream_is_done(AislStream stream)
|
||||
{
|
||||
return (!stream->buffer.used && stream->state == AISL_STREAM_STATE_DONE);
|
||||
return (!stream->buffer.used && stream->state == AISL_STREAM_STATE_DONE);
|
||||
}
|
||||
|
||||
|
||||
aisl_stream_state_t
|
||||
aisl_stream_get_state(aisl_stream_t stream)
|
||||
AislStreamState
|
||||
aisl_stream_get_state(AislStream stream)
|
||||
{
|
||||
return stream->state;
|
||||
return stream->state;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_set_request( aisl_stream_t stream,
|
||||
aisl_http_method_t http_method,
|
||||
const char * path,
|
||||
const char * query )
|
||||
aisl_stream_set_request(AislStream stream,
|
||||
AislHttpMethod http_method,
|
||||
const char *path,
|
||||
const char *query)
|
||||
{
|
||||
struct aisl_evt_stream_open on_open;
|
||||
struct aisl_evt_open on_open;
|
||||
|
||||
stream->state = AISL_STREAM_STATE_WAIT_HEADER;
|
||||
stream->state = AISL_STREAM_STATE_WAIT_HEADER;
|
||||
|
||||
DPRINTF(
|
||||
"%s -> path: %s, query: %s"
|
||||
, aisl_http_method_to_string(http_method)
|
||||
, path
|
||||
, query
|
||||
);
|
||||
DPRINTF("%s -> path: %s, query: %s", aisl_http_method_to_string(http_method),
|
||||
path, query);
|
||||
|
||||
on_open.evt.code = AISL_EVENT_STREAM_OPEN;
|
||||
on_open.evt.source = (void *) stream;
|
||||
on_open.evt.status = AISL_SUCCESS;
|
||||
on_open.http_method = http_method;
|
||||
on_open.path = path;
|
||||
on_open.query = query;
|
||||
on_open.evt.code = AISL_EVENT_STREAM_OPEN;
|
||||
on_open.evt.source = (void *) stream;
|
||||
on_open.evt.status = AISL_SUCCESS;
|
||||
on_open.http_method = http_method;
|
||||
on_open.path = path;
|
||||
on_open.query = query;
|
||||
|
||||
aisl_raise_evt(aisl_stream_get_instance(stream), (aisl_evt_t)&on_open);
|
||||
aisl_raise_evt(aisl_stream_get_instance(stream), (struct aisl_evt *)&on_open);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_set_header( aisl_stream_t stream,
|
||||
const char * key,
|
||||
const char * value )
|
||||
aisl_stream_set_header(AislStream stream, const char *key, const char *value)
|
||||
{
|
||||
struct aisl_evt_stream_header on_header;
|
||||
struct aisl_evt_header on_header;
|
||||
|
||||
if (stream->state != AISL_STREAM_STATE_WAIT_HEADER)
|
||||
return;
|
||||
if (stream->state != AISL_STREAM_STATE_WAIT_HEADER)
|
||||
return;
|
||||
|
||||
if (strcmp(key, "content-length")==0)
|
||||
stream->content_length = strtoll(value, NULL, 10);
|
||||
else if (strcmp(key, "connection")==0)
|
||||
aisl_client_set_keepalive(
|
||||
stream->client
|
||||
, (str_cmpi(value, "close")==0) ? false : true
|
||||
);
|
||||
if (strcmp(key, "content-length") == 0) {
|
||||
stream->content_length = strtoll(value, NULL, 10);
|
||||
} else if (strcmp(key, "connection") == 0) {
|
||||
aisl_client_set_keepalive(stream->client,
|
||||
(str_cmpi(value, "close")==0) ? false : true);
|
||||
}
|
||||
|
||||
DPRINTF("%s: %s", key, value);
|
||||
DPRINTF("%s: %s", key, value);
|
||||
|
||||
on_header.evt.code = AISL_EVENT_STREAM_HEADER;
|
||||
on_header.evt.source = (void *) stream;
|
||||
on_header.evt.status = AISL_SUCCESS;
|
||||
on_header.key = key;
|
||||
on_header.value = value;
|
||||
on_header.evt.code = AISL_EVENT_STREAM_HEADER;
|
||||
on_header.evt.source = (void *) stream;
|
||||
on_header.evt.status = AISL_SUCCESS;
|
||||
on_header.key = key;
|
||||
on_header.value = value;
|
||||
|
||||
aisl_raise_evt(aisl_stream_get_instance(stream), (aisl_evt_t)&on_header);
|
||||
aisl_raise_evt(aisl_stream_get_instance(stream),
|
||||
(struct aisl_evt *) &on_header);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
aisl_stream_set_end_of_headers( aisl_stream_t stream )
|
||||
aisl_stream_set_end_of_headers(AislStream stream)
|
||||
{
|
||||
int result;
|
||||
int result;
|
||||
|
||||
if (stream->state == AISL_STREAM_STATE_WAIT_HEADER)
|
||||
{
|
||||
stream->state = AISL_STREAM_STATE_WAIT_BODY;
|
||||
result = (stream->content_length == 0);
|
||||
}
|
||||
else
|
||||
result = 2;
|
||||
|
||||
return result;
|
||||
if (stream->state == AISL_STREAM_STATE_WAIT_HEADER) {
|
||||
stream->state = AISL_STREAM_STATE_WAIT_BODY;
|
||||
result = (stream->content_length == 0);
|
||||
} else {
|
||||
result = 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
aisl_stream_set_body( aisl_stream_t stream, const char * data, int32_t size )
|
||||
aisl_stream_set_body(AislStream stream, const char *data, int32_t size)
|
||||
{
|
||||
int result;
|
||||
if (stream->state == AISL_STREAM_STATE_WAIT_BODY)
|
||||
{
|
||||
if ( !(stream->content_length < size) )
|
||||
{
|
||||
struct aisl_evt_stream_input on_input;
|
||||
int result;
|
||||
if (stream->state == AISL_STREAM_STATE_WAIT_BODY) {
|
||||
if (!(stream->content_length < size)) {
|
||||
struct aisl_evt_input on_input;
|
||||
|
||||
if (stream->content_length == 0)
|
||||
{
|
||||
stream->state = AISL_STREAM_STATE_READY;
|
||||
result = 0;
|
||||
}
|
||||
else
|
||||
result = 1;
|
||||
if (stream->content_length == 0) {
|
||||
stream->state = AISL_STREAM_STATE_READY;
|
||||
result = 0;
|
||||
} else {
|
||||
result = 1;
|
||||
}
|
||||
|
||||
on_input.evt.code = AISL_EVENT_STREAM_INPUT;
|
||||
on_input.evt.source = (void *) stream;
|
||||
on_input.evt.status = AISL_SUCCESS;
|
||||
on_input.data = data;
|
||||
on_input.size = size;
|
||||
on_input.evt.code = AISL_EVENT_STREAM_INPUT;
|
||||
on_input.evt.source = (void *) stream;
|
||||
on_input.evt.status = AISL_SUCCESS;
|
||||
on_input.data = data;
|
||||
on_input.size = size;
|
||||
|
||||
aisl_raise_evt(stream->client->server->instance, (aisl_evt_t)&on_input);
|
||||
}
|
||||
else
|
||||
result = -1;
|
||||
}
|
||||
else
|
||||
result = 2;
|
||||
|
||||
return result;
|
||||
aisl_raise_evt(stream->client->server->instance,
|
||||
(struct aisl_evt *) &on_input);
|
||||
} else {
|
||||
result = -1;
|
||||
}
|
||||
} else {
|
||||
result = 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* API Level */
|
||||
|
||||
/* Why it was here?
|
||||
static int
|
||||
aisl_stream_write(aisl_stream_t stream, const char * data, uint32_t d_len)
|
||||
aisl_stream_write(AislStream stream, const char * data, uint32_t d_len)
|
||||
{
|
||||
return buffer_add( &stream->buffer, data, d_len);
|
||||
return buffer_add( &stream->buffer, data, d_len);
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_cancel(aisl_stream_t stream)
|
||||
aisl_cancel(AislStream stream)
|
||||
{
|
||||
aisl_client_close( stream->client );
|
||||
aisl_client_close( stream->client );
|
||||
}
|
||||
*/
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void *
|
||||
aisl_get_context(aisl_stream_t s)
|
||||
aisl_get_context(AislStream s)
|
||||
{
|
||||
return s->u_ptr;
|
||||
return s->u_ptr;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_set_context(aisl_stream_t s, void * u_ptr)
|
||||
aisl_set_context(AislStream s, void *u_ptr)
|
||||
{
|
||||
s->u_ptr = u_ptr;
|
||||
s->u_ptr = u_ptr;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_client_t
|
||||
aisl_get_client(aisl_stream_t s)
|
||||
AislClient
|
||||
aisl_get_client(AislStream s)
|
||||
{
|
||||
return s->client;
|
||||
return s->client;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_server_t
|
||||
aisl_get_server(aisl_stream_t s)
|
||||
AislServer
|
||||
aisl_get_server(AislStream s)
|
||||
{
|
||||
return aisl_client_get_server(s->client);
|
||||
return aisl_client_get_server(s->client);
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_http_version_t
|
||||
aisl_get_http_version(aisl_stream_t s)
|
||||
AislHttpVersion
|
||||
aisl_get_http_version(AislStream s)
|
||||
{
|
||||
return aisl_client_get_http_version(s->client);
|
||||
return aisl_client_get_http_version(s->client);
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_reject(aisl_stream_t s)
|
||||
aisl_reject(AislStream s)
|
||||
{
|
||||
aisl_client_disconnect( s->client );
|
||||
aisl_client_disconnect( s->client );
|
||||
}
|
||||
|
||||
|
||||
static aisl_status_t
|
||||
aisl_start_response(aisl_stream_t stream)
|
||||
static AislStatus
|
||||
aisl_start_response(AislStream stream)
|
||||
{
|
||||
return aisl_response( stream
|
||||
, AISL_HTTP_OK
|
||||
, AISL_AUTO_LENGTH );
|
||||
return aisl_response(stream, AISL_HTTP_OK, AISL_AUTO_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
static aisl_status_t
|
||||
aisl_stream_close_headers(aisl_stream_t stream)
|
||||
static AislStatus
|
||||
aisl_stream_close_headers(AislStream stream)
|
||||
{
|
||||
int32_t l;
|
||||
int32_t l;
|
||||
|
||||
if (aisl_start_response(stream) == AISL_MALLOC_ERROR)
|
||||
return AISL_MALLOC_ERROR;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
if (!(stream->flags & FLAG_CONTENT_TYPE_HEADER_SENT)) {
|
||||
l = buffer_append(&stream->buffer,
|
||||
"Content-type: text/html; encoding=utf-8\r\n", 41);
|
||||
|
||||
stream->flags |= FLAG_CONTENT_TYPE_HEADER_SENT;
|
||||
}
|
||||
if (l == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
|
||||
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_TYPE_HEADER_SENT;
|
||||
}
|
||||
|
||||
stream->flags |= FLAG_CONTENT_LENGTH_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 (!(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;
|
||||
if (l == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
|
||||
stream->flags |= FLAG_CONNECTION_HEADER_SENT;
|
||||
}
|
||||
stream->flags |= FLAG_CONTENT_LENGTH_HEADER_SENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer_append( &stream->buffer, "\r\n", 2 ) == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
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"));
|
||||
|
||||
stream->body_offset = stream->buffer.used;
|
||||
if (l == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
|
||||
stream->state = AISL_STREAM_STATE_SEND_BODY;
|
||||
stream->flags |= FLAG_CONNECTION_HEADER_SENT;
|
||||
}
|
||||
|
||||
return AISL_SUCCESS;
|
||||
if (buffer_append( &stream->buffer, "\r\n", 2 ) == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
|
||||
stream->body_offset = stream->buffer.used;
|
||||
stream->state = AISL_STREAM_STATE_SEND_BODY;
|
||||
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_status_t
|
||||
aisl_response( aisl_stream_t stream
|
||||
, aisl_http_response_t status_code
|
||||
, uint64_t content_length )
|
||||
AislStatus
|
||||
aisl_response(AislStream stream, AislHttpResponse rs_code, uint64_t c_len)
|
||||
{
|
||||
int32_t l;
|
||||
int32_t l;
|
||||
|
||||
/* check if those headers were already sent */
|
||||
if (stream->state > AISL_STREAM_STATE_READY) return AISL_IDLE;
|
||||
/* check if those headers were already sent */
|
||||
if (stream->state > AISL_STREAM_STATE_READY)
|
||||
return AISL_IDLE;
|
||||
|
||||
stream->http_response = status_code;
|
||||
stream->content_length = content_length;
|
||||
stream->http_response = rs_code;
|
||||
stream->content_length = c_len;
|
||||
|
||||
buffer_init( &stream->buffer
|
||||
, (content_length != AISL_AUTO_LENGTH) ? content_length : 0);
|
||||
buffer_init(&stream->buffer, (c_len != AISL_AUTO_LENGTH) ? c_len : 0);
|
||||
|
||||
l = buffer_append_printf(
|
||||
&stream->buffer
|
||||
, "%s %d %s\r\n"
|
||||
, aisl_http_version_to_string(stream->client->http_version)
|
||||
, status_code
|
||||
, aisl_http_response_to_string(status_code)
|
||||
);
|
||||
l = buffer_append_printf(&stream->buffer, "%s %d %s\r\n",
|
||||
aisl_http_version_to_string(stream->client->http_version), rs_code,
|
||||
aisl_http_response_to_string(rs_code));
|
||||
|
||||
if ( l == -1 )
|
||||
return AISL_MALLOC_ERROR;
|
||||
if (l == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
|
||||
stream->head_offset = l;
|
||||
stream->head_offset = l;
|
||||
stream->state = AISL_STREAM_STATE_SEND_HEADER;
|
||||
|
||||
stream->state = AISL_STREAM_STATE_SEND_HEADER;
|
||||
|
||||
return AISL_SUCCESS;
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_status_t
|
||||
aisl_flush(aisl_stream_t s)
|
||||
AislStatus
|
||||
aisl_flush(AislStream s)
|
||||
{
|
||||
if (!(s->flags & FLAG_CONTENT_LENGTH_HEADER_SENT))
|
||||
{
|
||||
char hdr[ 40 ];
|
||||
if (!(s->flags & FLAG_CONTENT_LENGTH_HEADER_SENT)) {
|
||||
char hdr[ 40 ];
|
||||
uint64_t c_len = s->buffer.used - s->body_offset;
|
||||
int32_t l;
|
||||
|
||||
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);
|
||||
|
||||
l = snprintf(hdr, sizeof(hdr), "Content-length: %"PRIu64"\r\n", c_len);
|
||||
if (l == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
|
||||
l = buffer_insert( &s->buffer
|
||||
, s->body_offset - 2
|
||||
, hdr
|
||||
, l );
|
||||
s->flags |= FLAG_CONTENT_LENGTH_HEADER_SENT;
|
||||
}
|
||||
|
||||
if (l == -1)
|
||||
return AISL_MALLOC_ERROR;
|
||||
s->state = AISL_STREAM_STATE_DONE;
|
||||
s->flags |= FLAG_FLUSHED;
|
||||
|
||||
s->flags |= FLAG_CONTENT_LENGTH_HEADER_SENT;
|
||||
}
|
||||
|
||||
s->state = AISL_STREAM_STATE_DONE;
|
||||
s->flags |= FLAG_FLUSHED;
|
||||
|
||||
return AISL_SUCCESS;
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int32_t
|
||||
aisl_stream_verify_header( aisl_stream_t stream,
|
||||
const char * key,
|
||||
const char * value )
|
||||
aisl_stream_verify_header(AislStream 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->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_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_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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int32_t
|
||||
aisl_header(aisl_stream_t stream, const char *key, const char *value)
|
||||
aisl_header(AislStream stream, const char *key, const char *value)
|
||||
{
|
||||
int32_t result;
|
||||
int32_t result;
|
||||
|
||||
if ( (result = aisl_stream_verify_header( stream, key, value )) != 1)
|
||||
return result;
|
||||
if ( (result = aisl_stream_verify_header( stream, key, value )) != 1)
|
||||
return result;
|
||||
|
||||
result = buffer_append_printf( &stream->buffer
|
||||
, "%s: %s\r\n"
|
||||
, key
|
||||
, value );
|
||||
result = buffer_append_printf(&stream->buffer, "%s: %s\r\n", key, value);
|
||||
|
||||
return result;
|
||||
|
||||
return result;
|
||||
/* For debug purposes
|
||||
if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL )
|
||||
{
|
||||
ret = strlen(pch);
|
||||
if ( buffer_insert(
|
||||
&stream->buffer,
|
||||
stream->end_of_headers,
|
||||
pch,
|
||||
ret
|
||||
) == -1 )
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
stream->end_of_headers += ret;
|
||||
|
||||
/* For debug purposes
|
||||
if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL )
|
||||
{
|
||||
ret = strlen(pch);
|
||||
if ( buffer_insert(
|
||||
&stream->buffer,
|
||||
stream->end_of_headers,
|
||||
pch,
|
||||
ret
|
||||
) == -1 )
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
stream->end_of_headers += ret;
|
||||
free(pch);
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
|
||||
free(pch);
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
*/
|
||||
return ret;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int32_t
|
||||
aisl_header_printf(aisl_stream_t stream, const char *key,
|
||||
const char *format, ...)
|
||||
aisl_header_printf(AislStream stream, const char *key, const char *format, ...)
|
||||
{
|
||||
int32_t result;
|
||||
int32_t result;
|
||||
va_list args;
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
va_start(args, format);
|
||||
result = aisl_header_vprintf( stream, key, format, args );
|
||||
va_end(args);
|
||||
|
||||
result = aisl_header_vprintf( stream, key, format, args );
|
||||
|
||||
va_end(args);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int32_t
|
||||
aisl_header_vprintf(aisl_stream_t stream, const char *key,
|
||||
const char *format,
|
||||
va_list args)
|
||||
aisl_header_vprintf(AislStream stream,
|
||||
const char *key,
|
||||
const char *format,
|
||||
va_list args)
|
||||
{
|
||||
int32_t result,
|
||||
l;
|
||||
int32_t result, l;
|
||||
|
||||
if ( (result = aisl_stream_verify_header( stream, key, NULL )) != 1)
|
||||
return result;
|
||||
if ( (result = aisl_stream_verify_header( stream, key, NULL )) != 1)
|
||||
return result;
|
||||
|
||||
result = buffer_append_printf( &stream->buffer, "%s: ", key );
|
||||
result = buffer_append_printf( &stream->buffer, "%s: ", key );
|
||||
|
||||
if (result != -1)
|
||||
{
|
||||
l = buffer_append_vprintf( &stream->buffer, format, args );
|
||||
if (result != -1) {
|
||||
l = buffer_append_vprintf( &stream->buffer, format, args );
|
||||
|
||||
if (l != -1)
|
||||
{
|
||||
result += l;
|
||||
if ((l = buffer_append(&stream->buffer, "\r\n", 2)) != -1)
|
||||
{
|
||||
result += l;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
if (l != -1) {
|
||||
result += l;
|
||||
if ((l = buffer_append(&stream->buffer, "\r\n", 2)) != -1) {
|
||||
result += l;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_printf(aisl_stream_t stream, const char *format, ...)
|
||||
aisl_printf(AislStream stream, const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int result;
|
||||
va_list arg;
|
||||
|
||||
int result = aisl_vprintf(stream, format, arg);
|
||||
|
||||
va_end(arg);
|
||||
|
||||
/* No need to update length there, because vprintf do that
|
||||
*
|
||||
* if (stream->c_length_unknown)
|
||||
stream->c_length += result;
|
||||
*/
|
||||
|
||||
|
||||
return result;
|
||||
va_start(arg, format);
|
||||
result = aisl_vprintf(stream, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int32_t
|
||||
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
|
||||
aisl_vprintf(AislStream stream, const char *format, va_list args)
|
||||
{
|
||||
if (stream->state < AISL_STREAM_STATE_SEND_BODY)
|
||||
{
|
||||
if (aisl_stream_close_headers(stream) != AISL_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
return buffer_append_vprintf(&stream->buffer, format, args);
|
||||
if (stream->state < AISL_STREAM_STATE_SEND_BODY) {
|
||||
if (aisl_stream_close_headers(stream) != AISL_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
return buffer_append_vprintf(&stream->buffer, format, args);
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int32_t
|
||||
aisl_write(aisl_stream_t stream, const char *data, int32_t d_len)
|
||||
aisl_write(AislStream stream, const char *data, int32_t d_len)
|
||||
{
|
||||
if (stream->state < AISL_STREAM_STATE_SEND_BODY)
|
||||
{
|
||||
if (aisl_stream_close_headers(stream) != AISL_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
if (d_len == -1)
|
||||
d_len = strlen(data);
|
||||
if (stream->state < AISL_STREAM_STATE_SEND_BODY) {
|
||||
if (aisl_stream_close_headers(stream) != AISL_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return buffer_append(&stream->buffer, data, d_len);
|
||||
if (d_len == -1)
|
||||
d_len = strlen(data);
|
||||
|
||||
return buffer_append(&stream->buffer, data, d_len);
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_puts(const char *str, aisl_stream_t stream)
|
||||
aisl_puts(const char *str, AislStream stream)
|
||||
{
|
||||
if (stream->state < AISL_STREAM_STATE_SEND_BODY)
|
||||
{
|
||||
if (aisl_stream_close_headers(stream) != AISL_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
return aisl_write( stream, str, -1);
|
||||
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)
|
||||
AislInstance
|
||||
aisl_stream_get_instance(AislStream stream)
|
||||
{
|
||||
return stream->client->server->instance;
|
||||
return stream->client->server->instance;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_set_output_event(aisl_stream_t stream, bool value)
|
||||
aisl_set_output_event(AislStream stream, bool value)
|
||||
{
|
||||
if (value)
|
||||
stream->flags |= FLAG_OUTPUT_CHUNKED;
|
||||
else if (stream->flags & FLAG_OUTPUT_CHUNKED)
|
||||
stream->flags &= ~FLAG_OUTPUT_CHUNKED;
|
||||
if (value)
|
||||
stream->flags |= FLAG_OUTPUT_CHUNKED;
|
||||
else if (stream->flags & FLAG_OUTPUT_CHUNKED)
|
||||
stream->flags &= ~FLAG_OUTPUT_CHUNKED;
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
bool
|
||||
aisl_get_output_event(aisl_stream_t stream)
|
||||
aisl_get_output_event(AislStream stream)
|
||||
{
|
||||
return (stream->flags & FLAG_OUTPUT_CHUNKED);
|
||||
return (stream->flags & FLAG_OUTPUT_CHUNKED);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
92
src/stream.h
92
src/stream.h
|
@ -1,96 +1,106 @@
|
|||
#ifndef AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file dummy.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/#ifndef AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
|
||||
#define AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
|
||||
|
||||
#include <aisl/types.h>
|
||||
#include <aisl/stream.h>
|
||||
#include "buffer.h"
|
||||
|
||||
#define AISL_STREAM(x) ((aisl_stream_t) x)
|
||||
#define AISL_STREAM(x) ((AislStream) x)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AISL_STREAM_STATE_IDLE
|
||||
AISL_STREAM_STATE_IDLE
|
||||
|
||||
, AISL_STREAM_STATE_WAIT_HEADER
|
||||
, AISL_STREAM_STATE_WAIT_BODY
|
||||
, AISL_STREAM_STATE_WAIT_HEADER
|
||||
, AISL_STREAM_STATE_WAIT_BODY
|
||||
|
||||
, AISL_STREAM_STATE_READY
|
||||
, AISL_STREAM_STATE_READY
|
||||
|
||||
, AISL_STREAM_STATE_SEND_HEADER
|
||||
, AISL_STREAM_STATE_SEND_BODY
|
||||
, AISL_STREAM_STATE_SEND_HEADER
|
||||
, AISL_STREAM_STATE_SEND_BODY
|
||||
|
||||
, AISL_STREAM_STATE_DONE
|
||||
, AISL_STREAM_STATE_DONE
|
||||
|
||||
} aisl_stream_state_t;
|
||||
} AislStreamState;
|
||||
|
||||
|
||||
struct aisl_stream
|
||||
{
|
||||
struct buffer buffer;
|
||||
aisl_client_t client;
|
||||
struct aisl_stream {
|
||||
struct buffer buffer;
|
||||
AislClient client;
|
||||
|
||||
void * u_ptr;
|
||||
void *u_ptr;
|
||||
|
||||
uint64_t content_length;
|
||||
int32_t head_offset;
|
||||
int32_t body_offset;
|
||||
int id;
|
||||
int flags;
|
||||
uint64_t content_length;
|
||||
int32_t head_offset;
|
||||
int32_t body_offset;
|
||||
int id;
|
||||
int flags;
|
||||
|
||||
aisl_http_response_t http_response;
|
||||
aisl_stream_state_t state;
|
||||
AislHttpResponse http_response;
|
||||
AislStreamState state;
|
||||
};
|
||||
|
||||
|
||||
aisl_stream_t
|
||||
aisl_stream_new(aisl_client_t client, int id );
|
||||
AislStream
|
||||
aisl_stream_new(AislClient client, int id);
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_free(aisl_stream_t stream);
|
||||
aisl_stream_free(AislStream stream);
|
||||
|
||||
|
||||
int32_t
|
||||
aisl_stream_get_buffer_space(aisl_stream_t stream);
|
||||
aisl_stream_get_buffer_space(AislStream stream);
|
||||
|
||||
|
||||
int32_t
|
||||
aisl_stream_get_buffer_size(aisl_stream_t stream);
|
||||
aisl_stream_get_buffer_size(AislStream stream);
|
||||
|
||||
|
||||
char *
|
||||
aisl_stream_get_data(aisl_stream_t stream, int32_t * p_length);
|
||||
aisl_stream_get_data(AislStream stream, int32_t *p_length);
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_shift(aisl_stream_t stream, int32_t offset);
|
||||
aisl_stream_shift(AislStream stream, int32_t offset);
|
||||
|
||||
|
||||
bool
|
||||
aisl_stream_is_done(aisl_stream_t stream);
|
||||
aisl_stream_is_done(AislStream stream);
|
||||
|
||||
|
||||
aisl_stream_state_t
|
||||
aisl_stream_get_state(aisl_stream_t stream);
|
||||
AislStreamState
|
||||
aisl_stream_get_state(AislStream stream);
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_set_request( aisl_stream_t stream,
|
||||
aisl_http_method_t http_method,
|
||||
const char * path,
|
||||
const char * query );
|
||||
aisl_stream_set_request(AislStream stream,
|
||||
AislHttpMethod http_method,
|
||||
const char *path,
|
||||
const char *query );
|
||||
|
||||
void
|
||||
aisl_stream_set_header( aisl_stream_t stream,
|
||||
const char * key,
|
||||
const char * value );
|
||||
aisl_stream_set_header(AislStream stream, const char *key, const char *value);
|
||||
|
||||
|
||||
int
|
||||
aisl_stream_set_end_of_headers( aisl_stream_t stream );
|
||||
aisl_stream_set_end_of_headers(AislStream stream);
|
||||
|
||||
|
||||
int
|
||||
aisl_stream_set_body( aisl_stream_t stream, const char * data, int32_t size );
|
||||
aisl_stream_set_body(AislStream stream, const char *data, int32_t size);
|
||||
|
||||
#endif /* !AISL_STREAM_H */
|
||||
|
|
52
src/types.c
52
src/types.c
|
@ -20,41 +20,39 @@
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
const char *
|
||||
aisl_status_to_string(aisl_status_t status)
|
||||
aisl_status_to_string(AislStatus status)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case AISL_INPUT_ERROR: return "AISL_INPUT_ERROR";
|
||||
case AISL_EXTCALL_ERROR: return "AISL_EXTCALL_ERROR";
|
||||
case AISL_SYSCALL_ERROR: return "AISL_SYSCALL_ERROR";
|
||||
case AISL_MALLOC_ERROR: return "AISL_MALLOC_ERROR";
|
||||
case AISL_SUCCESS: return "AISL_SUCCESS";
|
||||
case AISL_IDLE: return "AISL_IDLE";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
switch(status) {
|
||||
case AISL_INPUT_ERROR: return "AISL_INPUT_ERROR";
|
||||
case AISL_EXTCALL_ERROR: return "AISL_EXTCALL_ERROR";
|
||||
case AISL_SYSCALL_ERROR: return "AISL_SYSCALL_ERROR";
|
||||
case AISL_MALLOC_ERROR: return "AISL_MALLOC_ERROR";
|
||||
case AISL_SUCCESS: return "AISL_SUCCESS";
|
||||
case AISL_IDLE: return "AISL_IDLE";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
const char *
|
||||
aisl_evt_code_to_string( aisl_evt_code_t evt_code )
|
||||
aisl_event_to_string(AislEvent evt_code)
|
||||
{
|
||||
switch(evt_code)
|
||||
{
|
||||
case AISL_EVENT_SERVER_OPEN: return "SERVER OPEN";
|
||||
case AISL_EVENT_SERVER_ERROR: return "SERVER ERROR";
|
||||
case AISL_EVENT_CLIENT_CONNECT: return "CLIENT CONNECT";
|
||||
case AISL_EVENT_CLIENT_DISCONNECT: return "CLIENT DISCONNECT";
|
||||
case AISL_EVENT_STREAM_OPEN: return "STREAM OPEN";
|
||||
case AISL_EVENT_STREAM_HEADER: return "STREAM HEADER";
|
||||
case AISL_EVENT_STREAM_INPUT: return "STREAM INPUT";
|
||||
case AISL_EVENT_STREAM_REQUEST: return "STREAM REQUEST";
|
||||
case AISL_EVENT_STREAM_OUTPUT: return "STREAM OUTPUT";
|
||||
case AISL_EVENT_STREAM_CLOSE: return "STREAM CLOSE";
|
||||
case AISL_EVENT_STREAM_ERROR: return "STREAM ERROR";
|
||||
}
|
||||
switch(evt_code) {
|
||||
case AISL_EVENT_SERVER_READY: return "SERVER READY";
|
||||
case AISL_EVENT_SERVER_ERROR: return "SERVER ERROR";
|
||||
case AISL_EVENT_CLIENT_CONNECT: return "CLIENT CONNECT";
|
||||
case AISL_EVENT_CLIENT_DISCONNECT: return "CLIENT DISCONNECT";
|
||||
case AISL_EVENT_STREAM_OPEN: return "STREAM OPEN";
|
||||
case AISL_EVENT_STREAM_HEADER: return "STREAM HEADER";
|
||||
case AISL_EVENT_STREAM_INPUT: return "STREAM INPUT";
|
||||
case AISL_EVENT_STREAM_REQUEST: return "STREAM REQUEST";
|
||||
case AISL_EVENT_STREAM_OUTPUT: return "STREAM OUTPUT";
|
||||
case AISL_EVENT_STREAM_CLOSE: return "STREAM CLOSE";
|
||||
case AISL_EVENT_STREAM_ERROR: return "STREAM ERROR";
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue