Initiated

This commit is contained in:
Ilja Kartašov 2019-02-23 21:06:34 +01:00
commit 4b137d7c55
38 changed files with 4378 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
# Binaries
build/*
root/*
demo/*
bin/*
obj/*
webstuff-*
Makefile
tmp
tmp/*
*.tar.gz
*.zip
*.rar
*.gz
*.bz2
pkg/*
include/webstuff_bak
CMakeCache.txt
CMakeFiles/*
cmake_install.cmake
libaisl.dylib
demo/demo

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "cStuff"]
path = cStuff
url = https://github.com/lowenware/cStuff.git

5
AUTHORS Normal file
View File

@ -0,0 +1,5 @@
(c) Copyright 2017 by Löwenware Ltd.
Developers:
Elias Löwe <el@lowenware.com>
Stanislav Ivanov <hotlinux@mail.ru>

0
CHANGELOG Normal file
View File

131
CMakeLists.txt Normal file
View File

@ -0,0 +1,131 @@
cmake_minimum_required (VERSION 2.8)
project ( AISL C)
set (PROJECT_TITLE "aisl")
set (LIBRARY_NAME ${PROJECT_TITLE})
# set (DEMO_NAME "demo")
# Defaults --------------------------------------------------------------------
include (cmake.compiler)
include (cmake.version)
include (cmake.system)
include (cmake.paths)
# Definitions -----------------------------------------------------------------
add_definitions(
-DPROJECT_TITLE="${PROJECT_TITLE}"
)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fvisibility=hidden")
if(DEFINED CMAKE_DEBUG)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror ")
add_definitions( -DDEBUG=${CMAKE_DEBUG} )
endif()
# Options ---------------------------------------------------------------------
#if( DEFINED WITH_EVERYTHING )
# set(WITH_TEMPLIGHT 1)
# set(WITH_OPTIONS 1)
# set(WITH_CONFIG 1)
#endif()
# Sources ---------------------------------------------------------------------
include_directories( "." ${INCLUDE_DIR} )
add_definitions( -DLIST_WITH_APPEND
-DCSTUFF_LIST_WITH_REMOVE_INDEX
-DCSTUFF_LIST_WITH_REMOVE
-DCSTUFF_LIST_WITH_APPEND
-DCSTUFF_LIST_WITH_INSERT
-DCSTUFF_LIST_WITH_COPY
-DCSTUFF_STR_UTILS_WITH_COPY
-DCSTUFF_STR_UTILS_WITH_NCAT
-DCSTUFF_STR_UTILS_WITH_CMPI
-DCSTUFF_STR_UTILS_WITH_PRINTF
-DCSTUFF_STR_UTILS_WITH_NCOPY
-DSTR_UTILS_WITH_COPY
-DSTR_UTILS_WITH_NCOPY
-DSTR_UTILS_WITH_CAT
-DSTR_UTILS_WITH_PRINTF
-DSTR_UTILS_WITH_CMPI
)
set ( LIBRARY_SOURCES library/aisl.c
library/buffer.c
library/server.c
library/client.c
library/stream.c
library/parser.c
library/http.c
library/handle.c
library/status.c
library/event.c
cStuff/list.c
cStuff/str-utils.c)
set ( DEMO_SOURCES demo/main.c demo/events.c demo/urls.c )
set ( META_FILES README.md LICENSE AUTHORS)
#if( DEFINED WITH_TEMPLIGHT )
# set(SOURCE_FILES ${SOURCE_FILES} ${SOURCES_DIR}/templight.c)
# add_definitions( -DWITH_TEMPLIGHT )
#endif()
#if( DEFINED WITH_OPTIONS )
# set(SOURCE_FILES ${SOURCE_FILES} ${SOURCES_DIR}/options.c)
# add_definitions( -DWITH_OPTIONS )
#endif()
#if( DEFINED WITH_CONFIG )
# set(SOURCE_FILES ${SOURCE_FILES} ${SOURCES_DIR}/config.c)
# add_definitions( -DWITH_CONFIG )
#endif()
find_package(OpenSSL)
include_directories(
${OPENSSL_INCLUDE_DIRS}
)
link_directories(
${OPENSSL_LIBRARY_DIRS}
)
# Library ----------------------------------------------------------------------
add_library(${LIBRARY_NAME} SHARED ${LIBRARY_SOURCES})
# Demos ------------------------------------------------------------------------
#add_executable(${DEMO_NAME} ${DEMO_SOURCES})
#target_link_libraries(${DEMO_NAME} ${LIBRARY_NAME})
target_link_libraries(${LIBRARY_NAME} ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY})
# Installation ----------------------------------------------------------------
install(
TARGETS ${LIBRARY_NAME}
DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
# ${LIB_INSTALL_DIR}
#install(
# FILES ${META_FILES}
# DESTINATION ${SHARE_INSTALL_PREFIX}/doc/packages/${LIBRARY_NAME}/
#)
install(
DIRECTORY ${INCLUDE_DIR}/${LIBRARY_NAME}
DESTINATION ${INCLUDE_INSTALL_DIR}
)

26
LICENSE Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (C) 2014-2017 Elias Löwe <el@lowenware.com>
* Copyright (C) 2014-2017 Löwenware Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

55
README.md Normal file
View File

@ -0,0 +1,55 @@
# AISL
Asynchronous Internet Server Library
## Installation on CentOS 7 / RedHat 7
1. Add repository
```
cd ~
wget http://lowenware.com/rpm/redhat-7/lowenware.repo
sudo mv lowenware.repo /etc/yum.repos.d/
```
2. Import GPG key
```
sudo rpm --import http://lowenware.com/rpm/RPM-GPG-KEY-Lowenware
```
3. Install
```
sudo yum install aisl aisl-devel
```
## Installation on OpenSUSE Tumbleweed
1. Add repository
```
sudo zypper ar http://lowenware.com/rpm/opensuse-tumbleweed/lowenware.repo
```
2. Import GPG key
```
sudo rpm --import http://lowenware.com/rpm/RPM-GPG-KEY-Lowenware
```
3. Install
```
sudo zypper install aisl aisl-devel
```
## Installation from sources on any distro
1. Configuration
```
cmake -DCMAKE_INSTALL_PREFIX=/usr/local
```
2. Compilation
```
make
```
3. Installation
```
sudo make install
```

36
aisl.proj Normal file
View File

@ -0,0 +1,36 @@
name = AISL
todo = aisl.todo
handbook = handbook.md
version:
major = 0
minor = 0
include =
definitions =
profile:
name = debug
flags = -Wall -Werror
definitions =
profile:
name = release
flags =
definitions =
library:
output = aisl
compiler = gcc
version:
major = $version.major
minor = $version.minor
tweak = 0
build = auto
sources = library/aisl.c,
library/buffer.c

1
cStuff Submodule

@ -0,0 +1 @@
Subproject commit a423fa7a6dfbd637f3c0b248123f682456fccad7

7
cmake.compiler Executable file
View File

@ -0,0 +1,7 @@
if(DEFINED CMAKE_DEBUG)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror ")
add_definitions(
-DDEBUG
)
endif()

90
cmake.paths Normal file
View File

@ -0,0 +1,90 @@
# Paths -----------------------------------------------------------------------
# Constants -------------------------------------------------------------------
set(INCLUDE_DIR "include")
set(BUILD_DIR "build")
# CMAKE installation paths ----------------------------------------------------
# -DCMAKE_INSTALL_PREFIX:PATH=/usr
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "/usr")
endif()
# -DINCLUDE_INSTALL_DIR:PATH=/usr/include
if(NOT DEFINED INCLUDE_INSTALL_DIR)
set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include")
endif()
# -DSHARE_INSTALL_PREFIX:PATH=/usr/share
if(NOT DEFINED SHARE_INSTALL_PREFIX)
set(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/share")
endif()
# -DSYSCONF_INSTALL_DIR:PATH=/etc
if(NOT DEFINED SYSCONF_INSTALL_DIR)
set(SYSCONF_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/etc")
endif()
# -DCMAKE_INSTALL_LIBDIR:PATH=lib64
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR "lib${SYSTEM_LIB_SUFFIX}")
endif()
# -DLIB_INSTALL_DIR:PATH=/usr/lib64
if(NOT DEFINED LIB_INSTALL_DIR)
set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif()
# -----------------------------------------------------------------------------
set(PATH_BIN "${CMAKE_INSTALL_PREFIX}/bin")
set(PATH_INC "${INCLUDE_INSTALL_DIR}")
set(PATH_CFG "${SYSCONF_INSTALL_DIR}")
set(PATH_RUN "/var/run")
set(PATH_LIB "${LIB_INSTALL_DIR}")
set(PATH_LOG "/var/log")
set(PATH_RES "${SHARE_INSTALL_PREFIX}")
set(PATH_LNG "${SHARE_INSTALL_PREFIX}/locale")
MESSAGE( STATUS "Paths:")
MESSAGE( STATUS " Prefix: ${CMAKE_INSTALL_PREFIX}" )
MESSAGE( STATUS " Binaries: ${PATH_BIN}" )
MESSAGE( STATUS " Configuration: ${PATH_CFG}" )
MESSAGE( STATUS " Libraries: ${PATH_LIB}" )
MESSAGE( STATUS " Includes: ${PATH_INC}" )
MESSAGE( STATUS " Run: ${PATH_RUN}" )
MESSAGE( STATUS " Log Files: ${PATH_LOG}" )
MESSAGE( STATUS " Resources: ${PATH_RES}" )
MESSAGE( STATUS " Locale Files: ${PATH_LNG}" )
MESSAGE( STATUS "")
# Compiler's Definitions ------------------------------------------------------
add_definitions(
-DPREFIX="${CMAKE_INSTALL_PREFIX}"
-DPATH_BIN="${PATH_BIN}"
-DPATH_CFG="${PATH_CFG}"
-DPATH_INC="${PATH_INC}"
-DPATH_LIB="${PATH_LIB}"
-DPATH_RUN="${PATH_RUN}"
-DPATH_LOG="${PATH_LOG}"
-DPATH_LNG="${PATH_LNG}"
-DPATH_RES="${PATH_RES}"
)
# -----------------------------------------------------------------------------

18
cmake.system Normal file
View File

@ -0,0 +1,18 @@
# Architecture ----------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(SYSTEM_BITNESS 64)
set(SYSTEM_ARCH "amd64")
set(SYSTEM_LIB_SUFFIX "64")
else()
set(SYSTEM_BITNESS 32)
set(SYSTEM_ARCH "x86")
set(SYSTEM_LIB_SUFFIX "")
endif()
add_definitions(
-DSYSTEM_NAME="${CMAKE_SYSTEM_NAME}"
-DSYSTEM_BITNESS=${SYSTEM_BITNESS}
-DSYSTEM_ARCH_${SYSTEM_ARCH}
-DSYSTEM_ARCH="${SYSTEM_ARCH}"
)

61
cmake.version Normal file
View File

@ -0,0 +1,61 @@
# -----------------------------------------------------------------------------
#
# CMake module for paths generation in DEBUG and RELEASE modes
#
# (c) Copyright Löwenware Ltd. (https://lowenware.com/)
#
# -----------------------------------------------------------------------------
## Constants
set (VERSION_FILE "version")
set (
VERSION_REGEX
"^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-(pre|alpha|beta|rc|release))?"
)
# Read file
file (READ ${VERSION_FILE} VERSION_STRING)
# Match file content
string(REGEX MATCH ${VERSION_REGEX} VERSION_STRING ${VERSION_STRING} )
# Set Version constants
set (VERSION_MAJOR ${CMAKE_MATCH_1})
set (VERSION_MINOR ${CMAKE_MATCH_2})
set (VERSION_TWEAK ${CMAKE_MATCH_3})
if (CMAKE_MATCH_5 STREQUAL "pre")
set(VERSION_CYCLE 1)
elseif (CMAKE_MATCH_5 STREQUAL "alpha")
set (VERSION_CYCLE 2)
elseif (CMAKE_MATCH_5 STREQUAL "beta")
set (VERSION_CYCLE 3)
elseif (CMAKE_MATCH_5 STREQUAL "rc")
set (VERSION_CYCLE 4)
else()
set (VERSION_CYCLE 0)
endif()
set (VERSION_LABEL ${CMAKE_MATCH_4})
# Add compiler macros
add_definitions(
-DVERSION_MAJOR=${VERSION_MAJOR}
-DVERSION_MINOR=${VERSION_MINOR}
-DVERSION_TWEAK=${VERSION_TWEAK}
-DVERSION_CYCLE=${VERSION_CYCLE}
-DVERSION_LABEL="${VERSION_LABEL}"
)
#Print output
MESSAGE(
STATUS "${PROJECT_TITLE} version: " ${VERSION_MAJOR} "."
${VERSION_MINOR} "."
${VERSION_TWEAK} "-"
${VERSION_CYCLE_TEXT} " "
${VERSION_LABEL}
)

107
include/aisl/aisl.h Normal file
View File

@ -0,0 +1,107 @@
/* ----------------------------------------------------------------------------
* aisl.h - header file for AISL library, part of AISLing Technology
*
* Copyright (c) 2017 by Löwenware Ltd. (https://lowenware.com/)
*
* Authors and maintainers:
* Ilja Kartaschoff <ik@lowenware.com>
*
* DOCUMENTATION
* This file is not designed to be used as a documentation, but for looking at
* the precise values of constants and definitions.
* Please, for documentation refer to web page https://lowenware.com/aisling/ or
* file READEME.md from library source package.
*
* LICENSE and DISCLAIMER
*
* -------------------------------------------------------------------------- */
#ifndef _AISL_H_
#define _AISL_H_
/* system includes ---------------------------------------------------------- */
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <arpa/inet.h>
/* aisl includes ------------------------------------------------------------ */
#include <aisl/status.h>
#include <aisl/event.h>
#include <aisl/stream.h>
#include <aisl/handle.h>
#include <aisl/http.h>
/* Control calls ------------------------------------------------------------ */
/* DEPRECATED, use aisl_handle_new instead
* */
aisl_status_t
aisl_init();
/* DEPRECATED, use aisl_handle_free instead
* */
void
aisl_release();
/* Tell library what socket should be opened. Could be called multiple times.
* This function only save passed data. In fact, sockets are being opened only
* inside aisl_run loop.
* @address : host or IP to listen
* @port : port to listen
* */
aisl_status_t
aisl_select(const char *address, int port);
/* Start main loop
* @result : exit code
* */
aisl_status_t
aisl_run( int * flags );
/* Event calls -------------------------------------------------------------- */
/* Add callback to be executed after timeout. If callback function will return
* true, callback will be kept in main loop and raised again, otherwise it will
* be removed
* @cb : callback function: bool callback (void * u_data)
* @usec : delay in milliseconds
* @data : user-defined data to be passed to callback
* */
aisl_status_t
aisl_delay(aisl_callback_t cb, uint32_t msec, void *u_data);
/* Add event listener
* @source : pointer to event source
* @e_id : event identifier
* @cb : callback to be executed
* */
aisl_status_t
aisl_listen(void *source, aisl_event_t e_id, aisl_callback_t cb);
/* Raise event
* @source : pointer to event source data
* @e_id : event identifier
* @... : custom event data
* @result : true if event was handled, false otherwise
* */
bool
aisl_raise(void *source, aisl_event_t e_id, ... );
/* input stream functions --------------------------------------------------- */
const char *
aisl_header_get(aisl_stream_t stream, const char *key);
const char *
aisl_header_get_by_index(aisl_stream_t stream, const char **key, uint32_t i);
/* -------------------------------------------------------------------------- */
#endif

