Documentation and code base update
This commit is contained in:
parent
3efc86a341
commit
0b05984f85
|
@ -16,6 +16,7 @@ tmp/*
|
|||
*.gz
|
||||
*.bz2
|
||||
pkg/*
|
||||
doc/html
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -12,4 +12,48 @@
|
|||
|
||||
#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 */
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
|
||||
struct aisl_config
|
||||
{
|
||||
uint32_t servers_spool_size;
|
||||
uint32_t clients_spool_size;
|
||||
uint32_t server_spool_size;
|
||||
uint32_t client_spool_size;
|
||||
uint32_t ssl_spool_size;
|
||||
uint32_t callbacks_spool_size;
|
||||
uint32_t callback_spool_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;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* <aisl/instance.h>
|
||||
/**
|
||||
* @file aisl/instance.h
|
||||
*
|
||||
* 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_new( aisl_config_t config );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Frees previously allocated pointer of AISL instance.
|
||||
* @param instance a pointer to #aisl_t instance.
|
||||
*/
|
||||
void
|
||||
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_listen( aisl_t instance, const char * address, uint16_t port );
|
||||
|
||||
|
||||
#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_set_ssl( aisl_t instance,
|
||||
const char * hostname,
|
||||
const char * domain,
|
||||
const char * key_file,
|
||||
const char * crt_file );
|
||||
|
||||
#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_set_callback( aisl_t instance,
|
||||
void * source,
|
||||
|
@ -50,33 +88,69 @@ aisl_set_callback( aisl_t instance,
|
|||
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_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,
|
||||
void * source,
|
||||
aisl_event_t event,
|
||||
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
|
||||
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_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_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 */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* <aisl/server.h>
|
||||
/**
|
||||
* @file aisl/server.h
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd.
|
||||
*
|
||||
|
@ -10,14 +10,46 @@
|
|||
#ifndef 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>
|
||||
#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 );
|
||||
|
||||
|
||||
/**
|
||||
* @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 /* !AISL_SERVER_H */
|
||||
|
|
|
@ -196,6 +196,9 @@ aisl_event_to_string( aisl_event_t event );
|
|||
|
||||
/* real type event callbacks */
|
||||
|
||||
typedef bool
|
||||
(*aisl_on_source_event_t)( void * source );
|
||||
|
||||
typedef bool
|
||||
(*aisl_on_server_open_t)( aisl_server_t server );
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
struct callback
|
||||
{
|
||||
void * source;
|
||||
aisl_callback_t callback;
|
||||
aisl_event_t eevent;
|
||||
aisl_callback_t f_ptr;
|
||||
aisl_event_t event;
|
||||
};
|
||||
|
||||
typedef struct callback * callback_t;
|
||||
|
|
580
src/client.c
580
src/client.c
|
@ -1,3 +1,4 @@
|
|||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
@ -6,117 +7,82 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
#include <aisl/aisl.h>
|
||||
#include "client.h"
|
||||
#include "list.h"
|
||||
#include "stream.h"
|
||||
#include "parser.h"
|
||||
#include "globals.h"
|
||||
#include "handle.h"
|
||||
#include "client.h"
|
||||
|
||||
#ifndef OUTPUT_BUFFER_SIZE
|
||||
#define OUTPUT_BUFFER_SIZE 4096
|
||||
#endif
|
||||
struct client
|
||||
#define FLAG_KEEPALIVE (1<<0)
|
||||
#define FLAG_HANDSHAKE (1<<1)
|
||||
#define FLAG_CAN_READ (1<<2)
|
||||
#define FLAG_CAN_WRITE (1<<3)
|
||||
|
||||
|
||||
struct aisl_client
|
||||
{
|
||||
struct sockaddr_in address;
|
||||
server_t server;
|
||||
int fd;
|
||||
struct sockaddr_in address; /**< Client's address structure */
|
||||
aisl_server_t server; /**< Server instance associated with client */
|
||||
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) */
|
||||
int istream; /* input stream id */
|
||||
int ostream; /* output stream id */
|
||||
list_t streams;
|
||||
SSL * ssl;
|
||||
aisl_stream_t stream; /**< Pending client's stream */
|
||||
/* int next_id; / **< stream id generator (even)*/
|
||||
/* int istream; / **< input stream id */
|
||||
/* int ostream; / **< output stream id */
|
||||
int flags; /**< Client's flag bitmask */
|
||||
int fd; /**< Client's socket descriptor */
|
||||
|
||||
time_t timestamp;
|
||||
aisl_http_version_t protocol;
|
||||
int flags;
|
||||
aisl_http_version_t protocol; /**< Client's protocol version */
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
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
|
||||
client_input(client_t self)
|
||||
aisl_client_raise_event(aisl_client_t client, aisl_event_t event, ...)
|
||||
{
|
||||
int l;
|
||||
parser_status_t p_status = PARSER_PENDING;
|
||||
char *ptr;
|
||||
buffer_t buffer = self->server->owner->buffer;
|
||||
bool result;
|
||||
va_list vl_args;
|
||||
|
||||
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)
|
||||
{
|
||||
if (self->flags & CLIENT_FLAG_HANDSHAKE)
|
||||
{
|
||||
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 */
|
||||
static aisl_status_t
|
||||
aisl_client_parse(aisl_client_t client, char * data, size_t size)
|
||||
{
|
||||
/* parse next data chunk */
|
||||
while ( p_status == PARSER_PENDING )
|
||||
{
|
||||
switch(s->state)
|
||||
{
|
||||
case STREAM_REQUEST_METHOD:
|
||||
p_status = parse_request_method(self, &ptr, &l);
|
||||
p_status = parse_request_method(client, &ptr, &l);
|
||||
break;
|
||||
case STREAM_REQUEST_PATH:
|
||||
p_status = parse_request_path(self, &ptr, &l);
|
||||
p_status = parse_request_path(client, &ptr, &l);
|
||||
break;
|
||||
case STREAM_REQUEST_PROTOCOL:
|
||||
p_status = parse_request_protocol(self, &ptr, &l);
|
||||
p_status = parse_request_protocol(client, &ptr, &l);
|
||||
break;
|
||||
|
||||
case STREAM_REQUEST_HEADER_KEY:
|
||||
p_status = parse_request_header_key(self, &ptr, &l);
|
||||
p_status = parse_request_header_key(client, &ptr, &l);
|
||||
break;
|
||||
case STREAM_REQUEST_HEADER_VALUE:
|
||||
p_status = parse_request_header_value(self, &ptr, &l);
|
||||
p_status = parse_request_header_value(client, &ptr, &l);
|
||||
break;
|
||||
|
||||
case STREAM_REQUEST_CONTENT:
|
||||
p_status = parse_request_content(self, &ptr, &l);
|
||||
p_status = parse_request_content(client, &ptr, &l);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -129,43 +95,95 @@ client_input(client_t self)
|
|||
if (p_status == PARSER_FAILED)
|
||||
{
|
||||
/* reply Bad Request here */
|
||||
client_close(self);
|
||||
client_close(client);
|
||||
}
|
||||
else if (l)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (self->ssl)
|
||||
if (client->ssl)
|
||||
{
|
||||
if (SSL_get_error(self->ssl, l) == SSL_ERROR_WANT_READ)
|
||||
return false;
|
||||
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
|
||||
return AISL_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(errno == EWOULDBLOCK)
|
||||
return false;
|
||||
return AISL_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/* both: client disconnect + on read error */
|
||||
/* todo: raise client error here */
|
||||
client_close(self);
|
||||
client_close(client);
|
||||
|
||||
return true;
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
return true;
|
||||
|
@ -174,7 +192,7 @@ client_output(client_t self)
|
|||
stream_t s;
|
||||
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)
|
||||
|
@ -200,15 +218,15 @@ client_output(client_t self)
|
|||
}
|
||||
|
||||
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)
|
||||
return false;
|
||||
|
||||
l = (self->ssl) ?
|
||||
SSL_write(self->ssl, s->buffer->data, s->buffer->size) :
|
||||
send( self->fd, s->buffer->data, s->buffer->size, 0);
|
||||
l = (client->ssl) ?
|
||||
SSL_write(client->ssl, s->buffer->data, s->buffer->size) :
|
||||
send( client->fd, s->buffer->data, s->buffer->size, 0);
|
||||
|
||||
if (l > 0)
|
||||
{
|
||||
|
@ -220,31 +238,31 @@ client_output(client_t self)
|
|||
|
||||
/* data has been sent */
|
||||
/*
|
||||
if (self->protocol == AISL_HTTP_2_0)
|
||||
if (client->protocol == AISL_HTTP_2_0)
|
||||
{
|
||||
|
||||
}
|
||||
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);
|
||||
|
||||
s = stream_new((struct sockaddr_in *) self, self->next_id++, STREAM_REQUEST_METHOD );
|
||||
list_append(self->streams, s);
|
||||
s = stream_new((struct sockaddr_in *) client, client->next_id++, STREAM_REQUEST_METHOD );
|
||||
list_append(client->streams, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
client_close(self);
|
||||
client_close(client);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
else
|
||||
|
@ -253,223 +271,195 @@ client_output(client_t self)
|
|||
return false;
|
||||
}
|
||||
|
||||
client_close(self);
|
||||
client_close(client);
|
||||
|
||||
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;
|
||||
stream_t s;
|
||||
aisl_client_t client;
|
||||
aisl_stream_t stream;
|
||||
|
||||
/* input */
|
||||
s = list_index(self->streams, self->istream);
|
||||
if ( (client = calloc(1, sizeof(struct client))) != NULL )
|
||||
{
|
||||
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 ((self->protocol==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
|
||||
(client_input(self)) ) result = true;
|
||||
if (buffer_init(client->in, 2*BUFFER_SIZE) == 0)
|
||||
{
|
||||
memcpy(&client->out, client->in, sizeof(struct buffer));
|
||||
|
||||
/* output */
|
||||
s = list_index(self->streams, self->ostream);
|
||||
stream = aisl_stream_new(client, 0, STREAM_REQUEST_METHOD);
|
||||
|
||||
if ( s->flags & (STREAM_FLAG_OUTPUT_READY | STREAM_FLAG_OUTPUT_CHUNKED) )
|
||||
result = client_output(self);
|
||||
if (stream != NULL)
|
||||
{
|
||||
client->stream = stream;
|
||||
|
||||
/* update timestamp */
|
||||
if (result)
|
||||
self->timestamp = time(NULL);
|
||||
#ifdef AISL_WITHOUT_SSL
|
||||
|
||||
return result;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
result = AISL_SYSCALL_ERROR;
|
||||
e_detail = strerror(errno);
|
||||
goto raise;
|
||||
}
|
||||
|
||||
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)) )
|
||||
{
|
||||
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
|
||||
client_free(client_t self)
|
||||
aisl_client_free(aisl_client_t client)
|
||||
{
|
||||
if (self->fd > -1)
|
||||
close(self->fd);
|
||||
aisl_client_close(client);
|
||||
|
||||
if (self->ssl)
|
||||
SSL_free(self->ssl);
|
||||
#ifndef AISL_WITHOUT_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(
|
||||
self->server->owner,
|
||||
self->server,
|
||||
AISL_CLIENT_DISCONNECT,
|
||||
self
|
||||
);
|
||||
/* out buffer is a shared part of input buffer, so no need to free it */
|
||||
|
||||
free(self);
|
||||
list_free(client->streams, (list_destructor_t)aisl_stream_free);
|
||||
|
||||
free(client);
|
||||
}
|
||||
|
||||
/* check if communication time with client is expired ----------------------- */
|
||||
|
||||
bool
|
||||
client_is_timeout(client_t self)
|
||||
aisl_status_t
|
||||
aisl_client_touch(aisl_client_t client)
|
||||
{
|
||||
bool result = false;
|
||||
stream_t s;
|
||||
if (self->protocol == AISL_HTTP_2_0)
|
||||
{
|
||||
aisl_status_t result, status;
|
||||
aisl_stream_t s = client->stream;
|
||||
|
||||
}
|
||||
else
|
||||
/* input */
|
||||
if (client->flags & FLAG_CAN_READ)
|
||||
{
|
||||
s = list_index(self->streams, self->istream);
|
||||
if ( (s->state < STREAM_REQUEST_READY) && /* still waiting for data */
|
||||
(time(NULL)-self->timestamp > AISL_MAX_CLIENT_SILENCE) ) result=true;
|
||||
if ( (result = client_input(client)) < 0 )
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result)
|
||||
client_close(self);
|
||||
/* output */
|
||||
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;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
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
|
||||
#define AISL_CLIENT_H_164FE6B2_E5D4_4968_B50F_823E30E8F777
|
||||
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <aisl/client.h>
|
||||
#include "server.h"
|
||||
#include "list.h"
|
||||
|
||||
#define CLIENT_FLAG_KEEPALIVE (1<<0)
|
||||
#define CLIENT_FLAG_HANDSHAKE (1<<1)
|
||||
#define AISL_CLIENT(x) ((aisl_client_t) x)
|
||||
|
||||
#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_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
|
||||
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);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
aisl_client_close(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.
|
||||
*/
|
||||
int
|
||||
aisl_client_get_socket(aisl_client_t client);
|
||||
|
||||
#endif /* !AISL_CLIENT_H */
|
||||
|
|
404
src/instance.c
404
src/instance.c
|
@ -23,21 +23,15 @@
|
|||
#include "server.h"
|
||||
#include "ssl.h"
|
||||
//#include "globals.h"
|
||||
//#include "stream.h"
|
||||
#include "stream.h"
|
||||
#include "instance.h"
|
||||
|
||||
|
||||
enum {
|
||||
AISL_CYCLE_SERVER = 0
|
||||
, AISL_CYCLE_CLIENT = 1
|
||||
};
|
||||
|
||||
|
||||
struct callback
|
||||
{
|
||||
void * source;
|
||||
aisl_callback_t callback;
|
||||
aisl_event_t eevent;
|
||||
aisl_callback_t f_ptr;
|
||||
aisl_event_t event;
|
||||
};
|
||||
|
||||
typedef struct callback * callback_t;
|
||||
|
@ -45,18 +39,20 @@ typedef struct callback * callback_t;
|
|||
|
||||
struct aisl
|
||||
{
|
||||
list_t servers;
|
||||
list_t clients;
|
||||
list_t callbacks;
|
||||
list_t server_spool;
|
||||
list_t client_spool;
|
||||
list_t callback_spool;
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
list_t ssl;
|
||||
list_t ssl_spool;
|
||||
#endif
|
||||
|
||||
buffer_t buffer;
|
||||
char * last_error;
|
||||
int iterator;
|
||||
int stage;
|
||||
int flags;
|
||||
|
||||
size_t iterator;
|
||||
|
||||
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))) )
|
||||
goto finally;
|
||||
|
||||
if ( !(instance->servers = list_new(config->servers_spool_size)) )
|
||||
if ( !(instance->server_spool = list_new(config->server_spool_size)) )
|
||||
goto release;
|
||||
|
||||
if ( !(instance->clients = list_new(config->clients_spool_size)) )
|
||||
if ( !(instance->client_spool = list_new(config->client_spool_size)) )
|
||||
goto release;
|
||||
|
||||
if ( !(instance->callbacks = list_new(config->callbacks_spool_size)) )
|
||||
if ( !(instance->callback_spool = list_new(config->callback_spool_size)) )
|
||||
goto release;
|
||||
|
||||
if ( !(instance->buffer = buffer_new(config->initial_buffer_size)) )
|
||||
goto release;
|
||||
|
||||
#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;
|
||||
#endif
|
||||
|
||||
instance->accept_limit = config->clients_accept_limit;
|
||||
instance->accept_limit = config->client_accept_limit;
|
||||
instance->silence_timeout = config->client_silence_timeout;
|
||||
|
||||
goto finally;
|
||||
|
||||
|
@ -118,21 +115,21 @@ __attribute__ ((visibility ("default") ))
|
|||
void
|
||||
aisl_free( aisl_t instance )
|
||||
{
|
||||
if (instance->clients)
|
||||
list_free(instance->clients, (list_destructor_t) aisl_client_free );
|
||||
if (instance->client_spool)
|
||||
list_free(instance->client_spool, (list_destructor_t) aisl_client_free );
|
||||
|
||||
if (instance->servers)
|
||||
list_free(instance->servers, (list_destructor_t) aisl_server_free );
|
||||
if (instance->server_spool)
|
||||
list_free(instance->server_spool, (list_destructor_t) aisl_server_free );
|
||||
|
||||
if (instance->callbacks)
|
||||
list_free(instance->callbacks, free);
|
||||
if (instance->callback_spool)
|
||||
list_free(instance->callback_spool, (list_destructor_t) free);
|
||||
|
||||
if (instance->buffer)
|
||||
buffer_free(instance->buffer);
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (instance->ssl)
|
||||
list_free(instance->ssl, (list_destructor_t) ssl_free );
|
||||
if (instance->ssl_spool)
|
||||
list_free(instance->ssl_spool, (list_destructor_t) ssl_free );
|
||||
#endif
|
||||
|
||||
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 (list_append(instance->servers, result) == LIST_NAN)
|
||||
if (list_append(instance->server_spool, result) == LIST_NAN)
|
||||
{
|
||||
aisl_server_free(result);
|
||||
}
|
||||
|
@ -180,34 +177,21 @@ aisl_set_ssl( aisl_t instance, const char * domain,
|
|||
size_t i;
|
||||
|
||||
/* 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 &&
|
||||
ssl->crt_file && strcmp(ssl->crt_file, crt_file)==0 )
|
||||
{
|
||||
if ((ssl_ctx = crypter->ssl_ctx) != NULL)
|
||||
{
|
||||
key_file = NULL;
|
||||
crt_file = NULL;
|
||||
ssl_ctx = ssl->ctx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((ssl = ssl_new(domain, key_file, crt_file)) != NULL)
|
||||
{
|
||||
if (! ssl_ctx)
|
||||
ssl_ctx = ssl__new_context(key_file, crt_file, (void*)instance);
|
||||
|
||||
if (ssl_ctx)
|
||||
{
|
||||
ssl->ctx = ssl_ctx;
|
||||
if (list_append(instance->ssl, ssl) != LIST_NAN)
|
||||
if ((ssl = ssl_new(domain, key_file, crt_file, ssl_ctx)) != NULL)
|
||||
{
|
||||
if (list_append(instance->ssl_spool, ssl) != LIST_NAN)
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
ssl_free(ssl);
|
||||
}
|
||||
|
@ -224,9 +208,9 @@ aisl_get_ssl_ctx( aisl_t instance, const char * 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)
|
||||
continue;
|
||||
|
||||
|
@ -253,20 +237,23 @@ aisl_set_callback( aisl_t instance,
|
|||
{
|
||||
cb->source = source;
|
||||
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)
|
||||
{
|
||||
case AISL_STREAM_OUTPUT:
|
||||
case AISL_EVENT_STREAM_OUTPUT:
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -280,19 +267,19 @@ aisl_set_callback( aisl_t instance,
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
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)
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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") ))
|
||||
bool
|
||||
aisl_raise( aisl_t instance,
|
||||
void * source,
|
||||
aisl_event_t e_id,
|
||||
... )
|
||||
aisl_raise( aisl_t instance, void * source, aisl_event_t event, ... )
|
||||
{
|
||||
va_list vl;
|
||||
bool result;
|
||||
|
||||
va_start(vl, e_id);
|
||||
result = aisl_raise_vl(instance, source, e_id, vl);
|
||||
va_start(vl, event);
|
||||
result = aisl_raise_vl(instance, source, event, vl);
|
||||
va_end(vl);
|
||||
|
||||
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") ))
|
||||
bool
|
||||
aisl_raise_vl( aisl_t instance,
|
||||
void * source,
|
||||
aisl_event_t e_id,
|
||||
va_list vl )
|
||||
aisl_event_t event,
|
||||
va_list vl_args )
|
||||
{
|
||||
int i,
|
||||
i_val;
|
||||
listener_t lst;
|
||||
bool res = false;
|
||||
va_list vl_copy;
|
||||
size_t i;
|
||||
|
||||
char * c_ptr,
|
||||
* c_ptr2;
|
||||
callback_t cb;
|
||||
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 (lst->e_id == e_id && (source == lst->source || lst->source == NULL))
|
||||
if (cb->event == event && (source == cb->source || cb->source == NULL))
|
||||
{
|
||||
/*
|
||||
if (e_id == AISL_STREAM_HEADER)
|
||||
fprintf(stderr,"FOUND HANDLER %d\n", i);
|
||||
*/
|
||||
|
||||
/*printf(" catch\n");*/
|
||||
switch(e_id)
|
||||
va_copy(vl_copy, vl_args);
|
||||
switch(event)
|
||||
{
|
||||
/* server events */
|
||||
case AISL_EVENT_SERVER_OPEN:
|
||||
i_val = va_arg(vl, aisl_status_t);
|
||||
res = ((aisl_on_server_open_t) lst->cb)( source, i_val );
|
||||
break;
|
||||
case AISL_EVENT_SERVER_ERROR:
|
||||
i_val = va_arg(vl, aisl_status_t);
|
||||
c_ptr = va_arg(vl, char *);
|
||||
res = ((aisl_on_server_error_t) lst->cb)( source, i_val, c_ptr );
|
||||
break;
|
||||
|
||||
/* client events */
|
||||
case AISL_EVENT_CLIENT_CONNECT:
|
||||
res = ((aisl_on_client_connect_t) lst->cb)(source, va_arg(vl, void *));
|
||||
break;
|
||||
case AISL_EVENT_CLIENT_DISCONNECT:
|
||||
res = ((aisl_on_client_disconnect_t) lst->cb)(source, va_arg(vl, void*));
|
||||
aisl_unset_callback_for( instance, source );
|
||||
break;
|
||||
case AISL_EVENT_CLIENT_TIMEOUT:
|
||||
res = ((aisl_client_timeout_t) lst->cb)(source, va_arg(vl, void *));
|
||||
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;
|
||||
|
||||
/* request events */
|
||||
case AISL_EVENT_STREAM_OPEN:
|
||||
i_val = va_arg(vl, int);
|
||||
c_ptr = va_arg(vl, char *);
|
||||
c_ptr2 = va_arg(vl, char *);
|
||||
res = ((aisl_on_stream_open_t) lst->cb)(source, i_val, c_ptr, c_ptr2);
|
||||
stop_propg = aisl_on_stream_open(source, cb->f_ptr, vl_copy);
|
||||
break;
|
||||
|
||||
case AISL_EVENT_STREAM_HEADER:
|
||||
c_ptr = va_arg(vl, char *);
|
||||
c_ptr2 = va_arg(vl, char *);
|
||||
res = ((aisl_on_stream_header_t) lst->cb)(source, c_ptr, c_ptr2);
|
||||
stop_propg = aisl_on_stream_header(source, cb->f_ptr, vl_copy);
|
||||
break;
|
||||
|
||||
|
||||
case AISL_EVENT_STREAM_INPUT:
|
||||
/*printf("AISL> raise AISL_STREAM_INPUT\n");*/
|
||||
c_ptr = va_arg(vl, char *);
|
||||
i_val = va_arg(vl, int );
|
||||
res = ((aisl_on_stream_input_t) lst->cb)(source, c_ptr, i_val);
|
||||
break;
|
||||
case AISL_EVENT_STREAM_REQUEST:
|
||||
/*printf("AISL> raise AISL_STREAM_REQUEST\n");*/
|
||||
buffer_clear( STREAM(source)->buffer, 0);
|
||||
res = ((aisl_on_stream_request_t) lst->cb)(source);
|
||||
stop_propg = aisl_on_stream_input(source, cb->f_ptr, vl_copy);
|
||||
break;
|
||||
|
||||
|
||||
case AISL_EVENT_STREAM_ERROR:
|
||||
res = ((aisl_on_stream_error_t) lst->cb)( source, va_arg(vl, char *));
|
||||
break;
|
||||
|
||||
/* response events */
|
||||
case AISL_EVENT_STREAM_OUTPUT:
|
||||
res = ((aisl_on_stream_output_t)lst->cb)(
|
||||
source,
|
||||
va_arg(vl, uint32_t)
|
||||
);
|
||||
break;
|
||||
case AISL_EVENT_STREAM_CLOSE:
|
||||
res = ((aisl_on_stream_close_t)lst->cb)( source );
|
||||
aisl_unset_callback_for( instance, source );
|
||||
((aisl_stream_t) source)->u_ptr=NULL;
|
||||
stop_propg = aisl_on_stream_output(source, cb->f_ptr, vl_copy);
|
||||
break;
|
||||
|
||||
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") ))
|
||||
aisl_status_t
|
||||
aisl_run_cycle( aisl_t instance )
|
||||
{
|
||||
int max = instance->servers->count+instance->clients->count+instance->delays->count,
|
||||
cnt = 0;
|
||||
aisl_status_t result = AISL_IDLE;
|
||||
|
||||
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:
|
||||
while (instance->iterator < instance->servers->count )
|
||||
{
|
||||
aisl_server_t srv = (server_t)list_index(instance->servers, instance->iterator++);
|
||||
if ( aisl_server_touch(srv) != AISL_IDLE )
|
||||
return AISL_SUCCESS;
|
||||
aisl_client_t cli;
|
||||
|
||||
if ( ! (++cnt < max) ) return AISL_IDLE;
|
||||
if (i < instance->server_spool->count)
|
||||
{
|
||||
if (instance->client_spool->count < instance->accept_limit)
|
||||
{
|
||||
aisl_server_t srv;
|
||||
SSL_CTX * ssl_ctx;
|
||||
|
||||
srv = (aisl_server_t) list_index(instance->server_spool, i);
|
||||
|
||||
ssl_ctx = (aisl_server_get_ssl(srv)) ?
|
||||
aisl_get_ssl_ctx(instance, NULL) :
|
||||
NULL;
|
||||
|
||||
result = aisl_server_touch(srv, &cli, ssl_ctx);
|
||||
|
||||
if (result == AISL_SUCCESS)
|
||||
{
|
||||
if ( list_append(instance->client_spool, cli) != LIST_NAN )
|
||||
{
|
||||
aisl_raise(instance, cli, AISL_EVENT_CLIENT_CONNECT);
|
||||
}
|
||||
if ( ! (instance->flags & AISL_HANDLE_HAS_STREAM_LISTENERS) )
|
||||
return AISL_IDLE;
|
||||
|
||||
instance->iterator = 0;
|
||||
instance->stage++;
|
||||
|
||||
|
||||
case STAGE_CLIENT:
|
||||
while (instance->iterator < instance->clients->count )
|
||||
else
|
||||
{
|
||||
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);
|
||||
/* todo: save error message here */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aisl_client_free( cli );
|
||||
list_remove_index(instance->clients, i);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (r) return AISL_SUCCESS;
|
||||
|
||||
if ( ! (++cnt < max) ) return AISL_IDLE;
|
||||
}
|
||||
instance->iterator = 0;
|
||||
instance->stage = 0;
|
||||
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") ))
|
||||
int
|
||||
aisl_sleep( aisl_t instance, unsigned long usec )
|
||||
aisl_status_t
|
||||
aisl_sleep( aisl_t instance, uint32_t usec )
|
||||
{
|
||||
int maxfd=0,
|
||||
sd;
|
||||
|
@ -514,9 +546,9 @@ aisl_sleep( aisl_t instance, unsigned long usec )
|
|||
fd_set 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);
|
||||
|
||||
|
@ -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);
|
||||
sd = aisl_client_get_socket(s);
|
||||
aisl_client_t c = list_index(instance->client_spool, i);
|
||||
sd = aisl_client_get_socket(c);
|
||||
if (sd != -1)
|
||||
{
|
||||
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
|
||||
#define INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
||||
#ifndef AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
||||
#define AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#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 *
|
||||
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
|
||||
aisl_set_error( aisl_t instance, const char * err_msg );
|
||||
|
||||
#endif /* !INSTANCE_H */
|
||||
|
|
281
src/server.c
281
src/server.c
|
@ -5,201 +5,204 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
#include "server.h"
|
||||
#include "instance.h"
|
||||
#include "client.h"
|
||||
#include "globals.h"
|
||||
#include "str-utils.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#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 sockaddr_in address;
|
||||
aisl_t instance;
|
||||
char * host;
|
||||
int fd;
|
||||
int port;
|
||||
int flags;
|
||||
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. */
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
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
|
||||
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 (!_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)
|
||||
if (fd != -1)
|
||||
{
|
||||
setsockopt(
|
||||
self->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&s_opt, sizeof(int)
|
||||
);
|
||||
setsockopt(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);
|
||||
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 (bind(fd, (struct sockaddr *) &server->address, s_opt)==0)
|
||||
{
|
||||
if (listen(self->fd, SOMAXCONN) == 0)
|
||||
return result;
|
||||
if (listen(fd, SOMAXCONN) == 0)
|
||||
{
|
||||
server->fd = fd;
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
server_close(self);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
result = AISL_SYSCALL_ERROR;
|
||||
|
||||
return result;
|
||||
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.
|
||||
* @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
|
||||
server_touch(server_t self)
|
||||
fd = accept(server->fd, (struct sockaddr *) &addr, &len);
|
||||
|
||||
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;
|
||||
client_t cli;
|
||||
|
||||
if (self->fd == -1)
|
||||
if (server->fd == -1)
|
||||
{
|
||||
result = server_open(self);
|
||||
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)
|
||||
);
|
||||
aisl_event_t event;
|
||||
|
||||
return result;
|
||||
}
|
||||
result = aisl_server_open(server);
|
||||
event = (result == AISL_SUCCESS) ? AISL_EVENT_SERVER_OPEN
|
||||
: AISL_EVENT_SERVER_ERROR;
|
||||
|
||||
result = client_accept(&cli, self);
|
||||
|
||||
if (result == AISL_SUCCESS)
|
||||
{
|
||||
if (list_append(self->owner->clients, cli) == -1)
|
||||
{
|
||||
client_free(cli);
|
||||
result = AISL_MALLOC_ERROR;
|
||||
aisl_raise(server->instance, server, event);
|
||||
}
|
||||
else
|
||||
aisl_raise_event(self->owner, self, AISL_CLIENT_CONNECT, cli);
|
||||
|
||||
}
|
||||
result = aisl_server_accept(server, p_client, ssl_ctx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* API Level ---------------------------------------------------------------- */
|
||||
|
||||
server_t
|
||||
server_new(const char * address, int port)
|
||||
aisl_server_t
|
||||
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;
|
||||
self->port = port;
|
||||
if ( !(self->host = str_copy(address)) )
|
||||
{
|
||||
free(self);
|
||||
self = NULL;
|
||||
}
|
||||
server->instance = instance;
|
||||
server->fd = -1;
|
||||
server->address.sin_family = AF_INET;
|
||||
server->address.sin_addr.s_addr = inet_addr(host);
|
||||
server->address.sin_port = htons(port);
|
||||
}
|
||||
|
||||
return self;
|
||||
return server;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
server_free(server_t self)
|
||||
aisl_server_free(aisl_server_t server)
|
||||
{
|
||||
if (self)
|
||||
if (server)
|
||||
{
|
||||
if (self->fd > -1)
|
||||
server_close(self);
|
||||
if ( server->fd != -1)
|
||||
{
|
||||
close(server->fd);
|
||||
server->fd=-1;
|
||||
}
|
||||
|
||||
if (self->host)
|
||||
free(self->host);
|
||||
|
||||
free(self);
|
||||
free(server);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
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
|
||||
#define AISL_SERVER_H_FACD3B4D_0D72_4345_9A30_811103DA9AE2
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <aisl/types.h>
|
||||
#include <aisl/server.h>
|
||||
|
||||
|
||||
#define SERVER(x) ((aisl_server_t) x)
|
||||
#define AISL_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_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
|
||||
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 */
|
||||
|
|
|
@ -26,14 +26,11 @@ typedef struct ssl * 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
|
||||
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 */
|
||||
|
|
14
src/stream.h
14
src/stream.h
|
@ -1,7 +1,7 @@
|
|||
#ifndef 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 "list.h"
|
||||
#include "buffer.h"
|
||||
|
@ -49,15 +49,12 @@ typedef enum {
|
|||
/* real wrapper for aisl_stream_t */
|
||||
|
||||
|
||||
typedef struct aisl_stream * aisl_stream_t;
|
||||
|
||||
#define STREAM(x) ((stream_t) x)
|
||||
#define ASTREAM(x) ((aisl_stream_t) x)
|
||||
#define STREAM(x) ((aisl_stream_t) x)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
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 */
|
||||
|
|
Loading…
Reference in New Issue