Documentation and code base update
This commit is contained in:
parent
3efc86a341
commit
0b05984f85
|
@ -16,6 +16,7 @@ tmp/*
|
||||||
*.gz
|
*.gz
|
||||||
*.bz2
|
*.bz2
|
||||||
pkg/*
|
pkg/*
|
||||||
|
doc/html
|
||||||
|
|
||||||
include/webstuff_bak
|
include/webstuff_bak
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,21 @@
|
||||||
|
<!-- HTML footer for doxygen 1.8.14-->
|
||||||
|
<!-- start footer part -->
|
||||||
|
<!--BEGIN GENERATE_TREEVIEW-->
|
||||||
|
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
||||||
|
<ul>
|
||||||
|
$navpath
|
||||||
|
<li class="footer">$generatedby
|
||||||
|
<a href="http://www.doxygen.org/index.html">
|
||||||
|
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<!--END GENERATE_TREEVIEW-->
|
||||||
|
<!--BEGIN !GENERATE_TREEVIEW-->
|
||||||
|
<hr class="footer"/><address class="footer"><small>
|
||||||
|
$generatedby  <a href="http://www.doxygen.org/index.html">
|
||||||
|
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
|
||||||
|
</a> $doxygenversion
|
||||||
|
</small></address>
|
||||||
|
<!--END !GENERATE_TREEVIEW-->
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,56 @@
|
||||||
|
<!-- HTML header for doxygen 1.8.14-->
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||||
|
<meta name="generator" content="Doxygen $doxygenversion"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
||||||
|
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||||
|
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||||
|
$treeview
|
||||||
|
$search
|
||||||
|
$mathjax
|
||||||
|
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||||
|
$extrastylesheet
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
|
||||||
|
<!--BEGIN TITLEAREA-->
|
||||||
|
<div id="titlearea">
|
||||||
|
<table cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr style="height: 56px;">
|
||||||
|
<!--BEGIN PROJECT_LOGO-->
|
||||||
|
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
||||||
|
<!--END PROJECT_LOGO-->
|
||||||
|
<!--BEGIN PROJECT_NAME-->
|
||||||
|
<td id="projectalign" style="padding-left: 0.5em;">
|
||||||
|
<div id="projectname">$projectname
|
||||||
|
<!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
|
||||||
|
</div>
|
||||||
|
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME-->
|
||||||
|
<!--BEGIN PROJECT_BRIEF-->
|
||||||
|
<td style="padding-left: 0.5em;">
|
||||||
|
<div id="projectbrief">$projectbrief</div>
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_BRIEF-->
|
||||||
|
<!--END !PROJECT_NAME-->
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN SEARCHENGINE-->
|
||||||
|
<td>$searchbox</td>
|
||||||
|
<!--END SEARCHENGINE-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--END TITLEAREA-->
|
||||||
|
<!-- end header part -->
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/**
|
||||||
* <aisl/server.h>
|
* @file aisl/client.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||||
*
|
*
|
||||||
|
@ -12,4 +12,48 @@
|
||||||
|
|
||||||
#include <aisl/types.h>
|
#include <aisl/types.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets #aisl_server_t instance associated with client.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
|
* @return an associated #aisl_server_t pointer.
|
||||||
|
*/
|
||||||
|
aisl_server_t
|
||||||
|
aisl_client_get_server(aisl_client_t client);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets security connection status.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
|
* @return true if SSL is enabled and false if disabled.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
aisl_client_is_secure(aisl_client_t client);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets client's connection state.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
|
* @return true if client is online and false if is offline.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
aisl_client_is_online(aisl_client_t client);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Forcefully closes client's connection.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
aisl_client_close(aisl_client_t client);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets HTTP protocol version.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
|
* @return HTTP protocol version
|
||||||
|
*/
|
||||||
|
aisl_http_version_t
|
||||||
|
aisl_client_get_http_version(aisl_client_t client);
|
||||||
|
|
||||||
#endif /* !AISL_CLIENT_H */
|
#endif /* !AISL_CLIENT_H */
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
|
|
||||||
struct aisl_config
|
struct aisl_config
|
||||||
{
|
{
|
||||||
uint32_t servers_spool_size;
|
uint32_t server_spool_size;
|
||||||
uint32_t clients_spool_size;
|
uint32_t client_spool_size;
|
||||||
uint32_t ssl_spool_size;
|
uint32_t ssl_spool_size;
|
||||||
uint32_t callbacks_spool_size;
|
uint32_t callback_spool_size;
|
||||||
uint32_t initial_buffer_size;
|
uint32_t initial_buffer_size;
|
||||||
uint32_t clients_accept_limit;
|
uint32_t client_accept_limit;
|
||||||
|
uint32_t client_silence_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct aisl_config * aisl_config_t;
|
typedef struct aisl_config * aisl_config_t;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/**
|
||||||
* <aisl/instance.h>
|
* @file aisl/instance.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||||
*
|
*
|
||||||
|
@ -17,32 +17,70 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialization functions */
|
/**
|
||||||
|
* @brief Allocates new AISL instance.
|
||||||
|
*
|
||||||
|
* @param config a pointer to #aisl_config structure.
|
||||||
|
* @return an #aisl_t instance pointer.
|
||||||
|
*/
|
||||||
aisl_t
|
aisl_t
|
||||||
aisl_new( aisl_config_t config );
|
aisl_new( aisl_config_t config );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Frees previously allocated pointer of AISL instance.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
aisl_free( aisl_t instance );
|
aisl_free( aisl_t instance );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocates and registers HTTP server instance.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param address a null-terminated ip or hostname string.
|
||||||
|
* @param port a number of port to listen.
|
||||||
|
* @return a pointer representing HTTP server.
|
||||||
|
*/
|
||||||
aisl_server_t
|
aisl_server_t
|
||||||
aisl_listen( aisl_t instance, const char * address, uint16_t port );
|
aisl_listen( aisl_t instance, const char * address, uint16_t port );
|
||||||
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#ifndef AISL_WITHOUT_SSL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets pair of SSL certificate and key for domain name.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param domain a null-terminated string with domain name.
|
||||||
|
* @param key_file a null-terminated string with path to private SSL key file.
|
||||||
|
* @param crt_file a null-terminated string with path to SSL certificate file.
|
||||||
|
* @return #aisl_status_t code.
|
||||||
|
*/
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_set_ssl( aisl_t instance,
|
aisl_set_ssl( aisl_t instance,
|
||||||
const char * hostname,
|
const char * domain,
|
||||||
const char * key_file,
|
const char * key_file,
|
||||||
const char * crt_file );
|
const char * crt_file );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Callbacks and Events functions */
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Registers a callback for event and its source.
|
||||||
|
* If source is NULL, then callback will be executed for all events of specified
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
* Typical sources are:
|
||||||
|
* - #aisl_server_t,
|
||||||
|
* - #aisl_client_t,
|
||||||
|
* - #aisl_stream_t;
|
||||||
|
*
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param source a pointer to an event source.
|
||||||
|
* @param event a code of event.
|
||||||
|
* @param callback a pointer to function that will be triggered on event.
|
||||||
|
* @return #aisl_status_t code.
|
||||||
|
*/
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_set_callback( aisl_t instance,
|
aisl_set_callback( aisl_t instance,
|
||||||
void * source,
|
void * source,
|
||||||
|
@ -50,33 +88,69 @@ aisl_set_callback( aisl_t instance,
|
||||||
aisl_callback_t callback );
|
aisl_callback_t callback );
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
/**
|
||||||
|
* @brief Raises event from source.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param source a pointer to an event source.
|
||||||
|
* @param event a code of event.
|
||||||
|
* @param ... a list of arguments specific for event.
|
||||||
|
* @return true if event was handled by at least one callback, false otherwise.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
aisl_raise( aisl_t instance, void * source, aisl_event_t event, ... );
|
aisl_raise( aisl_t instance, void * source, aisl_event_t event, ... );
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
/**
|
||||||
|
* @brief Raises event from source.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param source a pointer to an event source.
|
||||||
|
* @param event a code of event.
|
||||||
|
* @param args a list of arguments specific for event.
|
||||||
|
* @return true if event was handled by at least one callback, false otherwise.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
aisl_raise_vl( aisl_t instance,
|
aisl_raise_vl( aisl_t instance,
|
||||||
void * source,
|
void * source,
|
||||||
aisl_event_t event,
|
aisl_event_t event,
|
||||||
va_list args );
|
va_list args );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unsets callbacks for specified source.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param source a pointer to an event source.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
aisl_unset_callback_for( aisl_t instance, void * source );
|
aisl_unset_callbacks_for( aisl_t instance, void * source );
|
||||||
|
|
||||||
|
|
||||||
/* Control functions */
|
/**
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_run_cycle( aisl_t instance );
|
aisl_run_cycle( aisl_t instance );
|
||||||
|
|
||||||
|
|
||||||
const char *
|
/**
|
||||||
aisl_get_error( aisl_t 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 usec a number of miliseconds to wait for any data on sockets.
|
||||||
|
* @return #aisl_status_t code.
|
||||||
|
*/
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_sleep( aisl_t instance, uint32_t usec );
|
aisl_sleep( aisl_t instance, uint32_t usec );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get last error message.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @return a null-terminated string with error message.
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
aisl_get_error( aisl_t instance );
|
||||||
|
|
||||||
#endif /* !AISL_INSTANCE_H */
|
#endif /* !AISL_INSTANCE_H */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/**
|
||||||
* <aisl/server.h>
|
* @file aisl/server.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||||
*
|
*
|
||||||
|
@ -10,14 +10,46 @@
|
||||||
#ifndef AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768
|
#ifndef AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768
|
||||||
#define AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768
|
#define AISL_SERVER_H_CC564608_7A05_4B31_9E7E_32750BC60768
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <aisl/types.h>
|
#include <aisl/types.h>
|
||||||
#ifdef AISL_WITH_SSL
|
|
||||||
|
|
||||||
aisl_status_t
|
/**
|
||||||
|
* @brief Function to get appropriate AISL instance pointer from server pointer.
|
||||||
|
* @param server an #aisl_server_t pointer.
|
||||||
|
* @return an #aisl_t instance pointer.
|
||||||
|
*/
|
||||||
|
aisl_t
|
||||||
|
aisl_server_get_instance( aisl_server_t server );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copies server listen address information to sockaddr_in structure.
|
||||||
|
* @param server an #aisl_server_t pointer.
|
||||||
|
* @param address a pointer to sockaddr_in structure.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AISL_WITHOUT_SSL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to switch on and off SSL for the #aisl_server_t.
|
||||||
|
* @param server an #aisl_server_t pointer.
|
||||||
|
* @param value a boolean value representing SSL enabled/disabled state.
|
||||||
|
*/
|
||||||
|
void
|
||||||
aisl_server_set_ssl( aisl_server_t server, bool value );
|
aisl_server_set_ssl( aisl_server_t server, bool value );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to get on and off status of SSL for the #aisl_server_t.
|
||||||
|
* @param server an #aisl_server_t pointer.
|
||||||
|
* @return a boolean value representing SSL enabled/disabled state.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
aisl_server_get_ssl( aisl_server_t server );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif /* !AISL_SERVER_H */
|
#endif /* !AISL_SERVER_H */
|
||||||
|
|
|
@ -196,6 +196,9 @@ aisl_event_to_string( aisl_event_t event );
|
||||||
|
|
||||||
/* real type event callbacks */
|
/* real type event callbacks */
|
||||||
|
|
||||||
|
typedef bool
|
||||||
|
(*aisl_on_source_event_t)( void * source );
|
||||||
|
|
||||||
typedef bool
|
typedef bool
|
||||||
(*aisl_on_server_open_t)( aisl_server_t server );
|
(*aisl_on_server_open_t)( aisl_server_t server );
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
struct callback
|
struct callback
|
||||||
{
|
{
|
||||||
void * source;
|
void * source;
|
||||||
aisl_callback_t callback;
|
aisl_callback_t f_ptr;
|
||||||
aisl_event_t eevent;
|
aisl_event_t event;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct callback * callback_t;
|
typedef struct callback * callback_t;
|
||||||
|
|
578
src/client.c
578
src/client.c
|
@ -1,3 +1,4 @@
|
||||||
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -6,117 +7,82 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <aisl/aisl.h>
|
#include <aisl/aisl.h>
|
||||||
#include "client.h"
|
#include "list.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "parser.h"
|
#include "client.h"
|
||||||
#include "globals.h"
|
|
||||||
#include "handle.h"
|
|
||||||
|
|
||||||
#ifndef OUTPUT_BUFFER_SIZE
|
#define FLAG_KEEPALIVE (1<<0)
|
||||||
#define OUTPUT_BUFFER_SIZE 4096
|
#define FLAG_HANDSHAKE (1<<1)
|
||||||
#endif
|
#define FLAG_CAN_READ (1<<2)
|
||||||
struct client
|
#define FLAG_CAN_WRITE (1<<3)
|
||||||
|
|
||||||
|
|
||||||
|
struct aisl_client
|
||||||
{
|
{
|
||||||
struct sockaddr_in address;
|
struct sockaddr_in address; /**< Client's address structure */
|
||||||
server_t server;
|
aisl_server_t server; /**< Server instance associated with client */
|
||||||
int fd;
|
list_t streams; /**< list of client streams */
|
||||||
|
struct buffer in; /**< Client's input buffer */
|
||||||
|
struct buffer out; /**< Client's output buffer */
|
||||||
|
#ifndef AISL_WITHOUT_SSL
|
||||||
|
SSL * ssl; /**< SSL pointer for encrypted connections */
|
||||||
|
#endif
|
||||||
|
time_t timestamp; /**< Last communication timestamp */
|
||||||
|
|
||||||
int next_id; /* server id generator (even, starts from 2) */
|
aisl_stream_t stream; /**< Pending client's stream */
|
||||||
int istream; /* input stream id */
|
/* int next_id; / **< stream id generator (even)*/
|
||||||
int ostream; /* output stream id */
|
/* int istream; / **< input stream id */
|
||||||
list_t streams;
|
/* int ostream; / **< output stream id */
|
||||||
SSL * ssl;
|
int flags; /**< Client's flag bitmask */
|
||||||
|
int fd; /**< Client's socket descriptor */
|
||||||
|
|
||||||
time_t timestamp;
|
aisl_http_version_t protocol; /**< Client's protocol version */
|
||||||
aisl_http_version_t protocol;
|
|
||||||
int flags;
|
|
||||||
};
|
};
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void
|
|
||||||
client_close(client_t self)
|
|
||||||
{
|
|
||||||
close(self->fd);
|
|
||||||
/* will provide double free
|
|
||||||
if (self->ssl)
|
|
||||||
SSL_free(self->ssl);
|
|
||||||
*/
|
|
||||||
shutdown(self->fd, SHUT_RDWR);
|
|
||||||
self->fd=-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
client_input(client_t self)
|
aisl_client_raise_event(aisl_client_t client, aisl_event_t event, ...)
|
||||||
{
|
{
|
||||||
int l;
|
bool result;
|
||||||
parser_status_t p_status = PARSER_PENDING;
|
va_list vl_args;
|
||||||
char *ptr;
|
|
||||||
buffer_t buffer = self->server->owner->buffer;
|
|
||||||
|
|
||||||
stream_t s = list_index(self->streams, self->istream);
|
aisl_t instance = aisl_server_get_instance(client->server);
|
||||||
|
|
||||||
|
va_start(vl_args, event);
|
||||||
|
result = aisl_raise_vl(instance, client, event, vl_args);
|
||||||
|
va_end(vl_args);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (self->ssl)
|
static aisl_status_t
|
||||||
{
|
aisl_client_parse(aisl_client_t client, char * data, size_t size)
|
||||||
if (self->flags & CLIENT_FLAG_HANDSHAKE)
|
{
|
||||||
{
|
/* parse next data chunk */
|
||||||
if ( (l = SSL_accept(self->ssl)) != 1 )
|
|
||||||
{
|
|
||||||
l = SSL_get_error(self->ssl, l);
|
|
||||||
|
|
||||||
if (l == SSL_ERROR_WANT_READ || l == SSL_ERROR_WANT_WRITE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
client_close(self);
|
|
||||||
fprintf(stderr, "SSL handshake fail: %s\n", ERR_error_string(l, NULL));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->flags ^= CLIENT_FLAG_HANDSHAKE;
|
|
||||||
}
|
|
||||||
|
|
||||||
l = SSL_read(self->ssl, buffer->data, buffer->size) ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
l = recv( self->fd, buffer->data, buffer->size, 0);
|
|
||||||
|
|
||||||
if (l>0)
|
|
||||||
{
|
|
||||||
if( buffer_add(s->buffer, buffer->data, l) == BUFFER_EOB )
|
|
||||||
{
|
|
||||||
client_close(self);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = s->buffer->data;
|
|
||||||
l = s->buffer->size;
|
|
||||||
|
|
||||||
/* parse next data chunk */
|
|
||||||
while ( p_status == PARSER_PENDING )
|
while ( p_status == PARSER_PENDING )
|
||||||
{
|
{
|
||||||
switch(s->state)
|
switch(s->state)
|
||||||
{
|
{
|
||||||
case STREAM_REQUEST_METHOD:
|
case STREAM_REQUEST_METHOD:
|
||||||
p_status = parse_request_method(self, &ptr, &l);
|
p_status = parse_request_method(client, &ptr, &l);
|
||||||
break;
|
break;
|
||||||
case STREAM_REQUEST_PATH:
|
case STREAM_REQUEST_PATH:
|
||||||
p_status = parse_request_path(self, &ptr, &l);
|
p_status = parse_request_path(client, &ptr, &l);
|
||||||
break;
|
break;
|
||||||
case STREAM_REQUEST_PROTOCOL:
|
case STREAM_REQUEST_PROTOCOL:
|
||||||
p_status = parse_request_protocol(self, &ptr, &l);
|
p_status = parse_request_protocol(client, &ptr, &l);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STREAM_REQUEST_HEADER_KEY:
|
case STREAM_REQUEST_HEADER_KEY:
|
||||||
p_status = parse_request_header_key(self, &ptr, &l);
|
p_status = parse_request_header_key(client, &ptr, &l);
|
||||||
break;
|
break;
|
||||||
case STREAM_REQUEST_HEADER_VALUE:
|
case STREAM_REQUEST_HEADER_VALUE:
|
||||||
p_status = parse_request_header_value(self, &ptr, &l);
|
p_status = parse_request_header_value(client, &ptr, &l);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STREAM_REQUEST_CONTENT:
|
case STREAM_REQUEST_CONTENT:
|
||||||
p_status = parse_request_content(self, &ptr, &l);
|
p_status = parse_request_content(client, &ptr, &l);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -129,43 +95,95 @@ client_input(client_t self)
|
||||||
if (p_status == PARSER_FAILED)
|
if (p_status == PARSER_FAILED)
|
||||||
{
|
{
|
||||||
/* reply Bad Request here */
|
/* reply Bad Request here */
|
||||||
client_close(self);
|
client_close(client);
|
||||||
}
|
}
|
||||||
else if (l)
|
else if (l)
|
||||||
{
|
{
|
||||||
buffer_shift(s->buffer, s->buffer->size-l); /* reset buffer */
|
buffer_shift(s->buffer, s->buffer->size-l); /* reset buffer */
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
else
|
|
||||||
buffer_clear(s->buffer, 0);*/
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 aisl_status_t
|
||||||
|
aisl_client_input(aisl_client_t client)
|
||||||
|
{
|
||||||
|
int l;
|
||||||
|
parser_status_t p_status = PARSER_PENDING;
|
||||||
|
aisl_stream_t s = client->stream;
|
||||||
|
|
||||||
|
char * data = &client->in.data[ client->in.length ];
|
||||||
|
size_t size = client->in.size - client.in.length;
|
||||||
|
|
||||||
|
#ifndef AISL_WITHOUT_SSL
|
||||||
|
if (client->ssl)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
fprintf( stderr
|
||||||
|
, "*AISL: SSL handshake fail: %s\n"
|
||||||
|
, ERR_error_string(l, NULL) );
|
||||||
|
|
||||||
|
aisl_client_close(client);
|
||||||
|
return AISL_SYSCALL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
client->flags |= FLAG_HANDSHAKE;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = SSL_read(client->ssl, data, size) ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
l = recv( client->fd, data, size, 0);
|
||||||
|
|
||||||
|
if (l > 0)
|
||||||
|
{
|
||||||
|
data = client->in.data;
|
||||||
|
size = client->in.length + l;
|
||||||
|
|
||||||
|
client->in.length = size;
|
||||||
|
|
||||||
|
return aisl_client_parse(client, data, size);
|
||||||
}
|
}
|
||||||
else if (l<0)
|
else if (l<0)
|
||||||
{
|
{
|
||||||
if (self->ssl)
|
if (client->ssl)
|
||||||
{
|
{
|
||||||
if (SSL_get_error(self->ssl, l) == SSL_ERROR_WANT_READ)
|
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
|
||||||
return false;
|
return AISL_IDLE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(errno == EWOULDBLOCK)
|
if(errno == EWOULDBLOCK)
|
||||||
return false;
|
return AISL_IDLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* both: client disconnect + on read error */
|
/* both: client disconnect + on read error */
|
||||||
/* todo: raise client error here */
|
/* todo: raise client error here */
|
||||||
client_close(self);
|
client_close(client);
|
||||||
|
|
||||||
return true;
|
return AISL_SYSCALL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
client_output(client_t self)
|
aisl_client_output(aisl_client_t client)
|
||||||
{
|
{
|
||||||
if (self->fd < 0)
|
if (client->fd < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[aisl] assertion !(client->fd<0) failed\n");
|
fprintf(stderr, "[aisl] assertion !(client->fd<0) failed\n");
|
||||||
return true;
|
return true;
|
||||||
|
@ -174,7 +192,7 @@ client_output(client_t self)
|
||||||
stream_t s;
|
stream_t s;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
s = list_index(self->streams, self->ostream);
|
s = list_index(client->streams, client->ostream);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (!s->c_length_unknown && s->buffer && s->buffer->len)
|
if (!s->c_length_unknown && s->buffer && s->buffer->len)
|
||||||
|
@ -200,15 +218,15 @@ client_output(client_t self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (l = bsz - s->buffer->size) > OUTPUT_BUFFER_SIZE / 2 )
|
if ( (l = bsz - s->buffer->size) > OUTPUT_BUFFER_SIZE / 2 )
|
||||||
aisl_raise_event( self->server->owner, s, AISL_STREAM_OUTPUT, l);
|
aisl_raise_event( client->server->owner, s, AISL_STREAM_OUTPUT, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->buffer->size == 0)
|
if (s->buffer->size == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
l = (self->ssl) ?
|
l = (client->ssl) ?
|
||||||
SSL_write(self->ssl, s->buffer->data, s->buffer->size) :
|
SSL_write(client->ssl, s->buffer->data, s->buffer->size) :
|
||||||
send( self->fd, s->buffer->data, s->buffer->size, 0);
|
send( client->fd, s->buffer->data, s->buffer->size, 0);
|
||||||
|
|
||||||
if (l > 0)
|
if (l > 0)
|
||||||
{
|
{
|
||||||
|
@ -220,31 +238,31 @@ client_output(client_t self)
|
||||||
|
|
||||||
/* data has been sent */
|
/* data has been sent */
|
||||||
/*
|
/*
|
||||||
if (self->protocol == AISL_HTTP_2_0)
|
if (client->protocol == AISL_HTTP_2_0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
else*/
|
else*/
|
||||||
if (self->flags & CLIENT_FLAG_KEEPALIVE)
|
if (client->flags & CLIENT_FLAG_KEEPALIVE)
|
||||||
{
|
{
|
||||||
list_remove(self->streams, s);
|
list_remove(client->streams, s);
|
||||||
stream_free(s);
|
stream_free(s);
|
||||||
|
|
||||||
s = stream_new((struct sockaddr_in *) self, self->next_id++, STREAM_REQUEST_METHOD );
|
s = stream_new((struct sockaddr_in *) client, client->next_id++, STREAM_REQUEST_METHOD );
|
||||||
list_append(self->streams, s);
|
list_append(client->streams, s);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client_close(self);
|
client_close(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* l < 0 */
|
/* l < 0 */
|
||||||
if (self->ssl)
|
if (client->ssl)
|
||||||
{
|
{
|
||||||
if ( SSL_get_error(self->ssl, l) == SSL_ERROR_WANT_WRITE )
|
if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -253,223 +271,195 @@ client_output(client_t self)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
client_close(self);
|
client_close(client);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
client_touch(client_t self)
|
aisl_client_t
|
||||||
|
aisl_client_new( aisl_server_t server,
|
||||||
|
int fd,
|
||||||
|
struct sockaddr_in * addr,
|
||||||
|
SSL_CTX * ssl_ctx )
|
||||||
{
|
{
|
||||||
bool result = false;
|
aisl_client_t client;
|
||||||
stream_t s;
|
aisl_stream_t stream;
|
||||||
|
|
||||||
/* input */
|
if ( (client = calloc(1, sizeof(struct client))) != NULL )
|
||||||
s = list_index(self->streams, self->istream);
|
|
||||||
|
|
||||||
if ((self->protocol==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
|
|
||||||
(client_input(self)) ) result = true;
|
|
||||||
|
|
||||||
/* output */
|
|
||||||
s = list_index(self->streams, self->ostream);
|
|
||||||
|
|
||||||
if ( s->flags & (STREAM_FLAG_OUTPUT_READY | STREAM_FLAG_OUTPUT_CHUNKED) )
|
|
||||||
result = client_output(self);
|
|
||||||
|
|
||||||
/* update timestamp */
|
|
||||||
if (result)
|
|
||||||
self->timestamp = time(NULL);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* constructor -------------------------------------------------------------- */
|
|
||||||
|
|
||||||
static client_t
|
|
||||||
client_new( int fd, struct sockaddr_in * addr )
|
|
||||||
{
|
|
||||||
client_t self;
|
|
||||||
stream_t stream;
|
|
||||||
|
|
||||||
if ( !(self = calloc(1, sizeof(struct client))) )
|
|
||||||
goto finally;
|
|
||||||
|
|
||||||
memcpy(&self->address, addr, sizeof(struct sockaddr_in));
|
|
||||||
|
|
||||||
self->fd = fd;
|
|
||||||
self->next_id = 2;
|
|
||||||
/*
|
|
||||||
self->istream = 0;
|
|
||||||
self->ostream = 0;
|
|
||||||
* UTPUT
|
|
||||||
*/
|
|
||||||
self->protocol = AISL_HTTP_1_0;
|
|
||||||
self->timestamp = time(NULL);
|
|
||||||
self->flags = CLIENT_FLAG_KEEPALIVE | CLIENT_FLAG_HANDSHAKE;
|
|
||||||
|
|
||||||
if ( !(self->streams = list_new(AISL_MIN_STREAMS)) )
|
|
||||||
goto except;
|
|
||||||
|
|
||||||
if ( !(stream = stream_new((struct sockaddr_in *)self, 0, STREAM_REQUEST_METHOD)) )
|
|
||||||
goto e_stream;
|
|
||||||
|
|
||||||
if (list_append(self->streams, stream) == -1)
|
|
||||||
goto e_append;
|
|
||||||
|
|
||||||
goto finally;
|
|
||||||
|
|
||||||
e_append:
|
|
||||||
stream_free(stream);
|
|
||||||
|
|
||||||
e_stream:
|
|
||||||
list_free(self->streams, NULL);
|
|
||||||
|
|
||||||
except:
|
|
||||||
free(self);
|
|
||||||
self=NULL;
|
|
||||||
|
|
||||||
finally:
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
aisl_status_t
|
|
||||||
client_accept(client_t * p_self, server_t server)
|
|
||||||
{
|
|
||||||
aisl_status_t result;
|
|
||||||
const char * e_detail = NULL;
|
|
||||||
int fd;
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
socklen_t len = sizeof(struct sockaddr_in);
|
|
||||||
SSL * ssl = NULL;
|
|
||||||
SSL_CTX * ssl_ctx;
|
|
||||||
|
|
||||||
*p_self = NULL;
|
|
||||||
|
|
||||||
if ( (fd = accept(server->fd, (struct sockaddr *) &addr, &len)) < 0 )
|
|
||||||
{
|
{
|
||||||
if (errno != EWOULDBLOCK)
|
memcpy(&client->address, addr, sizeof(struct sockaddr_in));
|
||||||
|
client->fd = fd;
|
||||||
|
client->next_id = 2;
|
||||||
|
client->protocol = 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) == 0)
|
||||||
{
|
{
|
||||||
result = AISL_SYSCALL_ERROR;
|
memcpy(&client->out, client->in, sizeof(struct buffer));
|
||||||
e_detail = strerror(errno);
|
|
||||||
goto raise;
|
stream = aisl_stream_new(client, 0, STREAM_REQUEST_METHOD);
|
||||||
|
|
||||||
|
if (stream != NULL)
|
||||||
|
{
|
||||||
|
client->stream = stream;
|
||||||
|
|
||||||
|
#ifdef AISL_WITHOUT_SSL
|
||||||
|
|
||||||
|
return client;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
if ( !ssl_ctx )
|
||||||
|
return client;
|
||||||
|
|
||||||
|
if ((client->ssl = SSL_new(ssl_ctx)) != NULL )
|
||||||
|
{
|
||||||
|
SSL_set_fd(client->ssl, fd);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
aisl_client_free(client);
|
||||||
result = AISL_IDLE;
|
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
|
|
||||||
int flags = fcntl(fd, F_GETFL, 0);
|
|
||||||
if (flags == -1)
|
|
||||||
{
|
|
||||||
result = AISL_SYSCALL_ERROR;
|
|
||||||
e_detail = strerror(errno);
|
|
||||||
goto raise;
|
|
||||||
}
|
|
||||||
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
|
|
||||||
if (fcntl(fd, F_SETFL, flags) != 0)
|
|
||||||
{
|
|
||||||
result = AISL_SYSCALL_ERROR;
|
|
||||||
e_detail = strerror(errno);
|
|
||||||
goto raise;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (server->flags & AISL_FLAG_SSL)
|
|
||||||
{
|
|
||||||
if ( !(ssl_ctx = aisl_get_ssl_ctx( server->owner, NULL )) )
|
|
||||||
goto except;
|
|
||||||
|
|
||||||
if ( !(ssl = SSL_new(ssl_ctx)) )
|
|
||||||
{
|
|
||||||
e_detail = "SSL_new";
|
|
||||||
result = AISL_EXTCALL_ERROR;
|
|
||||||
goto except;
|
|
||||||
}
|
|
||||||
|
|
||||||
SSL_set_fd(ssl, fd);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
ssl = NULL;
|
|
||||||
|
|
||||||
if ( !(*p_self = client_new(fd, &addr)) )
|
return NULL;
|
||||||
{
|
|
||||||
result = AISL_MALLOC_ERROR;
|
|
||||||
e_detail = "client_t";
|
|
||||||
goto raise;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*p_self)->server = server;
|
|
||||||
(*p_self)->ssl = ssl;
|
|
||||||
result = AISL_SUCCESS;
|
|
||||||
|
|
||||||
goto finally;
|
|
||||||
|
|
||||||
except:
|
|
||||||
close(fd);
|
|
||||||
if (ssl)
|
|
||||||
SSL_free(ssl);
|
|
||||||
|
|
||||||
raise:
|
|
||||||
aisl_raise_event(
|
|
||||||
server->owner,
|
|
||||||
server,
|
|
||||||
AISL_SERVER_ERROR,
|
|
||||||
server->flags,
|
|
||||||
e_detail
|
|
||||||
);
|
|
||||||
|
|
||||||
finally:
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* destructor --------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
client_free(client_t self)
|
aisl_client_free(aisl_client_t client)
|
||||||
{
|
{
|
||||||
if (self->fd > -1)
|
aisl_client_close(client);
|
||||||
close(self->fd);
|
|
||||||
|
|
||||||
if (self->ssl)
|
#ifndef AISL_WITHOUT_SSL
|
||||||
SSL_free(self->ssl);
|
if (client->ssl)
|
||||||
|
SSL_free(client->ssl);
|
||||||
|
#endif
|
||||||
|
|
||||||
list_free(self->streams, (list_destructor_t)stream_free);
|
if (client->in.data)
|
||||||
|
free(client->in.data);
|
||||||
|
|
||||||
aisl_raise_event(
|
/* out buffer is a shared part of input buffer, so no need to free it */
|
||||||
self->server->owner,
|
|
||||||
self->server,
|
|
||||||
AISL_CLIENT_DISCONNECT,
|
|
||||||
self
|
|
||||||
);
|
|
||||||
|
|
||||||
free(self);
|
list_free(client->streams, (list_destructor_t)aisl_stream_free);
|
||||||
|
|
||||||
|
free(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if communication time with client is expired ----------------------- */
|
|
||||||
|
|
||||||
bool
|
aisl_status_t
|
||||||
client_is_timeout(client_t self)
|
aisl_client_touch(aisl_client_t client)
|
||||||
{
|
{
|
||||||
bool result = false;
|
aisl_status_t result, status;
|
||||||
stream_t s;
|
aisl_stream_t s = client->stream;
|
||||||
if (self->protocol == AISL_HTTP_2_0)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
/* input */
|
||||||
else
|
if (client->flags & FLAG_CAN_READ)
|
||||||
{
|
{
|
||||||
s = list_index(self->streams, self->istream);
|
if ( (result = client_input(client)) < 0 )
|
||||||
if ( (s->state < STREAM_REQUEST_READY) && /* still waiting for data */
|
return result;
|
||||||
(time(NULL)-self->timestamp > AISL_MAX_CLIENT_SILENCE) ) result=true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
/* output */
|
||||||
client_close(self);
|
if (client->flags & FLAG_CAN_WRITE)
|
||||||
|
{
|
||||||
|
if ( (status = client_output(client)) < 0 )
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
if ((client->protocol==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);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
bool
|
||||||
|
aisl_client_is_timed_out(aisl_client_t client, uint32_t timeout)
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
if ( !(now - client->timestamp < timeout) )
|
||||||
|
{
|
||||||
|
aisl_client_raise_event( client, AISL_CLIENT_TIMEOUT );
|
||||||
|
aisl_client_close(client);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
aisl_client_get_socket(aisl_client_t client)
|
||||||
|
{
|
||||||
|
return client->fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* API Level ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
aisl_server_t
|
||||||
|
aisl_client_get_server(aisl_client_t client)
|
||||||
|
{
|
||||||
|
return client->server;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
aisl_client_is_secure(aisl_client_t client)
|
||||||
|
{
|
||||||
|
return (client->ssl == NULL) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
aisl_client_is_online(aisl_client_t client)
|
||||||
|
{
|
||||||
|
return (client->fd == -1) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
aisl_client_close(aisl_client_t client)
|
||||||
|
{
|
||||||
|
if (client->fd != -1)
|
||||||
|
{
|
||||||
|
aisl_client_raise_event( client, AISL_CLIENT_DISCONNECT );
|
||||||
|
|
||||||
|
close(client->fd);
|
||||||
|
shutdown(client->fd, SHUT_RDWR);
|
||||||
|
client->fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
aisl_http_version_t
|
||||||
|
aisl_client_get_http_version(aisl_client_t client)
|
||||||
|
{
|
||||||
|
return client->http_version;
|
||||||
|
}
|
||||||
|
|
72
src/client.h
72
src/client.h
|
@ -1,47 +1,61 @@
|
||||||
#ifndef AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
|
#ifndef AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
|
||||||
#define AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
|
#define AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
|
||||||
#include <openssl/err.h>
|
|
||||||
#include <openssl/ssl.h>
|
|
||||||
|
|
||||||
#include <aisl/client.h>
|
#include <aisl/client.h>
|
||||||
#include "server.h"
|
|
||||||
#include "list.h"
|
|
||||||
|
|
||||||
#define CLIENT_FLAG_KEEPALIVE (1<<0)
|
#define AISL_CLIENT(x) ((aisl_client_t) x)
|
||||||
#define CLIENT_FLAG_HANDSHAKE (1<<1)
|
|
||||||
|
|
||||||
#define CLIENT(x) ((aisl_client_t)x)
|
|
||||||
|
|
||||||
/* constructor -------------------------------------------------------------- */
|
/**
|
||||||
|
* @brief Constructor for #aisl_client_t instance.
|
||||||
|
* @param server an #aisl_server_t 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,
|
||||||
|
SSL_CTX * ssl_ctx);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor for #aisl_client_t instance.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
aisl_client_free(aisl_client_t client);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Does all HTTP client routines.
|
||||||
|
* Reads and parses requests, writes responses.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
|
* @return #aisl_status_t code.
|
||||||
|
*/
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_client_accept(aisl_client_t * self, aisl_server_t server);
|
aisl_client_touch(aisl_client_t client);
|
||||||
|
|
||||||
/* destructor --------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void
|
|
||||||
aisl_client_free(aisl_client_t self);
|
|
||||||
|
|
||||||
/* all regular client routines. return true if something happened ----------- */
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Controls if communication time is not timed out.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
|
* @param timeout an allowed client silence time in seconds.
|
||||||
|
* @return true if client communication is timed out, otherwise false.
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
aisl_client_touch(aisl_client_t self);
|
aisl_client_is_timed_out(aisl_client_t client, uint32_t timeout);
|
||||||
|
|
||||||
/* check if communication time with client is expired ----------------------- */
|
|
||||||
|
|
||||||
bool
|
/**
|
||||||
aisl_client_is_timeout(aisl_client_t self);
|
* @brief Gets socket descriptor associated with #aisl_client_t instance.
|
||||||
|
* @param client an #aisl_client_t instance pointer.
|
||||||
/* -------------------------------------------------------------------------- */
|
* @return a client socket descriptor.
|
||||||
|
*/
|
||||||
void
|
int
|
||||||
aisl_client_close(aisl_client_t self);
|
aisl_client_get_socket(aisl_client_t client);
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#endif /* !AISL_CLIENT_H */
|
#endif /* !AISL_CLIENT_H */
|
||||||
|
|
414
src/instance.c
414
src/instance.c
|
@ -23,21 +23,15 @@
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
//#include "globals.h"
|
//#include "globals.h"
|
||||||
//#include "stream.h"
|
#include "stream.h"
|
||||||
#include "instance.h"
|
#include "instance.h"
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
AISL_CYCLE_SERVER = 0
|
|
||||||
, AISL_CYCLE_CLIENT = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct callback
|
struct callback
|
||||||
{
|
{
|
||||||
void * source;
|
void * source;
|
||||||
aisl_callback_t callback;
|
aisl_callback_t f_ptr;
|
||||||
aisl_event_t eevent;
|
aisl_event_t event;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct callback * callback_t;
|
typedef struct callback * callback_t;
|
||||||
|
@ -45,18 +39,20 @@ typedef struct callback * callback_t;
|
||||||
|
|
||||||
struct aisl
|
struct aisl
|
||||||
{
|
{
|
||||||
list_t servers;
|
list_t server_spool;
|
||||||
list_t clients;
|
list_t client_spool;
|
||||||
list_t callbacks;
|
list_t callback_spool;
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#ifndef AISL_WITHOUT_SSL
|
||||||
list_t ssl;
|
list_t ssl_spool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
buffer_t buffer;
|
buffer_t buffer;
|
||||||
char * last_error;
|
char * last_error;
|
||||||
int iterator;
|
|
||||||
int stage;
|
size_t iterator;
|
||||||
int flags;
|
|
||||||
uint32_t accept_limit;
|
uint32_t accept_limit;
|
||||||
|
uint32_t silence_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,24 +80,25 @@ aisl_new( aisl_config_t config )
|
||||||
if ( !(instance = calloc(1, sizeof(struct aisl))) )
|
if ( !(instance = calloc(1, sizeof(struct aisl))) )
|
||||||
goto finally;
|
goto finally;
|
||||||
|
|
||||||
if ( !(instance->servers = list_new(config->servers_spool_size)) )
|
if ( !(instance->server_spool = list_new(config->server_spool_size)) )
|
||||||
goto release;
|
goto release;
|
||||||
|
|
||||||
if ( !(instance->clients = list_new(config->clients_spool_size)) )
|
if ( !(instance->client_spool = list_new(config->client_spool_size)) )
|
||||||
goto release;
|
goto release;
|
||||||
|
|
||||||
if ( !(instance->callbacks = list_new(config->callbacks_spool_size)) )
|
if ( !(instance->callback_spool = list_new(config->callback_spool_size)) )
|
||||||
goto release;
|
goto release;
|
||||||
|
|
||||||
if ( !(instance->buffer = buffer_new(config->initial_buffer_size)) )
|
if ( !(instance->buffer = buffer_new(config->initial_buffer_size)) )
|
||||||
goto release;
|
goto release;
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#ifndef AISL_WITHOUT_SSL
|
||||||
if ( !(instance->ssl = list_new(config->ssl_spool_size)) )
|
if ( !(instance->ssl_spool = list_new(config->ssl_spool_size)) )
|
||||||
goto release;
|
goto release;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
instance->accept_limit = config->clients_accept_limit;
|
instance->accept_limit = config->client_accept_limit;
|
||||||
|
instance->silence_timeout = config->client_silence_timeout;
|
||||||
|
|
||||||
goto finally;
|
goto finally;
|
||||||
|
|
||||||
|
@ -118,21 +115,21 @@ __attribute__ ((visibility ("default") ))
|
||||||
void
|
void
|
||||||
aisl_free( aisl_t instance )
|
aisl_free( aisl_t instance )
|
||||||
{
|
{
|
||||||
if (instance->clients)
|
if (instance->client_spool)
|
||||||
list_free(instance->clients, (list_destructor_t) aisl_client_free );
|
list_free(instance->client_spool, (list_destructor_t) aisl_client_free );
|
||||||
|
|
||||||
if (instance->servers)
|
if (instance->server_spool)
|
||||||
list_free(instance->servers, (list_destructor_t) aisl_server_free );
|
list_free(instance->server_spool, (list_destructor_t) aisl_server_free );
|
||||||
|
|
||||||
if (instance->callbacks)
|
if (instance->callback_spool)
|
||||||
list_free(instance->callbacks, free);
|
list_free(instance->callback_spool, (list_destructor_t) free);
|
||||||
|
|
||||||
if (instance->buffer)
|
if (instance->buffer)
|
||||||
buffer_free(instance->buffer);
|
buffer_free(instance->buffer);
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#ifndef AISL_WITHOUT_SSL
|
||||||
if (instance->ssl)
|
if (instance->ssl_spool)
|
||||||
list_free(instance->ssl, (list_destructor_t) ssl_free );
|
list_free(instance->ssl_spool, (list_destructor_t) ssl_free );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (instance->last_error)
|
if (instance->last_error)
|
||||||
|
@ -157,7 +154,7 @@ aisl_listen( aisl_t instance, const char * address, uint16_t port )
|
||||||
|
|
||||||
if ( (result = aisl_server_new(instance, address, port)) != NULL )
|
if ( (result = aisl_server_new(instance, address, port)) != NULL )
|
||||||
{
|
{
|
||||||
if (list_append(instance->servers, result) == LIST_NAN)
|
if (list_append(instance->server_spool, result) == LIST_NAN)
|
||||||
{
|
{
|
||||||
aisl_server_free(result);
|
aisl_server_free(result);
|
||||||
}
|
}
|
||||||
|
@ -180,34 +177,21 @@ aisl_set_ssl( aisl_t instance, const char * domain,
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
/* lookup for existing contexts */
|
/* lookup for existing contexts */
|
||||||
for (i=0; i<instance->ssl->count; i++)
|
for (i=0; i<instance->ssl_spool->count; i++)
|
||||||
{
|
{
|
||||||
ssl = list_index(instance->ssl, i);
|
ssl = list_index(instance->ssl_spool, i);
|
||||||
if (ssl->key_file && strcmp(ssl->key_file, key_file)==0 &&
|
if (ssl->key_file && strcmp(ssl->key_file, key_file)==0 &&
|
||||||
ssl->crt_file && strcmp(ssl->crt_file, crt_file)==0 )
|
ssl->crt_file && strcmp(ssl->crt_file, crt_file)==0 )
|
||||||
{
|
{
|
||||||
if ((ssl_ctx = crypter->ssl_ctx) != NULL)
|
ssl_ctx = ssl->ctx;
|
||||||
{
|
break;
|
||||||
key_file = NULL;
|
|
||||||
crt_file = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ssl = ssl_new(domain, key_file, crt_file)) != NULL)
|
if ((ssl = ssl_new(domain, key_file, crt_file, ssl_ctx)) != NULL)
|
||||||
{
|
{
|
||||||
if (! ssl_ctx)
|
if (list_append(instance->ssl_spool, ssl) != LIST_NAN)
|
||||||
ssl_ctx = ssl__new_context(key_file, crt_file, (void*)instance);
|
return AISL_SUCCESS;
|
||||||
|
|
||||||
if (ssl_ctx)
|
|
||||||
{
|
|
||||||
ssl->ctx = ssl_ctx;
|
|
||||||
if (list_append(instance->ssl, ssl) != LIST_NAN)
|
|
||||||
{
|
|
||||||
return AISL_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssl_free(ssl);
|
ssl_free(ssl);
|
||||||
}
|
}
|
||||||
|
@ -224,9 +208,9 @@ aisl_get_ssl_ctx( aisl_t instance, const char * domain )
|
||||||
|
|
||||||
if (domain)
|
if (domain)
|
||||||
{
|
{
|
||||||
for (i=0; i<instance->ssl->count; i++)
|
for (i=0; i<instance->ssl_spool->count; i++)
|
||||||
{
|
{
|
||||||
ssl = list_index(instance->ssl, i);
|
ssl = list_index(instance->ssl_spool, i);
|
||||||
if (strcmp(ssl->domain, domain) != 0)
|
if (strcmp(ssl->domain, domain) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -251,22 +235,25 @@ aisl_set_callback( aisl_t instance,
|
||||||
|
|
||||||
if ( (cb = malloc(sizeof(struct callback))) != NULL )
|
if ( (cb = malloc(sizeof(struct callback))) != NULL )
|
||||||
{
|
{
|
||||||
cb->source = source;
|
cb->source = source;
|
||||||
cb->event = event;
|
cb->event = event;
|
||||||
cb->callback = callback;
|
cb->f_ptr = callback;
|
||||||
|
|
||||||
if ( list_append(instance->callbacks, cb) != LIST_NAN )
|
if ( list_append(instance->callback_spool, cb) != LIST_NAN )
|
||||||
{
|
{
|
||||||
switch(event)
|
switch(event)
|
||||||
{
|
{
|
||||||
case AISL_STREAM_OUTPUT:
|
case AISL_EVENT_STREAM_OUTPUT:
|
||||||
if (source)
|
if (source)
|
||||||
stream_set_chunked_output( (aisl_stream_t) source );
|
aisl_stream_set_chunked_output( (aisl_stream_t) source, true );
|
||||||
//( (stream_t) source )->flags |= STREAM_FLAG_OUTPUT_CHUNKED;
|
//( (stream_t) source )->flags |= STREAM_FLAG_OUTPUT_CHUNKED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AISL_STREAM_OPEN:
|
/*
|
||||||
instance->flags |= AISL_FLAG_HAS_STREAM_LISTENERS;
|
* case AISL_EVENT_STREAM_OPEN:
|
||||||
|
* instance->flags |= AISL_FLAG_HAS_STREAM_CALLBACKS;
|
||||||
|
*/
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,19 +267,19 @@ aisl_set_callback( aisl_t instance,
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
void
|
void
|
||||||
aisl_unset_callback_for( aisl_t instance, void * source )
|
aisl_unset_callbacks_for( aisl_t instance, void * source )
|
||||||
{
|
{
|
||||||
size_t i = instance->callbacks->count;
|
size_t i = instance->callback_spool->count;
|
||||||
|
|
||||||
if (i)
|
if (i)
|
||||||
{
|
{
|
||||||
for(i=i-1; i <= 0; i-- )
|
for(i=i-1; i <= 0; i-- )
|
||||||
{
|
{
|
||||||
callback_t callback = list_index(instance->callbacks, i);
|
callback_t callback = list_index(instance->callback_spool, i);
|
||||||
if ( callback->source == source )
|
if ( callback->source == source )
|
||||||
{
|
{
|
||||||
free(callback);
|
free(callback);
|
||||||
list_remove_index(instance->callbacks, i);
|
list_remove_index(instance->callback_spool, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,183 +288,228 @@ aisl_unset_callback_for( aisl_t instance, void * source )
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
bool
|
bool
|
||||||
aisl_raise( aisl_t instance,
|
aisl_raise( aisl_t instance, void * source, aisl_event_t event, ... )
|
||||||
void * source,
|
|
||||||
aisl_event_t e_id,
|
|
||||||
... )
|
|
||||||
{
|
{
|
||||||
va_list vl;
|
va_list vl;
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
va_start(vl, e_id);
|
va_start(vl, event);
|
||||||
result = aisl_raise_vl(instance, source, e_id, vl);
|
result = aisl_raise_vl(instance, source, event, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
aisl_on_source_event( void * source, aisl_callback_t cb, va_list vl_args )
|
||||||
|
{
|
||||||
|
aisl_on_source_event_t callback = (aisl_on_source_event_t) cb;
|
||||||
|
|
||||||
|
(void) vl_args;
|
||||||
|
|
||||||
|
return callback( (void *) source);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
aisl_on_stream_open( void * source, aisl_callback_t cb, va_list vl_args )
|
||||||
|
{
|
||||||
|
aisl_on_stream_open_t callback = (aisl_on_stream_open_t) cb;
|
||||||
|
|
||||||
|
aisl_http_method_t method = va_arg(vl_args, aisl_http_method_t);
|
||||||
|
char * path = va_arg(vl_args, char *);
|
||||||
|
char * query = va_arg(vl_args, char *);
|
||||||
|
|
||||||
|
return callback( (aisl_stream_t) source, method, path, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
aisl_on_stream_header( void * source, aisl_callback_t cb, va_list vl_args )
|
||||||
|
{
|
||||||
|
aisl_on_stream_header_t callback = (aisl_on_stream_header_t) cb;
|
||||||
|
|
||||||
|
char * key = va_arg(vl_args, char *);
|
||||||
|
char * val = va_arg(vl_args, char *);
|
||||||
|
|
||||||
|
return callback( (aisl_stream_t) source, key, val );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
aisl_on_stream_input( void * source, aisl_callback_t cb, va_list vl_args )
|
||||||
|
{
|
||||||
|
aisl_on_stream_input_t callback = (aisl_on_stream_input_t) cb;
|
||||||
|
|
||||||
|
size_t len = va_arg(vl_args, size_t);
|
||||||
|
char * data = va_arg(vl_args, char *);
|
||||||
|
|
||||||
|
return callback( (aisl_stream_t) source, data, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
aisl_on_stream_output( void * source, aisl_callback_t cb, va_list vl_args )
|
||||||
|
{
|
||||||
|
aisl_on_stream_output_t callback = (aisl_on_stream_output_t) cb;
|
||||||
|
|
||||||
|
size_t buffer_size = va_arg(vl_args, size_t);
|
||||||
|
|
||||||
|
return callback( (aisl_stream_t) source, buffer_size );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
bool
|
bool
|
||||||
aisl_raise_vl( aisl_t instance,
|
aisl_raise_vl( aisl_t instance,
|
||||||
void * source,
|
void * source,
|
||||||
aisl_event_t e_id,
|
aisl_event_t event,
|
||||||
va_list vl )
|
va_list vl_args )
|
||||||
{
|
{
|
||||||
int i,
|
va_list vl_copy;
|
||||||
i_val;
|
size_t i;
|
||||||
listener_t lst;
|
|
||||||
bool res = false;
|
|
||||||
|
|
||||||
char * c_ptr,
|
callback_t cb;
|
||||||
* c_ptr2;
|
bool result = false,
|
||||||
|
stop_propg = false;
|
||||||
|
|
||||||
for(i=instance->callbacks->count-1; i>=0; i--)
|
i = instance->callback_spool->count;
|
||||||
|
|
||||||
|
while(i--)
|
||||||
{
|
{
|
||||||
lst = list_index(instance->callbacks, i);
|
cb = list_index(instance->callback_spool, i);
|
||||||
|
|
||||||
/*printf("AISL> raise %s:%s, %p:%p\n", _event_text(e_id), _event_text(lst->e_id), source, lst->source);*/
|
if (cb->event == event && (source == cb->source || cb->source == NULL))
|
||||||
if (lst->e_id == e_id && (source == lst->source || lst->source == NULL))
|
|
||||||
{
|
{
|
||||||
/*
|
va_copy(vl_copy, vl_args);
|
||||||
if (e_id == AISL_STREAM_HEADER)
|
switch(event)
|
||||||
fprintf(stderr,"FOUND HANDLER %d\n", i);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*printf(" catch\n");*/
|
|
||||||
switch(e_id)
|
|
||||||
{
|
{
|
||||||
/* server events */
|
/* server events */
|
||||||
case AISL_EVENT_SERVER_OPEN:
|
case AISL_EVENT_SERVER_OPEN:
|
||||||
i_val = va_arg(vl, aisl_status_t);
|
|
||||||
res = ((aisl_on_server_open_t) lst->cb)( source, i_val );
|
|
||||||
break;
|
|
||||||
case AISL_EVENT_SERVER_ERROR:
|
case AISL_EVENT_SERVER_ERROR:
|
||||||
i_val = va_arg(vl, aisl_status_t);
|
|
||||||
c_ptr = va_arg(vl, char *);
|
|
||||||
res = ((aisl_on_server_error_t) lst->cb)( source, i_val, c_ptr );
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* client events */
|
|
||||||
case AISL_EVENT_CLIENT_CONNECT:
|
case AISL_EVENT_CLIENT_CONNECT:
|
||||||
res = ((aisl_on_client_connect_t) lst->cb)(source, va_arg(vl, void *));
|
|
||||||
break;
|
|
||||||
case AISL_EVENT_CLIENT_DISCONNECT:
|
case AISL_EVENT_CLIENT_DISCONNECT:
|
||||||
res = ((aisl_on_client_disconnect_t) lst->cb)(source, va_arg(vl, void*));
|
|
||||||
aisl_unset_callback_for( instance, source );
|
|
||||||
break;
|
|
||||||
case AISL_EVENT_CLIENT_TIMEOUT:
|
case AISL_EVENT_CLIENT_TIMEOUT:
|
||||||
res = ((aisl_client_timeout_t) lst->cb)(source, va_arg(vl, void *));
|
case AISL_EVENT_STREAM_REQUEST:
|
||||||
|
case AISL_EVENT_STREAM_CLOSE:
|
||||||
|
case AISL_EVENT_STREAM_ERROR:
|
||||||
|
stop_propg = aisl_on_source_event(source, cb->f_ptr, vl_copy);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* request events */
|
|
||||||
case AISL_EVENT_STREAM_OPEN:
|
case AISL_EVENT_STREAM_OPEN:
|
||||||
i_val = va_arg(vl, int);
|
stop_propg = aisl_on_stream_open(source, cb->f_ptr, vl_copy);
|
||||||
c_ptr = va_arg(vl, char *);
|
|
||||||
c_ptr2 = va_arg(vl, char *);
|
|
||||||
res = ((aisl_on_stream_open_t) lst->cb)(source, i_val, c_ptr, c_ptr2);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AISL_EVENT_STREAM_HEADER:
|
case AISL_EVENT_STREAM_HEADER:
|
||||||
c_ptr = va_arg(vl, char *);
|
stop_propg = aisl_on_stream_header(source, cb->f_ptr, vl_copy);
|
||||||
c_ptr2 = va_arg(vl, char *);
|
|
||||||
res = ((aisl_on_stream_header_t) lst->cb)(source, c_ptr, c_ptr2);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case AISL_EVENT_STREAM_INPUT:
|
case AISL_EVENT_STREAM_INPUT:
|
||||||
/*printf("AISL> raise AISL_STREAM_INPUT\n");*/
|
stop_propg = aisl_on_stream_input(source, cb->f_ptr, vl_copy);
|
||||||
c_ptr = va_arg(vl, char *);
|
|
||||||
i_val = va_arg(vl, int );
|
|
||||||
res = ((aisl_on_stream_input_t) lst->cb)(source, c_ptr, i_val);
|
|
||||||
break;
|
|
||||||
case AISL_EVENT_STREAM_REQUEST:
|
|
||||||
/*printf("AISL> raise AISL_STREAM_REQUEST\n");*/
|
|
||||||
buffer_clear( STREAM(source)->buffer, 0);
|
|
||||||
res = ((aisl_on_stream_request_t) lst->cb)(source);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case AISL_EVENT_STREAM_ERROR:
|
|
||||||
res = ((aisl_on_stream_error_t) lst->cb)( source, va_arg(vl, char *));
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* response events */
|
|
||||||
case AISL_EVENT_STREAM_OUTPUT:
|
case AISL_EVENT_STREAM_OUTPUT:
|
||||||
res = ((aisl_on_stream_output_t)lst->cb)(
|
stop_propg = aisl_on_stream_output(source, cb->f_ptr, vl_copy);
|
||||||
source,
|
|
||||||
va_arg(vl, uint32_t)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case AISL_EVENT_STREAM_CLOSE:
|
|
||||||
res = ((aisl_on_stream_close_t)lst->cb)( source );
|
|
||||||
aisl_unset_callback_for( instance, source );
|
|
||||||
((aisl_stream_t) source)->u_ptr=NULL;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
res = ((aisl_on_custom_event_t) lst->cb)(source, vl);
|
stop_propg = ((aisl_on_custom_event_t) cb->f_ptr)(source, vl_copy);
|
||||||
}
|
}
|
||||||
if (res) break;
|
|
||||||
|
va_end(vl_copy);
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
if (stop_propg)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
aisl_status_t
|
aisl_status_t
|
||||||
aisl_run_cycle( aisl_t instance )
|
aisl_run_cycle( aisl_t instance )
|
||||||
{
|
{
|
||||||
int max = instance->servers->count+instance->clients->count+instance->delays->count,
|
aisl_status_t result = AISL_IDLE;
|
||||||
cnt = 0;
|
|
||||||
|
|
||||||
|
size_t i = instance->iterator,
|
||||||
|
max = instance->server_spool->count + instance->client_spool->count;
|
||||||
|
|
||||||
switch (instance->stage)
|
while ( result == AISL_IDLE && max != 0)
|
||||||
{
|
{
|
||||||
case STAGE_SERVER:
|
aisl_client_t cli;
|
||||||
while (instance->iterator < instance->servers->count )
|
|
||||||
|
if (i < instance->server_spool->count)
|
||||||
|
{
|
||||||
|
if (instance->client_spool->count < instance->accept_limit)
|
||||||
{
|
{
|
||||||
aisl_server_t srv = (server_t)list_index(instance->servers, instance->iterator++);
|
aisl_server_t srv;
|
||||||
if ( aisl_server_touch(srv) != AISL_IDLE )
|
SSL_CTX * ssl_ctx;
|
||||||
return AISL_SUCCESS;
|
|
||||||
|
|
||||||
if ( ! (++cnt < max) ) return AISL_IDLE;
|
srv = (aisl_server_t) list_index(instance->server_spool, i);
|
||||||
}
|
|
||||||
if ( ! (instance->flags & AISL_HANDLE_HAS_STREAM_LISTENERS) )
|
|
||||||
return AISL_IDLE;
|
|
||||||
|
|
||||||
instance->iterator = 0;
|
ssl_ctx = (aisl_server_get_ssl(srv)) ?
|
||||||
instance->stage++;
|
aisl_get_ssl_ctx(instance, NULL) :
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
result = aisl_server_touch(srv, &cli, ssl_ctx);
|
||||||
|
|
||||||
case STAGE_CLIENT:
|
if (result == AISL_SUCCESS)
|
||||||
while (instance->iterator < instance->clients->count )
|
|
||||||
{
|
|
||||||
int i = instance->iterator++;
|
|
||||||
aisl_client_t cli = list_index(instance->clients, i);
|
|
||||||
bool r = aisl_client_touch( cli );
|
|
||||||
|
|
||||||
if (aisl_client_is_timeout( cli ) )
|
|
||||||
aisl_raise( instance, cli->server, AISL_CLIENT_TIMEOUT, cli );
|
|
||||||
|
|
||||||
if ( cli->fd == -1 )
|
|
||||||
{
|
{
|
||||||
aisl_client_free( cli );
|
if ( list_append(instance->client_spool, cli) != LIST_NAN )
|
||||||
list_remove_index(instance->clients, i);
|
{
|
||||||
|
aisl_raise(instance, cli, AISL_EVENT_CLIENT_CONNECT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aisl_client_free(cli);
|
||||||
|
/* todo: save error message here */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r) return AISL_SUCCESS;
|
|
||||||
|
|
||||||
if ( ! (++cnt < max) ) return AISL_IDLE;
|
|
||||||
}
|
}
|
||||||
instance->iterator = 0;
|
else
|
||||||
instance->stage = 0;
|
{
|
||||||
|
i = instance->server_spool->count;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t j = i - instance->server_spool->count;
|
||||||
|
|
||||||
|
if (j < instance->client_spool->count)
|
||||||
|
{
|
||||||
|
aisl_client_t c = list_index(instance->client_spool, j);
|
||||||
|
|
||||||
|
result = aisl_client_touch(c);
|
||||||
|
|
||||||
|
if (aisl_client_is_timed_out( c, instance->silence_timeout ) )
|
||||||
|
aisl_raise( instance, c, AISL_EVENT_CLIENT_TIMEOUT );
|
||||||
|
|
||||||
|
if ( !aisl_client_is_online(c) )
|
||||||
|
{
|
||||||
|
aisl_client_free( c );
|
||||||
|
list_remove_index(instance->client_spool, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max--;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AISL_IDLE;
|
instance->iterator = i;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -500,8 +532,8 @@ aisl_set_error( aisl_t instance, const char * err_msg )
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
int
|
aisl_status_t
|
||||||
aisl_sleep( aisl_t instance, unsigned long usec )
|
aisl_sleep( aisl_t instance, uint32_t usec )
|
||||||
{
|
{
|
||||||
int maxfd=0,
|
int maxfd=0,
|
||||||
sd;
|
sd;
|
||||||
|
@ -514,9 +546,9 @@ aisl_sleep( aisl_t instance, unsigned long usec )
|
||||||
fd_set fs;
|
fd_set fs;
|
||||||
FD_ZERO (&fs);
|
FD_ZERO (&fs);
|
||||||
|
|
||||||
for (i=0; i<instance->servers->count; i++)
|
for (i=0; i<instance->server_spool->count; i++)
|
||||||
{
|
{
|
||||||
aisl_server_t s = list_index(instance->servers, i);
|
aisl_server_t s = list_index(instance->server_spool, i);
|
||||||
|
|
||||||
sd = aisl_server_get_socket(s);
|
sd = aisl_server_get_socket(s);
|
||||||
|
|
||||||
|
@ -528,10 +560,10 @@ aisl_sleep( aisl_t instance, unsigned long usec )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (i=0; i<instance->clients->count; i++)
|
for (i=0; i<instance->client_spool->count; i++)
|
||||||
{
|
{
|
||||||
aisl_client_t c = list_index(instance->clients, i);
|
aisl_client_t c = list_index(instance->client_spool, i);
|
||||||
sd = aisl_client_get_socket(s);
|
sd = aisl_client_get_socket(c);
|
||||||
if (sd != -1)
|
if (sd != -1)
|
||||||
{
|
{
|
||||||
FD_SET(sd, &fs);
|
FD_SET(sd, &fs);
|
||||||
|
@ -539,8 +571,16 @@ aisl_sleep( aisl_t instance, unsigned long usec )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return select(maxfd+1, &fs, NULL, NULL, &timeout);
|
switch ( select(maxfd+1, &fs, NULL, NULL, &timeout) )
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
return AISL_SYSCALL_ERROR;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
return AISL_IDLE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,34 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
#ifndef AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
||||||
#define INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
#define AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
||||||
|
|
||||||
|
#ifndef AISL_WITHOUT_SSL
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <aisl/instance.h>
|
#include <aisl/instance.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AISL_WITHOUT_SSL
|
||||||
|
/**
|
||||||
|
* @brief Gets SSL context for appropriate server name.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param server_name a null-terminated string with server name or NULL.
|
||||||
|
* @return a pointer to SSL context
|
||||||
|
*/
|
||||||
SSL_CTX *
|
SSL_CTX *
|
||||||
aisl_get_ssl_ctx( aisl_t instance, const char * server_name );
|
aisl_get_ssl_ctx( aisl_t instance, const char * server_name );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets error message for AISL instace.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param err_msge a null-terminated string with error message.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
aisl_set_error( aisl_t instance, const char * err_msg );
|
aisl_set_error( aisl_t instance, const char * err_msg );
|
||||||
|
|
||||||
#endif /* !INSTANCE_H */
|
#endif /* !INSTANCE_H */
|
||||||
|
|
287
src/server.c
287
src/server.c
|
@ -5,201 +5,204 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "server.h"
|
|
||||||
#include "instance.h"
|
|
||||||
#include "client.h"
|
|
||||||
#include "globals.h"
|
|
||||||
#include "str-utils.h"
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
#include "str-utils.h"
|
||||||
|
#include "instance.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "server.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief HTTP(s) server data structure represented by #aisl_server_t pointer.
|
||||||
|
*/
|
||||||
struct aisl_server
|
struct aisl_server
|
||||||
{
|
{
|
||||||
struct sockaddr_in address;
|
struct sockaddr_in address; /**< TCP server address to listen to. */
|
||||||
aisl_t instance;
|
aisl_t instance; /**< Associated AISL instance pointer. */
|
||||||
char * host;
|
int fd; /**< System socket descriptor. */
|
||||||
int fd;
|
bool ssl; /**< SSL enabled/disabled flag. */
|
||||||
int port;
|
|
||||||
int flags;
|
|
||||||
};
|
};
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_set_addres_from_host_and_port( struct sockaddr_in * sa,
|
|
||||||
const char * host,
|
|
||||||
int port )
|
|
||||||
{
|
|
||||||
int rs;
|
|
||||||
struct addrinfo * ai;
|
|
||||||
|
|
||||||
memset(sa, 0, sizeof( struct sockaddr_in ));
|
|
||||||
sa->sin_family = AF_INET;
|
|
||||||
|
|
||||||
rs = getaddrinfo(host, NULL, NULL, &ai);
|
|
||||||
|
|
||||||
if(rs != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sa->sin_addr.s_addr=((struct sockaddr_in*)(ai->ai_addr))->sin_addr.s_addr;
|
|
||||||
sa->sin_port =htons(port);
|
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
static void
|
|
||||||
server_close(server_t self)
|
|
||||||
{
|
|
||||||
close(self->fd);
|
|
||||||
self->fd=-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
static aisl_status_t
|
static aisl_status_t
|
||||||
server_open(server_t self)
|
aisl_server_open(aisl_server_t server)
|
||||||
{
|
{
|
||||||
|
int fd, s_opt = 1;
|
||||||
|
|
||||||
aisl_status_t result = AISL_SUCCESS;
|
fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||||
|
|
||||||
int s_opt = 1;
|
if (fd != -1)
|
||||||
|
|
||||||
if (!_set_addres_from_host_and_port(&self->address, self->host, self->port))
|
|
||||||
return AISL_EXTCALL_ERROR;
|
|
||||||
|
|
||||||
self->fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
|
||||||
|
|
||||||
if (self->fd != -1)
|
|
||||||
{
|
{
|
||||||
setsockopt(
|
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&s_opt, sizeof(int));
|
||||||
self->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&s_opt, sizeof(int)
|
|
||||||
);
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
ioctl(fd, FIONBIO, (char *)&s_opt);
|
||||||
|
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
|
||||||
|
#endif
|
||||||
|
|
||||||
int on = 1;
|
s_opt = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
ioctl(self->fd, FIONBIO, (char *)&on);
|
if (bind(fd, (struct sockaddr *) &server->address, s_opt)==0)
|
||||||
fcntl(self->fd, F_SETFL, fcntl(self->fd, F_GETFL) | O_NONBLOCK);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (bind( self->fd,
|
|
||||||
(struct sockaddr *) &self->address,
|
|
||||||
sizeof(struct sockaddr_in) )==0)
|
|
||||||
{
|
{
|
||||||
if (listen(self->fd, SOMAXCONN) == 0)
|
if (listen(fd, SOMAXCONN) == 0)
|
||||||
return result;
|
{
|
||||||
|
server->fd = fd;
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server_close(self);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = AISL_SYSCALL_ERROR;
|
return AISL_SYSCALL_ERROR;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
* @param ssl_ctx a pointer to SSL context or NULL if connection is unsecure.
|
||||||
|
* @return #aisl_status_t code.
|
||||||
|
*/
|
||||||
|
static aisl_status_t
|
||||||
|
aisl_server_accept( aisl_server_t server,
|
||||||
|
aisl_client_t * p_client,
|
||||||
|
SSL_CTX * ssl_ctx )
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t len = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
*p_client = NULL;
|
||||||
|
|
||||||
bool
|
fd = accept(server->fd, (struct sockaddr *) &addr, &len);
|
||||||
server_touch(server_t self)
|
|
||||||
|
if (fd != -1)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
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, ssl_ctx))) ?
|
||||||
|
AISL_MALLOC_ERROR : AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
else if (errno == EWOULDBLOCK)
|
||||||
|
return AISL_IDLE;
|
||||||
|
|
||||||
|
aisl_raise( server->instance, server, AISL_EVENT_SERVER_ERROR );
|
||||||
|
|
||||||
|
return AISL_SYSCALL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Library Level ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
aisl_status_t
|
||||||
|
aisl_server_touch( aisl_server_t server,
|
||||||
|
aisl_client_t * p_client,
|
||||||
|
SSL_CTX * ssl_ctx )
|
||||||
{
|
{
|
||||||
aisl_status_t result;
|
aisl_status_t result;
|
||||||
client_t cli;
|
|
||||||
|
|
||||||
if (self->fd == -1)
|
if (server->fd == -1)
|
||||||
{
|
{
|
||||||
result = server_open(self);
|
aisl_event_t event;
|
||||||
if (result == AISL_SUCCESS)
|
|
||||||
aisl_raise_event(
|
|
||||||
self->owner,
|
|
||||||
self,
|
|
||||||
AISL_SERVER_OPEN,
|
|
||||||
self->flags
|
|
||||||
);
|
|
||||||
else
|
|
||||||
aisl_raise_event(
|
|
||||||
self->owner,
|
|
||||||
self,
|
|
||||||
AISL_SERVER_ERROR,
|
|
||||||
self->flags,
|
|
||||||
strerror(errno)
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = client_accept(&cli, self);
|
|
||||||
|
|
||||||
if (result == AISL_SUCCESS)
|
|
||||||
{
|
|
||||||
if (list_append(self->owner->clients, cli) == -1)
|
|
||||||
{
|
|
||||||
client_free(cli);
|
|
||||||
result = AISL_MALLOC_ERROR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
aisl_raise_event(self->owner, self, AISL_CLIENT_CONNECT, cli);
|
|
||||||
|
|
||||||
|
result = aisl_server_open(server);
|
||||||
|
event = (result == AISL_SUCCESS) ? AISL_EVENT_SERVER_OPEN
|
||||||
|
: AISL_EVENT_SERVER_ERROR;
|
||||||
|
|
||||||
|
aisl_raise(server->instance, server, event);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
result = aisl_server_accept(server, p_client, ssl_ctx);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* API Level ---------------------------------------------------------------- */
|
||||||
|
|
||||||
server_t
|
aisl_server_t
|
||||||
server_new(const char * address, int port)
|
aisl_server_new(aisl_t instance, const char * host, uint16_t port)
|
||||||
{
|
{
|
||||||
server_t self;
|
aisl_server_t server;
|
||||||
|
|
||||||
if ( (self = calloc(1, sizeof(struct server))) != NULL )
|
if ( (server = calloc(1, sizeof(struct aisl_server))) != NULL )
|
||||||
{
|
{
|
||||||
self->fd = -1;
|
server->instance = instance;
|
||||||
self->port = port;
|
server->fd = -1;
|
||||||
if ( !(self->host = str_copy(address)) )
|
server->address.sin_family = AF_INET;
|
||||||
{
|
server->address.sin_addr.s_addr = inet_addr(host);
|
||||||
free(self);
|
server->address.sin_port = htons(port);
|
||||||
self = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
server_free(server_t self)
|
aisl_server_free(aisl_server_t server)
|
||||||
{
|
{
|
||||||
if (self)
|
if (server)
|
||||||
{
|
{
|
||||||
if (self->fd > -1)
|
if ( server->fd != -1)
|
||||||
server_close(self);
|
{
|
||||||
|
close(server->fd);
|
||||||
|
server->fd=-1;
|
||||||
|
}
|
||||||
|
|
||||||
if (self->host)
|
free(server);
|
||||||
free(self->host);
|
|
||||||
|
|
||||||
free(self);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
aisl_t
|
||||||
|
aisl_server_get_instance( aisl_server_t server )
|
||||||
|
{
|
||||||
|
return server->instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address)
|
||||||
|
{
|
||||||
|
memcpy(address, &server->address, sizeof(struct sockaddr_in));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AISL_WITHOUT_SSL
|
||||||
|
|
||||||
|
void
|
||||||
|
aisl_server_set_ssl( aisl_server_t server, bool value )
|
||||||
|
{
|
||||||
|
server->ssl = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
aisl_server_get_ssl( aisl_server_t server )
|
||||||
|
{
|
||||||
|
return server->ssl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
56
src/server.h
56
src/server.h
|
@ -1,24 +1,64 @@
|
||||||
|
/*
|
||||||
|
* @file src/server.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||||
|
*
|
||||||
|
* Project homepage: https://lowenware.com/aisl/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
|
#ifndef AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
|
||||||
#define AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
|
#define AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <aisl/types.h>
|
|
||||||
#include <aisl/server.h>
|
#include <aisl/server.h>
|
||||||
|
|
||||||
|
#define AISL_SERVER(x) ((aisl_server_t) x)
|
||||||
#define SERVER(x) ((aisl_server_t) x)
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocates and instance of #aisl_server_t.
|
||||||
|
* @param instance a pointer to #aisl_t instance.
|
||||||
|
* @param host a null-terminated string with address to listen to.
|
||||||
|
* @param port a TCP server port number to listen to.
|
||||||
|
* @return a pointer to #aisl_server_t instance.
|
||||||
|
*/
|
||||||
aisl_server_t
|
aisl_server_t
|
||||||
aisl_server_new(aisl_t instance, const char * address, int port);
|
aisl_server_new(aisl_t instance, const char * host, uint16_t port);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Frees memory allocated for #aisl_server_t instance.
|
||||||
|
* @param server a pointer to #aisl_server_t instance.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
aisl_server_free(aisl_server_t self);
|
aisl_server_free(aisl_server_t server);
|
||||||
|
|
||||||
|
|
||||||
bool
|
/**
|
||||||
aisl_server_touch(aisl_server_t self);
|
* @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.
|
||||||
|
* @param ssl_ctx a pointer to SSL context or NULL if connection is unsecure.
|
||||||
|
* @return #aisl_status_t 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,
|
||||||
|
SSL_CTX * ssl_ctx );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a socket descriptor associated with HTTP client.
|
||||||
|
* @param server a pointer to #aisl_server_t instance.
|
||||||
|
* @return a client socket descriptor.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
aisl_server_get_socket(aisl_server_t server);
|
||||||
|
|
||||||
|
|
||||||
#endif /* !AISL_SERVER_H */
|
#endif /* !AISL_SERVER_H */
|
||||||
|
|
|
@ -26,14 +26,11 @@ typedef struct ssl * ssl_t;
|
||||||
|
|
||||||
|
|
||||||
ssl_t
|
ssl_t
|
||||||
ssl_new( const char * key_file, const char * crt_file, const char * domain );
|
ssl_new( const char * key_file, const char * crt_file, const char * domain, SSL_CTX * ctx );
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ssl_free( ssl_t self );
|
ssl_free( ssl_t self );
|
||||||
|
|
||||||
|
|
||||||
SSL_CTX *
|
|
||||||
ssl__new_context( const char * key_file, const char * crt_file, void * u_ptr );
|
|
||||||
|
|
||||||
#endif /* !AISL_SSL_H */
|
#endif /* !AISL_SSL_H */
|
||||||
|
|
14
src/stream.h
14
src/stream.h
|
@ -1,7 +1,7 @@
|
||||||
#ifndef AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
|
#ifndef AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
|
||||||
#define AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
|
#define AISL_STREAM_H_A9EC6601_34B2_4F3E_B631_EEDA8B6EF0D3
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <aisl/types.h>
|
||||||
#include <aisl/stream.h>
|
#include <aisl/stream.h>
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
@ -49,15 +49,12 @@ typedef enum {
|
||||||
/* real wrapper for aisl_stream_t */
|
/* real wrapper for aisl_stream_t */
|
||||||
|
|
||||||
|
|
||||||
typedef struct aisl_stream * aisl_stream_t;
|
#define STREAM(x) ((aisl_stream_t) x)
|
||||||
|
|
||||||
#define STREAM(x) ((stream_t) x)
|
|
||||||
#define ASTREAM(x) ((aisl_stream_t) x)
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
aisl_stream_t
|
aisl_stream_t
|
||||||
aisl_stream_new(struct sockaddr_in *client, int id, stream_state_t state);
|
aisl_stream_new(struct sockaddr_in *client, int id, aisl_stream_state_t state);
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@ -71,4 +68,9 @@ aisl_stream_reset(aisl_stream_t self);
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void
|
||||||
|
aisl_stream_set_chunked_output(aisl_stream_t self, bool value);
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#endif /* !AISL_STREAM_H */
|
#endif /* !AISL_STREAM_H */
|
||||||
|
|
Loading…
Reference in New Issue