Initiated
This commit is contained in:
commit
4b137d7c55
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "cStuff"]
|
||||
path = cStuff
|
||||
url = https://github.com/lowenware/cStuff.git
|
|
@ -0,0 +1,5 @@
|
|||
(c) Copyright 2017 by Löwenware Ltd.
|
||||
|
||||
Developers:
|
||||
Elias Löwe <el@lowenware.com>
|
||||
Stanislav Ivanov <hotlinux@mail.ru>
|
|
@ -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}
|
||||
)
|
||||
|
||||
|
|
@ -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.
|
||||
*/
|
|
@ -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
|
||||
```
|
|
@ -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
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a423fa7a6dfbd637f3c0b248123f682456fccad7
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
if(DEFINED CMAKE_DEBUG)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror ")
|
||||
add_definitions(
|
||||
-DDEBUG
|
||||
)
|
||||
endif()
|
|
@ -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}"
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
|
@ -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}"
|
||||
)
|
|
@ -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}
|
||||
)
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
|
@ -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
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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 "";
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
|
@ -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
|
|
@ -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 "";
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
|
@ -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 );
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
Loading…
Reference in New Issue