128
include/aisl/event.h Normal file
View File

@ -0,0 +1,128 @@
#ifndef _AISL_EVENT_H_
#define _AISL_EVENT_H_
#include <stdbool.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <aisl/stream.h>
#include <aisl/status.h>
#include <aisl/http.h>
/* -------------------------------------------------------------------------- */
typedef unsigned int aisl_event_t;
/* -------------------------------------------------------------------------- */
typedef enum
{
AISL_SERVER_OPEN = 100,
AISL_SERVER_ERROR = 190,
AISL_CLIENT_CONNECT = 200,
AISL_CLIENT_DISCONNECT = 210,
AISL_CLIENT_TIMEOUT = 220,
AISL_STREAM_OPEN = 300, /* 5 - headers recieved */
AISL_STREAM_HEADER = 310, /* 5 - headers recieved */
AISL_STREAM_INPUT = 320, /* 6 - chunk of data transmission */
AISL_STREAM_REQUEST = 330, /* 7 - data received, response required */
AISL_STREAM_OUTPUT = 340,/* event for long-size responses optimal handling */
AISL_STREAM_CLOSE = 350,
AISL_STREAM_ERROR = 390, /* 8 - bad request */
AISL_EVENTS_CUSTOM = 999
} aisl_event_id_t;
/* -------------------------------------------------------------------------- */
/* AISL_SERVER_OPEN event handler */
typedef bool
(*aisl_server_open_t)( aisl_server_t server,
int flags );
/* AISL_SERVER_ERROR event handler */
typedef bool
(*aisl_server_error_t)( aisl_server_t server,
int flags,
const char * details );
/* AISL_CLIENT_CONNECT event handler */
typedef bool
(*aisl_client_connect_t)( aisl_server_t server,
aisl_client_t client );
/* AISL_CLIENT_DISCONNECT event handler */
typedef bool
(*aisl_client_disconnect_t)( aisl_server_t server,
aisl_client_t client );
/* AISL_CLIENT_DISCONNECT event handler */
typedef bool
(*aisl_client_timeout_t)( aisl_server_t server,
aisl_client_t client );
/* AISL_STREAM_OPEN event handler */
typedef bool
(*aisl_stream_open_t)( aisl_stream_t s,
aisl_http_method_t method,
const char * path,
const char * query );
typedef bool
(*aisl_stream_header_t)( aisl_stream_t s,
const char * key,
const char * value );
/* AISL_STREAM_INPUT event handler */
typedef bool
(*aisl_stream_input_t)( aisl_stream_t s,
char * data,
int len );
/* AISL_STREAM_REQUEST event handler */
typedef bool
(*aisl_stream_request_t)( aisl_stream_t s );
/* AISL_STREAM_OUTPUT event handler */
typedef bool
(*aisl_stream_output_t)( aisl_stream_t s,
uint32_t buffer_space );
typedef bool
(*aisl_stream_close_t)( aisl_stream_t s );
/* AISL_STREAM_ERROR event handler */
typedef bool
(*aisl_stream_error_t)( aisl_stream_t s,
const char * details );
/* CUSTOM event_handler */
typedef bool
(*aisl_custom_event_t)( void * source,
va_list vl );
/* on delay timeout */
typedef bool
(*aisl_delay_timeout_t)( void * u_data );
/* -------------------------------------------------------------------------- */
/* type for event callbacks to use in structures and function prototypes */
typedef bool
(* aisl_callback_t) (void);
/* cast callback as aisl_callback_t */
#define AISL_CALLBACK(x) ((aisl_callback_t) x)
/* -------------------------------------------------------------------------- */
const char *
aisl_event_get_text( aisl_event_t e_id );
/* -------------------------------------------------------------------------- */
#endif

76
include/aisl/handle.h Normal file
View File

@ -0,0 +1,76 @@
#ifndef _AISL_HANDLE_H_
#define _AISL_HANDLE_H_
#include <aisl/status.h>
#include <aisl/event.h>
/* -------------------------------------------------------------------------- */
#define AISL_FLAG_SSL (1<<0)
/* -------------------------------------------------------------------------- */
typedef struct aisl_handle * aisl_handle_t;
/* -------------------------------------------------------------------------- */
aisl_handle_t
aisl_handle_new(size_t min_clients, size_t buffer_size);
/* -------------------------------------------------------------------------- */
aisl_handle_t
aisl_handle_from_stream( aisl_stream_t s );
/* -------------------------------------------------------------------------- */
void
aisl_handle_free( aisl_handle_t self );
/* -------------------------------------------------------------------------- */
aisl_status_t
aisl_bind( aisl_handle_t self, const char * address, int port, int flags );
/* -------------------------------------------------------------------------- */
aisl_status_t
aisl_set_ssl( aisl_handle_t self, const char * server_name,
const char * key_file,
const char * crt_file );
/* -------------------------------------------------------------------------- */
aisl_status_t
aisl_set_callback( aisl_handle_t self,
void * source,
aisl_event_t e_id,
aisl_callback_t cb );
/* -------------------------------------------------------------------------- */
bool
aisl_raise_event( aisl_handle_t self,
void * source,
aisl_event_t e_id,
... );
/* -------------------------------------------------------------------------- */
aisl_status_t
aisl_run_cycle( aisl_handle_t self );
/* -------------------------------------------------------------------------- */
const char *
aisl_handle_get_error( aisl_handle_t self );
/* -------------------------------------------------------------------------- */
int
aisl_sleep( aisl_handle_t self, unsigned long usec );
/* -------------------------------------------------------------------------- */
#endif

104
include/aisl/http.h Normal file
View File

@ -0,0 +1,104 @@
#ifndef _AISL_HTTP_H_
#define _AISL_HTTP_H_
/* -------------------------------------------------------------------------- */
typedef enum
{
AISL_HTTP_1_0,
AISL_HTTP_1_1,
AISL_HTTP_2_0
} aisl_http_version_t;
/* -------------------------------------------------------------------------- */
typedef enum {
AISL_HTTP_GET,
AISL_HTTP_PUT,
AISL_HTTP_POST,
AISL_HTTP_HEAD,
AISL_HTTP_TRACE,
AISL_HTTP_DELETE,
AISL_HTTP_OPTIONS,
AISL_HTTP_CONNECT,
AISL_HTTP_PRI
} aisl_http_method_t;
/* -------------------------------------------------------------------------- */
typedef enum
{
/* informational ------------------------------ */
AISL_HTTP_CONTINUE = 100,
AISL_HTTP_SWITCHING_PROTOCOLS,
/* Successful --------------------------------- */
AISL_HTTP_OK = 200,
AISL_HTTP_CREATED,
AISL_HTTP_ACCEPTED,
AISL_HTTP_NON_AUTHORITATIVE_INFORMATION,
AISL_HTTP_NO_CONTENT,
AISL_HTTP_RESET_CONTENT,
AISL_HTTP_PARTIAL_CONTENT,
/* redirection -------------------------------- */
AISL_HTTP_MULTIPLE_CHOICES = 300,
AISL_HTTP_MOVED_PERMANENTLY,
AISL_HTTP_FOUND,
AISL_HTTP_SEE_OTHER,
AISL_HTTP_NOT_MODIFIED,
AISL_HTTP_USE_PROXY,
AISL_HTTP_UNUSED,
AISL_HTTP_TEMPORARY_REDIRECT,
/* client error ------------------------------- */
AISL_HTTP_BAD_REQUEST = 400,
AISL_HTTP_UNAUTHORIZED,
AISL_HTTP_PAYMENT_REQUIRED,
AISL_HTTP_FORBIDDEN,
AISL_HTTP_NOT_FOUND,
AISL_HTTP_METHOD_NOT_ALLOWED,
AISL_HTTP_NOT_ACCEPTABLE,
AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED,
AISL_HTTP_REQUEST_TIMEOUT,
AISL_HTTP_CONFLICT,
AISL_HTTP_GONE,
AISL_HTTP_LENGTH_REQUIRED,
AISL_HTTP_PRECONDITION_FAILED,
AISL_HTTP_REQUEST_ENTITY_TOO_LARGE,
AISL_HTTP_REQUEST_URI_TOO_LONG,
AISL_HTTP_UNSUPPORTED_MEDIA_TYPE,
AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE,
AISL_HTTP_EXPECTATION_FAILED,
/* server error ------------------------------- */
AISL_HTTP_INTERNAL_SERVER_ERROR = 500,
AISL_HTTP_NOT_IMPLEMENTED,
AISL_HTTP_BAD_GATEWAY,
AISL_HTTP_SERVICE_UNAVAILABLE,
AISL_HTTP_GATEWAY_TIMEOUT,
AISL_HTTP_VERSION_NOT_SUPPORTED
} aisl_http_response_t;
/* -------------------------------------------------------------------------- */
const char *
aisl_http_version_to_string(aisl_http_version_t version);
/* -------------------------------------------------------------------------- */
const char *
aisl_http_response_to_string(aisl_http_response_t code);
/* -------------------------------------------------------------------------- */
const char *
aisl_http_secure_to_string( int is_secure );
/* -------------------------------------------------------------------------- */
const char *
aisl_http_method_to_string( aisl_http_method_t method );
/* -------------------------------------------------------------------------- */
#endif

24
include/aisl/status.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _AISL_STATUS_H_
#define _AISL_STATUS_H_
/* -------------------------------------------------------------------------- */
typedef enum {
AISL_EXTCALL_ERROR = -3,
AISL_SYSCALL_ERROR = -2,
AISL_MALLOC_ERROR = -1,
AISL_SUCCESS = 0,
AISL_IDLE = 1
} aisl_status_t;
/* -------------------------------------------------------------------------- */
const char *
aisl_status_to_string(aisl_status_t status);
/* -------------------------------------------------------------------------- */
#endif

172
include/aisl/stream.h Normal file
View File

@ -0,0 +1,172 @@
#ifndef _AISL_STREAM_H_
#define _AISL_STREAM_H_
#include <arpa/inet.h>
/* Library statuses */
/* HTTP requests */
#include <aisl/http.h>
#include <aisl/status.h>
/* -------------------------------------------------------------------------- */
typedef struct sockaddr_in * aisl_server_t;
typedef struct sockaddr_in * aisl_client_t;
struct aisl_stream
{
/* DO NOT USE PROPERTIES DIRECTLY IN NEW CODE */
struct sockaddr_in *client;
const char *host;
const char *path;
const char *query;
const char *scheme;
void *u_ptr; /* pointer to bind custom data to stream */
aisl_http_method_t request_method;
};
/* pointer to stream descriptor */
typedef struct aisl_stream * aisl_stream_t;
/* -------------------------------------------------------------------------- */
/* start response to client
* this function should be called before any header or content function
* necessary protocol headers as well as Content-Type and Content-Length
* will be set automaticaly
* @stream : stream instance
* @status : HTTP response status code (default 200)
* @content_type : string with content type (default text/html), NULL -> no
* @content_length : length of content, 0 = no content
* */
aisl_status_t
aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
const char *content_type,
uint32_t content_length);
/* send all buffered data to client
* ALL responses should always be finished with calling of this method
* @stream : stream instance
* */
aisl_status_t
aisl_flush(aisl_stream_t stream);
/* header functions --------------------------------------------------------- */
/* add custom header to stream
* this function should be called before content functions
* @stream : stream instance
* @key : header key string
* @value : header value string
* */
int
aisl_header(aisl_stream_t stream, const char *key, const char *value);
/* add custom header to stream
* this function should be called before content functions
* @stream : stream instance
* @key : header key string
* @f_value : value format string, same as for printf function
* @... : arguments according to f_value string
* */
int
aisl_header_printf(aisl_stream_t stream, const char *key,
const char *f_value, ...);
/* add custom header to stream
* this function should be called before content functions
* @stream : stream instance
* @key : header key string
* @f_value : value format string, same as for printf function
* @args : arguments macro according to f_value string
* */
int
aisl_header_vprintf(aisl_stream_t stream, const char *key,
const char *format,
va_list args);
/* data response functions -------------------------------------------------- */
/* response formated data to client
* @stream : stream instance
* @format : format string, same as for printf
* @... : arguments according to format string
* @result : number of responed bytes
* */
int
aisl_printf(aisl_stream_t stream, const char *format, ...);
/* response formated data to client
* @stream : stream instance
* @format : format string, same as for printf
* @args : arguments macro according to format string
* @result : number of responed bytes
* */
int
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args);
/* response characters to client
* @stream : stream instance
* @data : characters to be sent
* @d_len : number of characters to send
* @result : number of responed bytes
* */
int
aisl_write(aisl_stream_t s, const char *data, int d_len);
/* response string to client
* @string : string to be sent
* @stream : stream instance
* @result : number of responed bytes
* */
int
aisl_puts(const char *string, aisl_stream_t stream);
/* -------------------------------------------------------------------------- */
void
aisl_cancel(aisl_stream_t s);
/* -------------------------------------------------------------------------- */
bool
aisl_is_secure(aisl_stream_t s);
/* -------------------------------------------------------------------------- */
void *
aisl_get_context(aisl_stream_t s);
/* -------------------------------------------------------------------------- */
void
aisl_set_context(aisl_stream_t s, void * u_ptr);
/* -------------------------------------------------------------------------- */
aisl_client_t
aisl_get_client(aisl_stream_t s);
/* -------------------------------------------------------------------------- */
aisl_server_t
aisl_get_server(aisl_stream_t s);
/* -------------------------------------------------------------------------- */
aisl_http_version_t
aisl_get_http_version(aisl_stream_t s);
/* -------------------------------------------------------------------------- */
void
aisl_reject( aisl_stream_t s);
/* -------------------------------------------------------------------------- */
#endif

367
library/aisl.c Normal file
View File

@ -0,0 +1,367 @@
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>
#include <sys/time.h>
#include <aisl/aisl.h>
#include <cStuff/list.h>
#include <cStuff/str-utils.h>
#include "handle.h"
#include "client.h"
#include "server.h"
#include "globals.h"
#include "stream.h"
#include "buffer.h"
/* Globals ------------------------------------------------------------------ */
#define AISL_TERMINATED 1
aisl_handle_t gHandle = NULL;
/* DEPRECATED --------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_init( )
{
gHandle = aisl_handle_new( AISL_MIN_CLIENTS, AISL_BUFFER_SIZE );
return (gHandle != NULL) ? AISL_SUCCESS : AISL_MALLOC_ERROR;
}
/* DEPRECATED --------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_release()
{
aisl_handle_free(gHandle);
}
/* DEPRECATED --------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_select(const char * address, int port)
{
return aisl_bind(gHandle, address, port, 0);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_run( int * flags )
{
aisl_status_t exit_code = AISL_SUCCESS;
struct timeval timeout = {0,0};
while( !(*flags & AISL_TERMINATED) )
{
if ( (exit_code = aisl_run_cycle( gHandle )) == AISL_IDLE )
{
timeout.tv_usec = 300;
timeout.tv_sec = 0;
select(0, NULL, NULL, NULL, &timeout);
}
}
return exit_code;
}
/* Event calls -------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_delay( aisl_callback_t cb, uint32_t usec, void * u_data )
{
return aisl_set_delay(gHandle, cb, usec, u_data);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_listen( void * source, aisl_event_t e_id, aisl_callback_t cb )
{
return aisl_set_callback( gHandle, source, e_id, cb );
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
bool
aisl_raise( void *source, aisl_event_t e_id, ... )
{
bool result;
va_list vl;
va_start(vl, e_id);
result = aisl_raise_event_vl( gHandle, source, e_id, vl);
va_end(vl);
return result;
}
__attribute__ ((visibility ("default") ))
const char *
aisl_header_get(aisl_stream_t stream, const char *key)
{
int i;
if (STREAM(stream)->headers)
{
for (i=0; i< STREAM(stream)->headers->count; i++)
{
if (str_cmpi(((pair_t)list_index(STREAM(stream)->headers,i))->key,key)==0)
return ((pair_t) list_index(STREAM(stream)->headers,i))->value;
}
}
return NULL;
}
/* response functions ------------------------------------------------------- */
static char *
get_response_begin(stream_t stream)
{
char * r;
client_t cli = CLIENT(ASTREAM(stream)->client);
r = str_printf(
"%s %d %s\r\n"
"Server: AISL\r\n"
"Connection: %s\r\n\r\n",
aisl_http_version_to_string(cli->protocol),
stream->response,
aisl_http_response_to_string(stream->response),
((cli->flags & CLIENT_FLAG_KEEPALIVE) ? "keep-alive" : "close")
);
return r;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
const char *content_type,
uint32_t content_length)
{
char * pch;
int l;
/* check if those headers were already sent */
if (STREAM(stream)->state > STREAM_REQUEST_READY) return AISL_IDLE;
STREAM(stream)->response = status_code;
STREAM(stream)->c_type = content_type;
STREAM(stream)->c_length = content_length;
if ( !(pch = get_response_begin(STREAM(stream))) )
return AISL_MALLOC_ERROR;
l = strlen(pch);
STREAM(stream)->c_offset = l-2;
buffer_clear(STREAM(stream)->buffer, content_length);
l = buffer_add( STREAM(stream)->buffer, pch, l );
free(pch);
if (l == BUFFER_EOB) return AISL_MALLOC_ERROR;
if (content_length)
{
if (!aisl_header_printf( stream, "Content-Length", "%u", content_length ))
return AISL_MALLOC_ERROR;
}
if (content_type)
{
if (!aisl_header( stream, "Content-Type", content_type ))
return AISL_MALLOC_ERROR;
}
STREAM(stream)->state = STREAM_RESPONSE_HEADER;
return AISL_SUCCESS;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_flush(aisl_stream_t stream)
{
stream_t s = STREAM(stream);
if ( ! s->c_length )
{
s->c_length = s->buffer->size - s->c_offset - 2;
if (!aisl_header_printf(stream, "Content-Length", "%u", s->c_length))
return AISL_MALLOC_ERROR;
}
/*
fprintf(stdout, "(%lu bytes)------->\n", STREAM(stream)->buffer->size);
fwrite(STREAM(stream)->buffer->data, 1, STREAM(stream)->buffer->size, stdout);
fprintf(stdout, "<------\n");
*/
s->state = STREAM_RESPONSE_READY;
s->flags |= STREAM_FLAG_OUTPUT_READY;
return AISL_SUCCESS;
}
/* header functions --------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_header(aisl_stream_t stream, const char *key, const char *value)
{
int ret;
char * pch;
if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL )
{
ret = strlen(pch);
if ( buffer_insert(
STREAM(stream)->buffer,
STREAM(stream)->c_offset,
pch,
ret
) == BUFFER_EOB )
{
ret = -1;
}
else
STREAM(stream)->c_offset += ret;
free(pch);
}
else
ret = -1;
return ret;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_header_printf(aisl_stream_t stream, const char *key,
const char *f_value, ...)
{
int ret;
va_list arg;
va_start(arg, f_value);
ret = aisl_header_vprintf(stream, key, f_value, arg);
va_end(arg);
return ret;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_header_vprintf(aisl_stream_t stream, const char *key,
const char *format,
va_list args)
{
int ret;
char * value;
if ( (value = str_vprintf(format, args)) != NULL )
{
ret = aisl_header( stream, key, value );
free(value);
}
else
ret = -1;
return ret;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_printf(aisl_stream_t stream, const char *format, ...)
{
va_list arg;
va_start(arg, format);
int result = aisl_vprintf(stream, format, arg);
va_end(arg);
/* No need to update length there, because vprintf do that
*
* if (STREAM(stream)->c_length_unknown)
STREAM(stream)->c_length += result;
*/
return result;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
{
int result;
char * r;
if ( (r = str_vprintf(format, args)) != NULL)
{
result = strlen(r);
if (buffer_add(STREAM(stream)->buffer, r, result) == BUFFER_EOB)
result = -1;
free(r);
}
else
result = -1;
return result;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_write(aisl_stream_t stream, const char *data, int d_len)
{
if (d_len < 0)
d_len = strlen(data);
if (buffer_add(STREAM(stream)->buffer, data, d_len) == BUFFER_EOB)
d_len = -1;
return d_len;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_puts(const char *str, aisl_stream_t stream)
{
return aisl_write( stream, str, strlen(str));
}
/* -------------------------------------------------------------------------- */

129
library/buffer.c Normal file
View File

@ -0,0 +1,129 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "buffer.h"
/* -------------------------------------------------------------------------- */
buffer_t
buffer_new( size_t initial_size )
{
buffer_t self;
if ( (self = calloc(1, sizeof(struct buffer))) != NULL)
{
if ( (self->size = initial_size) > 0 )
{
if ( !(self->data = calloc( initial_size+1, sizeof(char) )) )
{
free(self);
self = NULL;
}
}
}
return self;
}
/* -------------------------------------------------------------------------- */
void
buffer_free( buffer_t self )
{
if (self->data)
free(self->data);
free(self);
}
/* -------------------------------------------------------------------------- */
size_t
buffer_add( buffer_t self, const char * data, size_t size )
{
size_t result = size+self->size;
char * ptr;
if ( (ptr = realloc(self->data, result+1)) != NULL )
{
memcpy( &ptr[self->size], data, size );
ptr[ result ] = 0;
self->data = ptr;
self->size = result;
}
else
result = BUFFER_EOB;
return result;
}
/* -------------------------------------------------------------------------- */
size_t
buffer_clear( buffer_t self, size_t to_alloc )
{
char * data;
self->size = 0;
if (to_alloc)
{
if ( (data = realloc(self->data, to_alloc)) != NULL )
{
self->data = data;
return to_alloc;
}
}
free(self->data);
self->data = NULL;
return 0;
}
/* -------------------------------------------------------------------------- */
size_t
buffer_shift( buffer_t self, size_t size )
{
size_t result;
if (size && !(size > self->size))
{
result = self->size - size;
memmove(self->data, &self->data[size], result);
self->size = result;
}
else
result = BUFFER_EOB;
return result;
}
/* -------------------------------------------------------------------------- */
size_t
buffer_insert( buffer_t self, size_t offset, const char * data, size_t size )
{
size_t result = size + self->size;
char * ptr;
if ( (ptr = realloc(self->data, result+1)) != NULL )
{
memmove( &ptr[offset+size], &ptr[offset], self->size - offset );
memcpy( &ptr[offset], data, size );
ptr[ result ] = 0;
self->data = ptr;
self->size = result;
}
else
result = BUFFER_EOB;
return result;
}
/* -------------------------------------------------------------------------- */

49
library/buffer.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef _AISL_BUFFER_H_
#define _AISL_BUFFER_H_
#include <sys/types.h>
/* -------------------------------------------------------------------------- */
struct buffer
{
char * data;
size_t size;
};
typedef struct buffer * buffer_t;
#define BUFFER_EOB ( ~0 )
/* -------------------------------------------------------------------------- */
buffer_t
buffer_new( size_t initial_size );
/* -------------------------------------------------------------------------- */
void
buffer_free( buffer_t self );
/* -------------------------------------------------------------------------- */
size_t
buffer_insert( buffer_t self, size_t offset, const char * data, size_t size );
/* -------------------------------------------------------------------------- */
size_t
buffer_add( buffer_t self, const char * data, size_t size );
/* -------------------------------------------------------------------------- */
size_t
buffer_clear( buffer_t self, size_t to_alloc );
/* -------------------------------------------------------------------------- */
size_t
buffer_shift( buffer_t self, size_t size );
/* -------------------------------------------------------------------------- */
#endif

460
library/client.c Normal file
View File

@ -0,0 +1,460 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <aisl/aisl.h>
#include "client.h"
#include "stream.h"
#include "parser.h"
#include "globals.h"
#include "handle.h"
#ifndef OUTPUT_BUFFER_SIZE
#define OUTPUT_BUFFER_SIZE 4096
#endif
/* -------------------------------------------------------------------------- */
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)
{
int l;
parser_status_t p_status = PARSER_PENDING;
char *ptr;
buffer_t buffer = self->server->owner->buffer;
stream_t s = list_index(self->streams, self->istream);
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 */
while ( p_status == PARSER_PENDING )
{
switch(s->state)
{
case STREAM_REQUEST_METHOD:
p_status = parse_request_method(self, &ptr, &l);
break;
case STREAM_REQUEST_PATH:
p_status = parse_request_path(self, &ptr, &l);
break;
case STREAM_REQUEST_PROTOCOL:
p_status = parse_request_protocol(self, &ptr, &l);
break;
case STREAM_REQUEST_HEADER_KEY:
p_status = parse_request_header_key(self, &ptr, &l);
break;
case STREAM_REQUEST_HEADER_VALUE:
p_status = parse_request_header_value(self, &ptr, &l);
break;
case STREAM_REQUEST_CONTENT:
p_status = parse_request_content(self, &ptr, &l);
break;
default:
p_status = PARSER_FINISHED;
/* this is error actually */
}
}
if (p_status == PARSER_FAILED)
{
/* reply Bad Request here */
client_close(self);
}
else if (l)
{
buffer_shift(s->buffer, s->buffer->size-l); /* reset buffer */
}
/*
else
buffer_clear(s->buffer, 0);*/
return true;
}
else if (l<0)
{
if (self->ssl)
{
if (SSL_get_error(self->ssl, l) == SSL_ERROR_WANT_READ)
return false;
}
else
{
if(errno == EWOULDBLOCK)
return false;
}
}
/* both: client disconnect + on read error */
/* todo: raise client error here */
client_close(self);
return true;
}
static bool
client_output(client_t self)
{
if (self->fd < 0)
{
fprintf(stderr, "[aisl] assertion !(client->fd<0) failed\n");
return true;
}
stream_t s;
int l;
s = list_index(self->streams, self->ostream);
/*
if (!s->c_length_unknown && s->buffer && s->buffer->len)
buffer_move(gBuffer, s->buffer);
*/
/* while stream is not flushed, we should raise event */
if(s->flags & STREAM_FLAG_OUTPUT_CHUNKED)
{
/* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
* buffer->size will be used to carry amount of stored bytes
* */
size_t bsz = s->buffer->size;
if (bsz < OUTPUT_BUFFER_SIZE)
{
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
return false;
s->buffer->size = bsz;
bsz = OUTPUT_BUFFER_SIZE;
}
if ( (l = bsz - s->buffer->size) > OUTPUT_BUFFER_SIZE / 2 )
aisl_raise_event( self->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);
if (l > 0)
{
buffer_shift(s->buffer, l);
if (s->state == STREAM_RESPONSE_READY && /* flushed */
s->buffer->size == 0) /* all sent */
{
buffer_clear(s->buffer, 0);
/* data has been sent */
/*
if (self->protocol == AISL_HTTP_2_0)
{
}
else*/
if (self->flags & CLIENT_FLAG_KEEPALIVE)
{
list_remove(self->streams, s);
stream_free(s);
s = stream_new((struct sockaddr_in *) self, self->next_id++, STREAM_REQUEST_METHOD );
list_append(self->streams, s);
}
else
{
client_close(self);
}
}
return true;
}
/* l < 0 */
if (self->ssl)
{
if ( SSL_get_error(self->ssl, l) == SSL_ERROR_WANT_WRITE )
return false;
}
else
{
if (errno == EWOULDBLOCK)
return false;
}
client_close(self);
return true;
}
bool
client_touch(client_t self)
{
bool result = false;
stream_t s;
/* input */
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)
{
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)
{
if (self->fd > -1)
close(self->fd);
if (self->ssl)
SSL_free(self->ssl);
list_free(self->streams, (list_destructor_t)stream_free);
aisl_raise_event(
self->server->owner,
self->server,
AISL_CLIENT_DISCONNECT,
self
);
free(self);
}
/* check if communication time with client is expired ----------------------- */
bool
client_is_timeout(client_t self)
{
bool result = false;
stream_t s;
if (self->protocol == AISL_HTTP_2_0)
{
}
else
{
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_close(self);
return result;
}
/* -------------------------------------------------------------------------- */

67
library/client.h Normal file
View File

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

28
library/event.c Normal file
View File

@ -0,0 +1,28 @@
#include <aisl/event.h>
__attribute__ ((visibility ("default") ))
const char *
aisl_event_get_text( aisl_event_t e_id )
{
switch(e_id)
{
case AISL_SERVER_OPEN: return "AISL_SERVER_OPEN";
case AISL_SERVER_ERROR: return "AISL_SERVER_ERROR";
case AISL_CLIENT_CONNECT: return "AISL_CLIENT_CONNECT";
case AISL_CLIENT_DISCONNECT: return "AISL_CLIENT_DISCONNECT";
case AISL_CLIENT_TIMEOUT: return "AISL_CLIENT_TIMEOUT";
case AISL_STREAM_OPEN: return "AISL_STREAM_OPEN";
case AISL_STREAM_INPUT: return "AISL_STREAM_INPUT";
case AISL_STREAM_REQUEST: return "AISL_STREAM_REQUEST";
case AISL_STREAM_OUTPUT: return "AISL_STREAM_OUTPUT";
case AISL_STREAM_CLOSE: return "AISL_STREAM_CLOSE";
case AISL_STREAM_ERROR: return "AISL_STREAM_ERROR";
default:
break;
}
return "AISL_CUSTOM_EVENT";
}

48
library/globals.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef _AISL_GLOBALS_H_
#define _AISL_GLOBALS_H_
#pragma GCC diagnostic ignored "-Wuninitialized"
#include <aisl/handle.h>
/* MACOS FIX AND OTHER OS */
#ifndef SOCK_NONBLOCK
#define SOCK_NONBLOCK 0
#endif
#ifndef AISL_MIN_SERVERS
#define AISL_MIN_SERVERS 1
#endif
#ifndef AISL_MIN_STREAMS
#define AISL_MIN_STREAMS 1
#endif
#ifndef AISL_MIN_CLIENTS
#define AISL_MIN_CLIENTS 32
#endif
#ifndef AISL_MIN_LISTENERS
#define AISL_MIN_LISTENERS 8
#endif
#ifndef AISL_MIN_DELAYS
#define AISL_MIN_DELAYS 8
#endif
#ifndef AISL_BUFFER_SIZE
#define AISL_BUFFER_SIZE 4096
#endif
#ifndef AISL_MIN_HEADERS
#define AISL_MIN_HEADERS 8
#endif
#ifndef AISL_MAX_CLIENT_SILENCE
#define AISL_MAX_CLIENT_SILENCE 10
#endif
extern aisl_handle_t gHandle;
#endif

802
library/handle.c Normal file
View File

@ -0,0 +1,802 @@
#include <stdlib.h>
#include <string.h>
#include <openssl/err.h>
#include <aisl/handle.h>
#include <cStuff/str-utils.h>
#include <cStuff/list.h>
#include "stream.h"
#include "server.h"
#include "client.h"
#include "globals.h"
#include "handle.h"
/* -------------------------------------------------------------------------- */
struct listener
{
void *source;
aisl_callback_t cb;
aisl_event_t e_id;
};
typedef struct listener * listener_t;
/* -------------------------------------------------------------------------- */
struct delay
{
struct timespec next;
uint32_t delay;
void *u_data;
aisl_callback_t cb;
};
typedef struct delay * delay_t;
/* -------------------------------------------------------------------------- */
struct crypter
{
char * keyFile;
char * crtFile;
char * srvName;
SSL_CTX * sslCtx;
};
typedef struct crypter * crypter_t;
/* -------------------------------------------------------------------------- */
static int gHandles = 0;
/* -------------------------------------------------------------------------- */
static listener_t
listener_new( void * source, aisl_event_t e_id, aisl_callback_t cb)
{
listener_t self = malloc(sizeof(struct listener));
if (self)
{
self->source = source;
self->e_id = e_id;
self->cb = cb;
}
return self;
}
/* -------------------------------------------------------------------------- */
void
aisl_remove_listeners_for( aisl_handle_t self, void * source )
{
int i=self->listeners->count-1;
while ( !(i < 0) )
{
listener_t listener = list_index(self->listeners, i);
if ( listener->source == source )
{
free(listener);
list_remove_index(self->listeners, i);
}
i--;
}
}
/* -------------------------------------------------------------------------- */
static void
crypter_free( crypter_t self )
{
if (self->srvName)
free(self->srvName);
if (self->keyFile)
{
free(self->keyFile);
SSL_CTX_free(self->sslCtx);
}
if (self->crtFile)
free(self->crtFile);
free(self);
}
/* -------------------------------------------------------------------------- */
static crypter_t
crypter_new( const char * server_name,
const char * key_file,
const char * crt_file )
{
crypter_t self;
if ( (self=calloc(1, sizeof(struct crypter))) != NULL )
{
if (!(self->srvName = str_copy( server_name ? server_name : "*" )))
goto release;
if ( key_file && !(self->keyFile = str_copy(key_file)))
goto release;
if ( crt_file && !(self->crtFile = str_copy(crt_file)))
goto release;
}
goto finally;
release:
crypter_free(self);
self = NULL;
finally:
return self;
}
/* -------------------------------------------------------------------------- */
static bool
delay_is_expired(delay_t self)
{
if (!self->delay) return true;
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
/*
printf("> %ld.%ld & %ld.%ld\n", self->next.tv_sec, self->next.tv_nsec,
tv.tv_sec, tv.tv_nsec);
*/
if (tv.tv_sec > self->next.tv_sec)
return true;
else if (tv.tv_sec == self->next.tv_sec && tv.tv_nsec >= self->next.tv_nsec)
return true;
return false;
}
/* -------------------------------------------------------------------------- */
static void
delay_reset(delay_t self)
{
clock_gettime(CLOCK_REALTIME, &self->next);
self->next.tv_sec += self->delay / 1000;
self->next.tv_nsec += (self->delay % 1000) * 1000000;
self->next.tv_sec += self->next.tv_nsec / 1000000000;
self->next.tv_nsec = self->next.tv_nsec % 1000000000;
}
/* -------------------------------------------------------------------------- */
static delay_t
delay_new(aisl_callback_t cb, uint32_t delay, void *u_data)
{
delay_t self = malloc(sizeof(struct delay));
if (self)
{
self->cb = cb;
self->u_data = u_data;
self->delay = delay;
delay_reset(self);
}
return self;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_handle_t
aisl_handle_new( size_t min_clients, size_t buffer_size )
{
aisl_handle_t self;
if ((gHandles++) == 0)
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
if ( !(self = calloc(1, sizeof(struct aisl_handle))) )
goto finally;
if ( !(self->servers = list_new(1)) )
goto release;
if ( !(self->clients = list_new(min_clients)) )
goto release;
if ( !(self->listeners = list_new(16)) )
goto release;
if ( !(self->buffer = buffer_new(buffer_size)) )
goto release;
if ( !(self->crypters = list_new(0)) )
goto release;
if ( !(self->delays = list_new(0)) )
goto release;
goto finally;
release:
aisl_handle_free(self);
self = NULL;
finally:
return self;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_handle_t
aisl_handle_from_stream( aisl_stream_t s )
{
return ((client_t)s->client)->server->owner;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_handle_free( aisl_handle_t self )
{
if ((--gHandles) == 0)
{
EVP_cleanup();
}
if (self->clients)
list_free(self->clients, (list_destructor_t) client_free );
if (self->servers)
list_free(self->servers, (list_destructor_t) server_free );
if (self->listeners)
list_free(self->listeners, free);
if (self->delays)
list_free(self->delays, free);
if (self->buffer)
buffer_free(self->buffer);
if (self->crypters)
list_free(self->crypters, (list_destructor_t) crypter_free );
if (self->lastError)
free(self->lastError);
free(self);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_handle_set_error( aisl_handle_t self, const char * err_msg )
{
if (self->lastError)
free(self->lastError);
self->lastError = str_copy(err_msg);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_bind( aisl_handle_t self, const char * address, int port, int flags )
{
server_t server;
if ( !(server = server_new(address, port)) )
goto finally;
server->owner = self;
server->flags |= (flags & AISL_FLAG_SSL);
if ( list_append(self->servers, server) == -1 )
goto release;
goto finally;
release:
server_free(server);
server = NULL;
finally:
return server ? AISL_SUCCESS : AISL_MALLOC_ERROR;
}
/* -------------------------------------------------------------------------- */
static int
get_ssl_context( SSL * ssl, int * ptr, void * handle )
{
const char * server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
SSL_CTX * ctx = aisl_get_ssl_ctx( (aisl_handle_t) handle, server_name );
if (ctx)
{
SSL_set_SSL_CTX(ssl, ctx);
}
return SSL_TLSEXT_ERR_OK;
}
/* -------------------------------------------------------------------------- */
static SSL_CTX *
create_ssl_context( aisl_handle_t self,
const char * key_file,
const char * crt_file )
{
const SSL_METHOD * method;
SSL_CTX * ctx;
method = SSLv23_server_method();
if ( !(ctx = SSL_CTX_new(method)) )
goto except;
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tlsext_servername_callback( ctx, get_ssl_context );
SSL_CTX_set_tlsext_servername_arg( ctx, (void *) self );
if (!(SSL_CTX_use_certificate_file(ctx, crt_file, SSL_FILETYPE_PEM) > 0))
goto release;
if (!(SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) > 0))
goto release;
goto finally;
release:
SSL_CTX_free(ctx);
ctx = NULL;
except:
aisl_handle_set_error( self, ERR_error_string(ERR_get_error(),NULL) );
finally:
return ctx;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_ssl( aisl_handle_t self, const char * server_name,
const char * key_file,
const char * crt_file )
{
SSL_CTX * ssl_ctx = NULL;
int i;
crypter_t crypter;
/* lookup for existing contexts */
for (i=0; i<self->crypters->count; i++)
{
crypter = list_index(self->crypters, i);
if (crypter->keyFile && strcmp(crypter->keyFile, key_file)==0 &&
crypter->crtFile && strcmp(crypter->crtFile, crt_file)==0 )
{
ssl_ctx = crypter->sslCtx;
key_file = NULL;
crt_file = NULL;
break;
}
}
if (! (crypter = crypter_new(server_name, key_file, crt_file)) )
{
return AISL_MALLOC_ERROR;
}
if (! ssl_ctx)
{
if (!(ssl_ctx = create_ssl_context(self, key_file, crt_file)))
{
crypter_free(crypter);
return AISL_EXTCALL_ERROR;
}
}
crypter->sslCtx = ssl_ctx;
if (list_append(self->crypters, crypter)==-1)
{
crypter_free(crypter);
return AISL_MALLOC_ERROR;
}
return AISL_SUCCESS;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
SSL_CTX *
aisl_get_ssl_ctx( aisl_handle_t self, const char * server_name )
{
int i;
crypter_t crypter;
for (i=0; i<self->crypters->count; i++)
{
crypter = list_index(self->crypters, i);
if (server_name)
{
if (strcmp(crypter->srvName, server_name)!=0)
continue;
}
return crypter->sslCtx;
}
return NULL;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_callback( aisl_handle_t self,
void * source,
aisl_event_t e_id,
aisl_callback_t cb )
{
listener_t listener;
if (! (listener = listener_new(source, e_id, cb)) )
return AISL_MALLOC_ERROR;
if (list_append(self->listeners, listener) == -1)
{
free(listener);
return AISL_MALLOC_ERROR;
}
if (e_id == AISL_STREAM_OUTPUT) /* subscribtion for chunked output */
{
if (source)
{
( (stream_t) source )->flags |= STREAM_FLAG_OUTPUT_CHUNKED;
}
}
else if (e_id == AISL_STREAM_OPEN)
{
self->flags |= AISL_HANDLE_HAS_STREAM_LISTENERS;
}
return AISL_SUCCESS;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_delay( aisl_handle_t self,
aisl_callback_t cb,
uint32_t usec,
void * u_data )
{
delay_t delay = delay_new(cb, usec, u_data);
if (!delay)
return AISL_MALLOC_ERROR;
if (list_append(self->delays, delay) == -1)
{
free(delay);
return AISL_MALLOC_ERROR;
}
return AISL_SUCCESS;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
bool
aisl_raise_event( aisl_handle_t self,
void * source,
aisl_event_t e_id,
... )
{
va_list vl;
bool result;
va_start(vl, e_id);
result = aisl_raise_event_vl(self, source, e_id, vl);
va_end(vl);
return result;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
bool
aisl_raise_event_vl( aisl_handle_t self,
void * source,
aisl_event_t e_id,
va_list vl )
{
int i,
i_val;
listener_t lst;
bool res = false;
char * c_ptr,
* c_ptr2;
for(i=self->listeners->count-1; i>=0; i--)
{
lst = list_index(self->listeners, i);
/*printf("AISL> raise %s:%s, %p:%p\n", _event_text(e_id), _event_text(lst->e_id), source, lst->source);*/
if (lst->e_id == e_id && (source == lst->source || lst->source == NULL))
{
/*
if (e_id == AISL_STREAM_HEADER)
fprintf(stderr,"FOUND HANDLER %d\n", i);
*/
/*printf(" catch\n");*/
switch(e_id)
{
/* server events */
case AISL_SERVER_OPEN:
i_val = va_arg(vl, aisl_status_t);
res = ((aisl_server_open_t) lst->cb)( source, i_val );
break;
case AISL_SERVER_ERROR:
i_val = va_arg(vl, aisl_status_t);
c_ptr = va_arg(vl, char *);
res = ((aisl_server_error_t) lst->cb)( source, i_val, c_ptr );
break;
/* client events */
case AISL_CLIENT_CONNECT:
res = ((aisl_client_connect_t) lst->cb)(source, va_arg(vl, void *));
break;
case AISL_CLIENT_DISCONNECT:
res = ((aisl_client_disconnect_t) lst->cb)(source, va_arg(vl, void*));
aisl_remove_listeners_for( self, source );
break;
case AISL_CLIENT_TIMEOUT:
res = ((aisl_client_timeout_t) lst->cb)(source, va_arg(vl, void *));
break;
/* request events */
case AISL_STREAM_OPEN:
i_val = va_arg(vl, int);
c_ptr = va_arg(vl, char *);
c_ptr2 = va_arg(vl, char *);
res = ((aisl_stream_open_t) lst->cb)(source, i_val, c_ptr, c_ptr2);
break;
case AISL_STREAM_HEADER:
c_ptr = va_arg(vl, char *);
c_ptr2 = va_arg(vl, char *);
res = ((aisl_stream_header_t) lst->cb)(source, c_ptr, c_ptr2);
break;
case AISL_STREAM_INPUT:
/*printf("AISL> raise AISL_STREAM_INPUT\n");*/
c_ptr = va_arg(vl, char *);
i_val = va_arg(vl, int );
res = ((aisl_stream_input_t) lst->cb)(source, c_ptr, i_val);
break;
case AISL_STREAM_REQUEST:
/*printf("AISL> raise AISL_STREAM_REQUEST\n");*/
buffer_clear( STREAM(source)->buffer, 0);
res = ((aisl_stream_request_t) lst->cb)(source);
break;
case AISL_STREAM_ERROR:
res = ((aisl_stream_error_t) lst->cb)( source, va_arg(vl, char *));
break;
/* response events */
case AISL_STREAM_OUTPUT:
res = ((aisl_stream_output_t)lst->cb)(
source,
va_arg(vl, uint32_t)
);
break;
case AISL_STREAM_CLOSE:
res = ((aisl_stream_close_t)lst->cb)( source );
aisl_remove_listeners_for( self, source );
((aisl_stream_t) source)->u_ptr=NULL;
break;
default:
res = ((aisl_custom_event_t) lst->cb)(source, vl);
}
if (res) break;
}
}
return res;
}
/* -------------------------------------------------------------------------- */
/*
aisl_status_t
aisl_run( int * flags )
{
aisl_status_t exit_code = AISL_SUCCESS;
struct timeval timeout;
while( !(*flags & (1<<0)) )
{
exit_code = aisl_run_cycle( gHandle );
if (exit_code == AISL_IDLE)
{
timeout.tv_usec = 300;
timeout.tv_sec = 0;
select(0, NULL, NULL, NULL, &timeout);
}
}
return exit_code;
}
*/
/* -------------------------------------------------------------------------- */
#define STAGE_SERVER 0
#define STAGE_CLIENT 1
#define STAGE_DELAY 2
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_run_cycle( aisl_handle_t self )
{
int max = self->servers->count+self->clients->count+self->delays->count,
cnt = 0;
switch (self->stage)
{
case STAGE_SERVER:
while (self->iterator < self->servers->count )
{
server_t srv = (server_t)list_index(self->servers, self->iterator++);
if ( server_touch(srv) != AISL_IDLE )
return AISL_SUCCESS;
if ( ! (++cnt < max) ) return AISL_IDLE;
}
if ( ! (self->flags & AISL_HANDLE_HAS_STREAM_LISTENERS) )
return AISL_IDLE;
self->iterator = 0;
self->stage++;
case STAGE_CLIENT:
while (self->iterator < self->clients->count )
{
int i = self->iterator++;
client_t cli = list_index(self->clients, i);
bool r = client_touch( cli );
if (client_is_timeout( cli ) )
aisl_raise_event( self, cli->server, AISL_CLIENT_TIMEOUT, cli );
if ( cli->fd == -1 )
{
client_free( cli );
list_remove_index(self->clients, i);
}
if (r) return AISL_SUCCESS;
if ( ! (++cnt < max) ) return AISL_IDLE;
}
self->iterator = 0;
self->stage++;
case STAGE_DELAY:
while (self->iterator < self->delays->count )
{
int i = self->iterator++;
delay_t dly = list_index(self->delays, i);
if( delay_is_expired(dly) )
{
if ( ((aisl_delay_timeout_t) dly->cb)(dly->u_data))
{
delay_reset(dly);
}
else
list_remove_index(self->delays, i);
return AISL_SUCCESS;
}
if ( ! (++cnt < max) ) return AISL_IDLE;
}
self->iterator = 0;
self->stage = 0;
}
return AISL_IDLE;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_handle_get_error( aisl_handle_t self )
{
return self->lastError;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_sleep( aisl_handle_t self, unsigned long usec )
{
int maxfd=0;
size_t i;
struct timeval timeout = {0,usec};
fd_set fs;
FD_ZERO (&fs);
for (i=0; i<self->servers->count; i++)
{
server_t s = list_index(self->servers, i);
if (s->fd != -1)
{
FD_SET(s->fd, &fs);
if (s->fd > maxfd) maxfd = s->fd;
}
}
for (i=0; i<self->clients->count; i++)
{
client_t c = list_index(self->clients, i);
if (c->fd != -1)
{
FD_SET(c->fd, &fs);
if (c->fd > maxfd) maxfd = c->fd;
}
}
return select(maxfd+1, &fs, NULL, NULL, &timeout);
}

61
library/handle.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef _AISL_HANDLE_H__
#define _AISL_HANDLE_H__
#include <stdbool.h>
#include <stdarg.h>
#include <aisl/handle.h>
#include <cStuff/list.h>
#include <openssl/ssl.h>
#include "buffer.h"
#define AISL_HANDLE_HAS_STREAM_LISTENERS (1<<8)
/* -------------------------------------------------------------------------- */
struct aisl_handle
{
list_t servers;
list_t clients;
list_t delays; /* deprecated */
list_t listeners;
list_t crypters;
buffer_t buffer;
char * lastError;
int iterator;
int stage;
int flags;
};
/* -------------------------------------------------------------------------- */
aisl_status_t
aisl_set_delay( aisl_handle_t self,
aisl_callback_t cb,
uint32_t usec,
void * u_data );
/* -------------------------------------------------------------------------- */
bool
aisl_raise_event_vl( aisl_handle_t self,
void * source,
aisl_event_t e_id,
va_list vl );
/* -------------------------------------------------------------------------- */
SSL_CTX *
aisl_get_ssl_ctx( aisl_handle_t self, const char * server_name );
/* -------------------------------------------------------------------------- */
void
aisl_remove_listeners_for( aisl_handle_t self, void * source );
/* -------------------------------------------------------------------------- */
#endif

112
library/http.c Normal file
View File

@ -0,0 +1,112 @@
#include <aisl/http.h>
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_http_version_to_string(aisl_http_version_t version)
{
switch (version)
{
case AISL_HTTP_1_0: return "HTTP/1.0";
case AISL_HTTP_1_1: return "HTTP/1.1";
case AISL_HTTP_2_0: return "HTTP/2.0";
}
return "";
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_http_response_to_string(aisl_http_response_t code)
{
switch (code)
{
/* most common for faster behavior */
case AISL_HTTP_OK: return "OK";
case AISL_HTTP_MOVED_PERMANENTLY: return "Moved Permanently";
/* informational */
case AISL_HTTP_CONTINUE: return "Continue";
case AISL_HTTP_SWITCHING_PROTOCOLS: return "Switching Protocols";
/* Successful */
case AISL_HTTP_CREATED: return "Created";
case AISL_HTTP_ACCEPTED: return "Accepted";
case AISL_HTTP_NON_AUTHORITATIVE_INFORMATION: return "Non-Authoritative Information";
case AISL_HTTP_NO_CONTENT: return "No Content";
case AISL_HTTP_RESET_CONTENT: return "Reset Content";
case AISL_HTTP_PARTIAL_CONTENT: return "Partial Content";
/* redirection */
case AISL_HTTP_MULTIPLE_CHOICES: return "Multiple Choices";
case AISL_HTTP_FOUND: return "Found";
case AISL_HTTP_SEE_OTHER: return "See other";
case AISL_HTTP_NOT_MODIFIED: return "Not Modified";
case AISL_HTTP_USE_PROXY: return "Use Proxy";
case AISL_HTTP_UNUSED: return "(unused)";
case AISL_HTTP_TEMPORARY_REDIRECT: return "Temporary Redirect";
/* client error */
case AISL_HTTP_BAD_REQUEST: return "Bad Request";
case AISL_HTTP_UNAUTHORIZED: return "Unauthorized";
case AISL_HTTP_PAYMENT_REQUIRED: return "Payment Required";
case AISL_HTTP_FORBIDDEN: return "Forbidden";
case AISL_HTTP_NOT_FOUND: return "Not Found";
case AISL_HTTP_METHOD_NOT_ALLOWED: return "Method Not Allowed";
case AISL_HTTP_NOT_ACCEPTABLE: return "Not Acceptable";
case AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED: return "Proxy Authentication Required";
case AISL_HTTP_REQUEST_TIMEOUT: return "Request Timeout";
case AISL_HTTP_CONFLICT: return "Conflict";
case AISL_HTTP_GONE: return "Gone";
case AISL_HTTP_LENGTH_REQUIRED: return "Length Required";
case AISL_HTTP_PRECONDITION_FAILED: return "Precondition Failed";
case AISL_HTTP_REQUEST_ENTITY_TOO_LARGE: return "Request Entity Too Large";
case AISL_HTTP_REQUEST_URI_TOO_LONG: return "Request-URI Too Long";
case AISL_HTTP_UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type";
case AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: return "Requested Range Not Satisfiable";
case AISL_HTTP_EXPECTATION_FAILED: return "Expectation Failed";
/* server error */
case AISL_HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
case AISL_HTTP_NOT_IMPLEMENTED: return "Not Implemented";
case AISL_HTTP_BAD_GATEWAY: return "Bad Gateway";
case AISL_HTTP_SERVICE_UNAVAILABLE: return "Service Unavailable";
case AISL_HTTP_GATEWAY_TIMEOUT: return "Gateway Timeout";
case AISL_HTTP_VERSION_NOT_SUPPORTED: return "HTTP Version Not Supported";
}
return "";
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_http_secure_to_string( int is_secure )
{
return (is_secure ? "HTTPS" : "HTTP");
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_http_method_to_string( aisl_http_method_t method )
{
switch(method)
{
case AISL_HTTP_GET: return "GET";
case AISL_HTTP_PUT: return "PUT";
case AISL_HTTP_POST: return "POST";
case AISL_HTTP_HEAD: return "HEAD";
case AISL_HTTP_TRACE: return "TRACE";
case AISL_HTTP_DELETE: return "DELETE";
case AISL_HTTP_OPTIONS: return "OPTIONS";
case AISL_HTTP_CONNECT: return "CONNECT";
case AISL_HTTP_PRI: return "PRI";
}
return "";
}
/* -------------------------------------------------------------------------- */

490
library/parser.c Normal file
View File

@ -0,0 +1,490 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <cStuff/str-utils.h>
#include <aisl/http.h>
#include "parser.h"
#include "globals.h"
#include "stream.h"
/* length(multipart/form-data; boundary=) = 30 */
#define B_OFFSET 30
/* common HTTP headers */
static const char cCookie[] = "Cookie";
static const char cContentType[] = "Content-Type";
static const char cContentLength[] = "Content-Length";
/*
static const char cConnection[] = "Connection";
static const char cHost[] = "Host";
static const char cUserAgent[] = "User-Agent";
static const char cAccept[] = "Accept";
static const char cAcceptLanguage[] = "Accept-Language";
static const char cAcceptEncoding[] = "Accept-Encoding";
*/
#define CLI_STREAM(x) ( ((stream_t)list_index(x->streams,x->istream)) )
/*
static void
debug(const char * label, char * buffer, int len)
{
printf("<<< %s [", label);
fwrite(buffer, 1, len, stdout);
printf("]\n");
}
*/
static pair_t
pair_new(const char * key, int length)
{
pair_t p = calloc(1, sizeof(struct pair));
if (p)
{
p->key = str_ncopy(key, length);
if (!p->key)
{
free(p);
p = NULL;
}
}
return p;
}
/* HTTP METHOD -------------------------------------------------------------- */
parser_status_t
parse_request_method(client_t cli, char ** b_ptr, int *b_len)
{
char * cur = memchr(*b_ptr, ' ', *b_len);
if (!cur)
{
if (*b_len < 8)
return PARSER_HUNGRY;
else
return PARSER_FAILED;
}
int l = (int) (cur - *b_ptr);
stream_t s = list_index(cli->streams, cli->istream);
switch( l )
{
case 3:
if (strncmp(*b_ptr, "GET", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_GET;
else if (strncmp(*b_ptr, "PRI", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_PRI;
else if (strncmp(*b_ptr, "PUT", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_PUT;
else
return PARSER_FAILED;
break;
case 4:
if (strncmp(*b_ptr, "POST", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_POST;
else if (strncmp(*b_ptr, "HEAD", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_HEAD;
else
return PARSER_FAILED;
break;
case 5:
if (strncmp(*b_ptr, "TRACE", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_TRACE;
else
return PARSER_FAILED;
break;
case 6:
if (strncmp(*b_ptr, "DELETE", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_DELETE;
else
return PARSER_FAILED;
break;
case 7:
if (strncmp(*b_ptr, "OPTIONS", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_OPTIONS;
else if (strncmp(*b_ptr, "CONNECT", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_CONNECT;
else
return PARSER_FAILED;
break;
default:
return PARSER_FAILED;
}
*b_ptr += ++l;
*b_len -= l; /* count method + space character */
s->state = STREAM_REQUEST_PATH;
return PARSER_PENDING;
}
/* HTTP REQUEST_URI and HOST ------------------------------------------------ */
static void
str_to_lower( char * src )
{
while (*src)
{
*src = tolower(*src);
src++;
}
}
parser_status_t
parse_request_path(client_t cli, char ** b_ptr, int *b_len)
{
parser_status_t result = PARSER_PENDING;
stream_t s = list_index(cli->streams, cli->istream);
int i;
char * host = NULL,
* path = NULL,
* query = NULL;
for ( i=0; i<*b_len; i++)
{
switch( (*b_ptr)[i] )
{
case ':':
if (host) /* if host is set, we parse host and it could not contain : */
{
result = PARSER_FAILED;
break;
}
else /* could be protocol separator */
{
if (i==5)
{
if (*b_len > 7 && strncmp(*b_ptr, "http://", 7)==0 ) /* protocol defined */
{
host = &(*b_ptr)[i+3];
i+=2;
continue;
}
result = PARSER_FAILED; /* something is wrong */
break;
}
}
continue;
case '?':
query = (*b_ptr) +i;
continue;
case ' ':
if (! path) path = *b_ptr;
if (query)
{
ASTREAM(s)->path = str_ncopy(path, (uint32_t) (query-path));
query++;
ASTREAM(s)->query = str_ncopy(query, (uint32_t)(&(*b_ptr)[i]-query));
}
else
ASTREAM(s)->path = str_ncopy(path, (uint32_t) (&(*b_ptr)[i]-path));
*b_len -= ++i;
*b_ptr += i;
s->state = STREAM_REQUEST_PROTOCOL;
return PARSER_PENDING;
break;
case '/':
if (host)
{
/* debug(" > host", host, (int) (&(*b_ptr)[i] - host)); */
pair_t p = malloc(sizeof(struct pair));
if (p)
{
p->key = str_copy("host");
p->value = str_ncopy(host, (uint32_t) (&(*b_ptr)[i] - host));
}
s->headers = list_new(AISL_MIN_HEADERS);
list_append(s->headers, p);
host = NULL;
path = &(*b_ptr)[i];
}
default:
continue;
}
break;
}
if (result == PARSER_PENDING) /* end space was not found */
result = PARSER_HUNGRY;
/*
if (result == PARSER_HUNGRY && *b_len == gBuffer->size)
result = PARSER_FAILED;*/ /* buffer is overloaded */
return result;
}
/* HTTP VERSION ------------------------------------------------------------- */
parser_status_t
parse_request_protocol(client_t cli, char ** b_ptr, int *b_len)
{
stream_t stream = CLI_STREAM(cli);
/* HTTP/X.X = 8 characters minimal */
if (*b_len < 8) return PARSER_HUNGRY;
char * ptr = memchr(*b_ptr, '\n', *b_len);
if (!ptr) return PARSER_HUNGRY;
int l = (int) (ptr - *b_ptr);
if (strncmp(*b_ptr, "HTTP/", 5)==0)
{
if (strncmp(&(*b_ptr)[5], "2.0", 3)==0) cli->protocol = AISL_HTTP_2_0; else
if (strncmp(&(*b_ptr)[5], "1.1", 3)==0) cli->protocol = AISL_HTTP_1_1; else
if (strncmp(&(*b_ptr)[5], "1.0", 3)==0) cli->protocol = AISL_HTTP_1_0; else
return PARSER_FAILED;
if ( (l==10 && *b_ptr[8]=='\r') || (l==9) )
{
/*r->version = str_ncopy(*b_ptr, 8); */
*b_ptr += ++l;
*b_len -=l;
stream->state=STREAM_REQUEST_HEADER_KEY;
aisl_raise_event(
cli->server->owner,
stream,
AISL_STREAM_OPEN,
ASTREAM(stream)->request_method,
ASTREAM(stream)->path,
ASTREAM(stream)->query
);
if (!stream->headers)
stream->headers = list_new(AISL_MIN_HEADERS);
else if (stream->headers->count == 1)
{
/* raise event for Host header */
pair_t p = list_index(stream->headers, 0);
aisl_raise_event(
cli->server->owner,
stream,
AISL_STREAM_HEADER,
p->key, p->value
);
}
return PARSER_PENDING;
}
}
return PARSER_FAILED;
}
/* HTTP HEADER KEY ---------------------------------------------------------- */
parser_status_t
parse_request_header_key(client_t cli, char ** b_ptr, int *b_len)
{
stream_t stream = CLI_STREAM(cli);
int l;
/* check end of headers */
switch (*b_ptr[0])
{
case '\r':
if (*b_len>1)
{
if( strncmp(*b_ptr, "\r\n", 2)==0 )
{
l=2;
}
else
return PARSER_FAILED;
}
else
return PARSER_HUNGRY;
break;
case '\n':
l=1;
break;
default:
l=0;
}
if (l)
{
/* end of headers */
*b_len -= l;
*b_ptr += l;
stream->state = STREAM_REQUEST_CONTENT;
/* aisl_raise_event(cli->server->owner, CLI_STREAM(cli), AISL_STREAM_OPEN);
* */
return PARSER_PENDING;
}
/* header key */
char * ptr = memchr(*b_ptr, ':', *b_len);
if (!ptr)
{
/*
if (*b_len == gBuffer->size)
return PARSER_FAILED;
*/
return PARSER_HUNGRY;
}
l = (int) (ptr-*b_ptr);
pair_t ppp = pair_new(*b_ptr, l);
str_to_lower(ppp->key);
if (ppp)
list_append(stream->headers, ppp);
*b_len -= ++l;
*b_ptr += l;
stream->state=STREAM_REQUEST_HEADER_VALUE;
return PARSER_PENDING;
}
/* HTTP HEADER VALUE -------------------------------------------------------- */
parser_status_t
parse_request_header_value(client_t cli, char ** b_ptr, int *b_len)
{
stream_t stream = CLI_STREAM(cli);
/* skip first space */
if (*b_len)
{
if ((*b_ptr)[0]==' ')
{
(*b_ptr)++;
(*b_len)--;
if (*b_len == 0)
return PARSER_HUNGRY;
}
}
else
return PARSER_HUNGRY;
char * ptr = memchr(*b_ptr, '\n', *b_len);
int l;
l = (ptr) ? (int) (ptr-*b_ptr) : *b_len;
uint32_t index = stream->headers->count -1;
pair_t p = list_index(stream->headers, index);
p->value = str_ncat(p->value, *b_ptr, (l && (*b_ptr)[l-1]=='\r') ? l-1 : l);
*b_len -= ++l;
*b_ptr += l;
stream->state=STREAM_REQUEST_HEADER_KEY;
/* todo: add limit for maximal header length */
if (ptr)
{
if (str_cmpi(p->key, cCookie )==0)
{
/* parse cookies */
}
else if (str_cmpi(p->key, cContentType )==0)
{
/* CLI(r)->c_type_index = index; */
}
else if (str_cmpi(p->key, cContentLength )==0)
{
stream->c_length = strtol(p->value, NULL, 0);
}
/* CLI(r)->c_length = strtol(p->value, NULL, 10); */
aisl_raise_event(
cli->server->owner,
stream,
AISL_STREAM_HEADER,
p->key, p->value
);
return PARSER_PENDING;
}
else
return PARSER_HUNGRY;
}
parser_status_t
parse_request_content(client_t cli, char ** b_ptr, int *b_len)
{
stream_t stream = CLI_STREAM(cli);
/*
fprintf(stdout, "AISL [%d]> ", CLI_STREAM(cli)->c_length);
fwrite(*b_ptr, 1, *b_len, stdout);
fprintf(stdout, "\n<");
*/
if (stream->c_length)
{
int l = *b_len;
aisl_raise_event(
cli->server->owner,
stream,
AISL_STREAM_INPUT,
*b_ptr,
l
);
*b_ptr += l;
*b_len = 0;
stream->c_length -= l;
}
else
goto request_ready;
if ( stream->c_length == 0 )
{
request_ready:
stream->state=STREAM_REQUEST_READY;
aisl_raise_event( cli->server->owner, stream, AISL_STREAM_REQUEST );
return PARSER_FINISHED;
}
else
return PARSER_HUNGRY;
}

52
library/parser.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef _AISL_PARSER_H_
#define _AISL_PARSER_H_
#include <aisl/aisl.h>
#include "client.h"
/* parser status ------------------------------------------------------------ */
typedef enum
{
PARSER_PENDING, /* process pending */
PARSER_FINISHED, /* successful finish */
PARSER_HUNGRY, /* not enough data in buffer */
PARSER_FAILED /* error happened */
} parser_status_t;
/* parse HTTP Request ------------------------------------------------------- */
parser_status_t
parse_request_method(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP Request URI --------------------------------------------------- */
parser_status_t
parse_request_path(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP Version ------------------------------------------------------- */
parser_status_t
parse_request_protocol(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP header key ---------------------------------------------------- */
parser_status_t
parse_request_header_key(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP header value -------------------------------------------------- */
parser_status_t
parse_request_header_value(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP data ---------------------------------------------------------- */
parser_status_t
parse_request_content(client_t cli, char ** b_ptr, int *b_len);
/* -------------------------------------------------------------------------- */
#endif

188
library/server.c Normal file
View File

@ -0,0 +1,188 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <cStuff/str-utils.h>
#include "server.h"
#include "handle.h"
#include "client.h"
#include "globals.h"
/* -------------------------------------------------------------------------- */
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;
}
/* -------------------------------------------------------------------------- */
static aisl_status_t
server_open(server_t self)
{
aisl_status_t result = AISL_SUCCESS;
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)
{
setsockopt(
self->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&s_opt, sizeof(int)
);
#ifdef __APPLE__
int on = 1;
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 (listen(self->fd, SOMAXCONN) == 0)
return result;
}
server_close(self);
}
result = AISL_SYSCALL_ERROR;
return result;
}
/* -------------------------------------------------------------------------- */
bool
server_touch(server_t self)
{
aisl_status_t result;
client_t cli;
if (self->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)
);
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);
}
return result;
}
/* -------------------------------------------------------------------------- */
server_t
server_new(const char * address, int port)
{
server_t self;
if ( (self = calloc(1, sizeof(struct server))) != NULL )
{
self->fd = -1;
self->port = port;
if ( !(self->host = str_copy(address)) )
{
free(self);
self = NULL;
}
}
return self;
}
/* -------------------------------------------------------------------------- */
void
server_free(server_t self)
{
if (self)
{
if (self->fd > -1)
server_close(self);
if (self->host)
free(self->host);
free(self);
}
}
/* -------------------------------------------------------------------------- */

47
library/server.h Normal file
View File

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

21
library/status.c Normal file
View File

@ -0,0 +1,21 @@
#include <aisl/status.h>
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_status_to_string(aisl_status_t status)
{
switch( status )
{
case AISL_SUCCESS: return "success";
case AISL_IDLE: return "idle";
case AISL_MALLOC_ERROR: return "malloc error";
case AISL_SYSCALL_ERROR: return "system call error";
case AISL_EXTCALL_ERROR: return "external call error";
}
return "";
}
/* -------------------------------------------------------------------------- */

196
library/stream.c Normal file
View File

@ -0,0 +1,196 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <aisl/status.h>
#include "stream.h"
#include "globals.h"
#include "client.h"
#include "handle.h"
static void
pair_free( pair_t self )
{
if (!self) return;
if(self->key) free(self->key);
if(self->value) free(self->value);
free(self);
}
/* -------------------------------------------------------------------------- */
stream_t
stream_new(struct sockaddr_in *client, int id, stream_state_t state)
{
stream_t self = malloc(sizeof(struct stream));
if (self)
{
/* public data */
ASTREAM(self)->client = client;
ASTREAM(self)->host = NULL;
ASTREAM(self)->path = NULL;
ASTREAM(self)->query = NULL;
ASTREAM(self)->scheme = NULL;
ASTREAM(self)->u_ptr = NULL;
ASTREAM(self)->request_method = AISL_HTTP_GET;
/* private data */
self->headers = NULL; /* request headers */
self->buffer = buffer_new(0);
self->c_type = NULL;
self->response = AISL_HTTP_OK;
self->state = STREAM_REQUEST_METHOD;
self->c_length = 0;
self->c_offset = 0; /* headers length */
self->id = id;
self->c_length_unknown = true;
self->flags = 0;
}
return self;
}
/*
stream_t
stream_reset(stream_t self)
{
if (ASTREAM(self)->path)
{
free( (char*) ASTREAM(self)->path);
ASTREAM(self)->path = NULL;
}
if (ASTREAM(self)->query)
{
free( (char*) ASTREAM(self)->query);
ASTREAM(self)->query = NULL;
}
ASTREAM(self)->u_ptr = NULL;
ASTREAM(self)->request_method = AISL_HTTP_GET;
if (self->headers)
{
list_free(self->headers, (list_destructor_t) pair_free);
self->headers = NULL;
}
self->c_type = NULL;
self->response = AISL_HTTP_OK;
self->state = STREAM_REQUEST_METHOD;
self->c_length = 0;
self->c_offset = 0; / * headers length * /
self->c_length_unknown = true;
self->flags = 0;
return self;
}
*/
/* -------------------------------------------------------------------------- */
void
stream_free(stream_t self)
{
if (self->buffer) buffer_free(self->buffer);
if (self->headers) list_free(self->headers, (list_destructor_t) pair_free);
if (ASTREAM(self)->path) free( (char*) ASTREAM(self)->path);
if (ASTREAM(self)->query) free( (char*) ASTREAM(self)->query);
aisl_handle_t hd = ((client_t) ASTREAM(self)->client)->server->owner;
aisl_raise_event(hd, self, AISL_STREAM_CLOSE);
ASTREAM(self)->u_ptr = NULL;
aisl_remove_listeners_for(hd, self);
free(self);
}
/* -------------------------------------------------------------------------- */
int
stream_write(stream_t self, const char * data, uint32_t d_len)
{
return buffer_add( self->buffer, data, d_len);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_cancel(aisl_stream_t s)
{
client_close( (client_t) s->client );
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
bool
aisl_is_secure(aisl_stream_t s)
{
client_t cli = (client_t) s->client;
return (cli->ssl) ? true : false;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void *
aisl_get_context(aisl_stream_t s)
{
return s->u_ptr;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_set_context(aisl_stream_t s, void * u_ptr)
{
s->u_ptr = u_ptr;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_client_t
aisl_get_client(aisl_stream_t s)
{
return s->client;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_server_t
aisl_get_server(aisl_stream_t s)
{
return (aisl_server_t) (((client_t) s->client)->server);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_http_version_t
aisl_get_http_version(aisl_stream_t s)
{
client_t cli = (client_t) s->client;
return cli->protocol;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_reject(aisl_stream_t s)
{
client_t cli = (client_t) s->client;
client_close( cli );
}
/* -------------------------------------------------------------------------- */

93
library/stream.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef _AISL_STREAM_H__
#define _AISL_STREAM_H__
#include <stdbool.h>
#include <aisl/stream.h>
#include <cStuff/list.h>
#include "buffer.h"
/* -------------------------------------------------------------------------- */
#define STREAM_FLAG_OUTPUT_READY (1<<0)
#define STREAM_FLAG_OUTPUT_CHUNKED (1<<1)
/* -------------------------------------------------------------------------- */
struct pair
{
char *key;
char *value;
};
typedef struct pair * pair_t;
/* -------------------------------------------------------------------------- */
typedef enum {
STREAM_REQUEST_METHOD,
STREAM_REQUEST_PATH,
STREAM_REQUEST_PROTOCOL,
STREAM_REQUEST_HEADER_KEY, /* HTTP1 header key */
STREAM_REQUEST_HEADER_VALUE, /* HTTP1 header value */
STREAM_REQUEST_CONTENT, /* HTTP1 data value */
/* states below show stream state
* and do not show what data was sent to client
* */
STREAM_REQUEST_READY,
STREAM_RESPONSE_HEADER,
STREAM_RESPONSE_CONTENT,
STREAM_RESPONSE_READY
} stream_state_t;
/* real wrapper for aisl_stream_t */
struct stream
{
struct aisl_stream _public;
/* private data */
list_t headers; /* request headers */
buffer_t buffer;
const char *c_type;
aisl_http_response_t response;
stream_state_t state;
uint32_t c_length;
uint32_t c_offset;
int id;
int flags;
bool c_length_unknown;
};
typedef struct stream * stream_t;
#define STREAM(x) ((stream_t) x)
#define ASTREAM(x) ((aisl_stream_t) x)
/* -------------------------------------------------------------------------- */
stream_t
stream_new(struct sockaddr_in *client, int id, stream_state_t state);
/* -------------------------------------------------------------------------- */
void
stream_free(stream_t self);
/* -------------------------------------------------------------------------- */
stream_t
stream_reset(stream_t self);
/* -------------------------------------------------------------------------- */
#endif

97
project.sh Executable file
View File

@ -0,0 +1,97 @@
#!/bin/bash
# -----------------------------------------------------------------------------
#
# CMake Wrapper v.1.0 for Linux
# (c) Copyright Löwenware Ltd. (https://lowenware.com/)
#
# -----------------------------------------------------------------------------
ABSOLUTE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT="aisl"
PROJECT_VERSION=$(cat ${ABSOLUTE_PATH}/version | sed 's/\([0-9]\{1,5\}.[0-9]\{1,5\}.[0-9]\{1,5\}\).*/\1/')
PREFIX="/usr"
SYSCONF="/etc"
DIR_BUILD="build"
DIR_ROOT="root"
# -----------------------------------------------------------------------------
function project_clean {
echo "Cleaning..."
if [ -d ./$DIR_BUILD ]; then
rm -Rf ./$DIR_BUILD/*
else
mkdir ./$DIR_BUILD
fi
if [ -d ./$DIR_ROOT ]; then
rm -Rf ./$DIR_ROOT/*
else
mkdir ./$DIR_ROOT
fi
}
# -----------------------------------------------------------------------------
function project_compile {
CMAKE="cmake"
if [[ "$OSTYPE" == "darwin"* ]]; then
ov="1.0.2n"
ov_p="-DOPENSSL_INCLUDE_DIRS=/usr/local/Cellar/openssl/${ov}/include -DOPENSSL_CRYPTO_LIBRARY=/usr/local/Cellar/openssl/${ov}/lib/libcrypto.dylib -DOPENSSL_SSL_LIBRARY=/usr/local/Cellar/openssl/${ov}/lib/libssl.dylib -DOPENSSL_LIBRARY_DIRS=/usr/local/Cellar/openssl/${ov}/lib"
CMAKE="cmake ${ov_p}"
fi
echo ${CMAKE}
${CMAKE} -B./$DIR_BUILD -H./ -DCMAKE_INSTALL_PREFIX=$PREFIX -DCMAKE_DEBUG=1
cd $DIR_BUILD/
make
make DESTDIR=../$DIR_ROOT install
cd ..
}
# -----------------------------------------------------------------------------
case $1 in
clean)
project_clean
;;
compile)
project_compile
;;
build)
project_clean
project_compile
;;
install)
cmake -DWITH_EVERYTHING=1 -B./$DIR_BUILD -H./ -DCMAKE_INSTALL_PREFIX=$PREFIX
cd $DIR_BUILD
sudo make install
cd ..
;;
deploy)
DEPLOY_PATH="${PROJECT}-${PROJECT_VERSION}"
mkdir ${2}${DEPLOY_PATH}
cp -R ${ABSOLUTE_PATH}/{include,library,LICENSE,AUTHORS,version,README.md,cmake*,CMakeLists.txt,cStuff} ${2}${DEPLOY_PATH}
rm ${2}${DEPLOY_PATH}/cStuff/.git
CUR_DIR=$(pwd)
cd $2
tar cfz ${DEPLOY_PATH}.tar.gz ${DEPLOY_PATH}
cd $CUR_DIR
rm -Rf ${2}${DEPLOY_PATH}
echo "_version ${PROJECT_VERSION}"
;;
*)
echo "Usage: ./project.sh (compile|build|clean|install)"
;;
esac
# -----------------------------------------------------------------------------

1
version Normal file
View File

@ -0,0 +1 @@
0.3.4-alpha