Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
Ilja Kartašov | 89ef04cfd4 | |
Ilja Kartašov | aff6ab6fb2 | |
Ilja Kartašov | 043d414df4 | |
Ilja Kartašov | ce7eda1820 | |
Ilja Kartašov | 006efe8692 | |
Ilja Kartašov | 06c99b1e4b | |
Ilja Kartašov | f7a9f255df |
|
@ -1,27 +1,6 @@
|
||||||
# Binaries
|
build/
|
||||||
|
*.tar.gz
|
||||||
build/*
|
*.zip
|
||||||
root/*
|
*.rar
|
||||||
demo/*
|
*.gz
|
||||||
|
*.bz2
|
||||||
bin/*
|
|
||||||
obj/*
|
|
||||||
webstuff-*
|
|
||||||
tmp
|
|
||||||
tmp/*
|
|
||||||
*.tar.gz
|
|
||||||
*.zip
|
|
||||||
*.rar
|
|
||||||
*.gz
|
|
||||||
*.bz2
|
|
||||||
pkg/*
|
|
||||||
doc/html
|
|
||||||
vgcore.*
|
|
||||||
|
|
||||||
include/webstuff_bak
|
|
||||||
|
|
||||||
CMakeCache.txt
|
|
||||||
CMakeFiles/*
|
|
||||||
cmake_install.cmake
|
|
||||||
libaisl.dylib
|
|
||||||
demo/demo
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
[submodule "sdk"]
|
||||||
|
path = sdk
|
||||||
|
url = https://git.lowenware.com/lowenware/aisl-sdk.git
|
||||||
|
[submodule "cStuff"]
|
||||||
|
path = cStuff
|
||||||
|
url = https://git.lowenware.com/lowenware/cStuff.git
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Release 1.0.0
|
||||||
|
|
||||||
|
By Ilja Kartašov <ik@lowenware.com>, 2019-06-02
|
||||||
|
|
||||||
|
1. Library release with new and final API and documented code.
|
||||||
|
2. Previous version is being called `aisl-legacy` and will be maintained in
|
||||||
|
security aspects in branch called `legacy` until all applications using it will
|
||||||
|
be updated.
|
81
Makefile
81
Makefile
|
@ -2,89 +2,30 @@
|
||||||
# Makefile
|
# Makefile
|
||||||
# Ilja Kartašov, 2019-03-02 17:32
|
# Ilja Kartašov, 2019-03-02 17:32
|
||||||
#
|
#
|
||||||
.POSIX:
|
#
|
||||||
|
|
||||||
# Project directories
|
|
||||||
SRC_DIR ?= src
|
|
||||||
SDK_DIR ?= sdk
|
|
||||||
OUT_DIR ?= build
|
OUT_DIR ?= build
|
||||||
LIB_DIR ?= lib
|
|
||||||
DESTDIR ?=
|
|
||||||
|
|
||||||
# Project definition
|
.PHONY: library examples tool
|
||||||
include project.mk
|
|
||||||
|
|
||||||
# Examples submodule
|
all: library
|
||||||
include examples.mk
|
|
||||||
|
|
||||||
# CFLAGS
|
library:
|
||||||
|
@cd library && make
|
||||||
|
|
||||||
CFLAGS := \
|
examples: library
|
||||||
$(PROJECT_INCLUDES) \
|
@cd examples && make
|
||||||
-std=c99 \
|
|
||||||
-pedantic \
|
|
||||||
-Wall \
|
|
||||||
-Wmissing-prototypes \
|
|
||||||
-Wstrict-prototypes \
|
|
||||||
-Wold-style-definition \
|
|
||||||
-O2 \
|
|
||||||
-s \
|
|
||||||
-fvisibility=hidden \
|
|
||||||
-DVERSION_MAJOR=$(PROJECT_VERSION_MAJOR) \
|
|
||||||
-DVERSION_MINOR=$(PROJECT_VERSION_MINOR) \
|
|
||||||
-DVERSION_TWEAK=$(PROJECT_VERSION_TWEAK) \
|
|
||||||
-DVERSION_LABEL=$(PROJECT_VERSION_LABEL) \
|
|
||||||
$(CPPFLAGS) \
|
|
||||||
$(CFLAGS) \
|
|
||||||
$(PROJECT_CFLAGS) \
|
|
||||||
|
|
||||||
|
|
||||||
LDFLAGS := \
|
|
||||||
$(PROJECT_LIBRARIES) \
|
|
||||||
$(LDFLAGS) \
|
|
||||||
$(PROJECT_LDFLAGS) \
|
|
||||||
|
|
||||||
|
|
||||||
SOURCE_LIST := $(wildcard $(PROJECT_SOURCES))
|
|
||||||
OBJECT_FILES := $(addprefix $(OUT_DIR)/o_, ${SOURCE_LIST:.c=.o})
|
|
||||||
|
|
||||||
|
|
||||||
library: dirs $(OBJECT_FILES)
|
|
||||||
$(info linking target: $@)
|
|
||||||
@$(CC) -shared -o $(OUT_DIR)/lib$(PROJECT_NAME).so $(OBJECT_FILES) $(LDFLAGS)
|
|
||||||
$(info done: $@)
|
|
||||||
|
|
||||||
|
|
||||||
build/o_%.o: %.c
|
|
||||||
$(info compiling file: $<)
|
|
||||||
@$(CC) $(CFLAGS) -fpic -c $< -o $@
|
|
||||||
|
|
||||||
dirs:
|
|
||||||
$(info preparing: build folders)
|
|
||||||
@mkdir -p $(OUT_DIR)/o_$(SRC_DIR)
|
|
||||||
@mkdir -p $(OUT_DIR)/o_$(SDK_DIR)
|
|
||||||
|
|
||||||
|
tool: library
|
||||||
|
@cd tool && make
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(info cleaning: build files)
|
$(info cleaning: build files)
|
||||||
@rm -Rf $(OUT_DIR)
|
@rm -Rf $(OUT_DIR)
|
||||||
@rm -Rf ./vgcore.*
|
@rm -Rf ./vgcore.*
|
||||||
|
|
||||||
doc:
|
|
||||||
doxygen doc/api-reference.conf
|
|
||||||
|
|
||||||
all: library examples doc
|
|
||||||
|
|
||||||
default: library
|
|
||||||
.PHONY: all dirs clean doc install
|
|
||||||
|
|
||||||
install: library
|
install: library
|
||||||
$(info installing files)
|
cd library && make install
|
||||||
@mkdir -p $(DESTDIR)$(PREFIX)/$(LIB_DIR)
|
cd tool && make install
|
||||||
@mkdir -p $(DESTDIR)$(PREFIX)/include
|
|
||||||
|
|
||||||
@cp $(OUT_DIR)/lib$(PROJECT_NAME).so $(DESTDIR)$(PREFIX)/$(LIB_DIR)
|
|
||||||
@cp -R include/aisl $(DESTDIR)$(PREFIX)/include
|
|
||||||
|
|
||||||
# vim:ft=make
|
# vim:ft=make
|
||||||
#
|
#
|
||||||
|
|
48
README.md
48
README.md
|
@ -1,36 +1,32 @@
|
||||||
# AISL
|
# AISL
|
||||||
Asynchronous Internet Server Library
|
|
||||||
|
|
||||||
## Installation on CentOS 7 / RedHat 7
|
Asynchronous Internet Server Library provides innovative way of web development.
|
||||||
|
AISL based applications have built-in web server giving full control of client
|
||||||
|
serving. All you need to know is a request string? - Start prepare the response
|
||||||
|
without waiting for headers and body! Don't need some headers? - Don't save them
|
||||||
|
in memory! Unwanted content-body? - simply ignore it!
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
[Hello World](https://lowenware.com/aisl/handbook.html#getting-started) example
|
||||||
|
and full [API reference](https://lowenware.com/aisl/handbook.html#api-reference)
|
||||||
|
can be found in an oficial [AISL HandBook](https://lowenware.com/aisl/handbook.html).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
1. Add repository
|
|
||||||
```
|
```
|
||||||
sudo curl -o /etc/yum.repos.d/lowenware.repo https://lowenware.com/rpm/redhat-7/lowenware.repo
|
$ make PREFIX=/usr/local
|
||||||
|
$ sudo make PREFIX=/usr/local install
|
||||||
|
$ sudo cp libaisl.pc.example /usr/lib/pkgconfig/libaisl.pc
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Import GPG key
|
ArchLinux users can install from [AUR](https://aur.archlinux.org/packages/aisl-git/) :
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo rpm --import https://lowenware.com/rpm/RPM-GPG-KEY-Lowenware
|
$ yaourt -S aisl-git
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Install
|
## License
|
||||||
```
|
|
||||||
sudo yum install aisl aisl-devel
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installation from sources on any distro
|
AISL is free for both commercial and non-commercial use, being distributed under
|
||||||
|
terms of [CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0/).
|
||||||
1. Configuration
|
|
||||||
```
|
|
||||||
cmake -DCMAKE_INSTALL_PREFIX=/usr/local
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Compilation
|
|
||||||
```
|
|
||||||
make
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Installation
|
|
||||||
```
|
|
||||||
sudo make install
|
|
||||||
```
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 4ba00ca17a6a86a9309fe8426220cc378d8f4579
|
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +0,0 @@
|
||||||
<!-- HTML footer for doxygen 1.8.14-->
|
|
||||||
<!-- start footer part -->
|
|
||||||
<!--BEGIN GENERATE_TREEVIEW-->
|
|
||||||
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
|
||||||
<ul>
|
|
||||||
$navpath
|
|
||||||
<li class="footer">$generatedby
|
|
||||||
<a href="http://www.doxygen.org/index.html">
|
|
||||||
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<!--END GENERATE_TREEVIEW-->
|
|
||||||
<!--BEGIN !GENERATE_TREEVIEW-->
|
|
||||||
<hr class="footer"/><address class="footer"><small>
|
|
||||||
$generatedby  <a href="http://www.doxygen.org/index.html">
|
|
||||||
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
|
|
||||||
</a> $doxygenversion
|
|
||||||
</small></address>
|
|
||||||
<!--END !GENERATE_TREEVIEW-->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,56 +0,0 @@
|
||||||
<!-- HTML header for doxygen 1.8.14-->
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
|
||||||
<meta name="generator" content="Doxygen $doxygenversion"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
||||||
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
|
||||||
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
|
||||||
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
|
||||||
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
|
||||||
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
|
||||||
$treeview
|
|
||||||
$search
|
|
||||||
$mathjax
|
|
||||||
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
|
||||||
$extrastylesheet
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
||||||
|
|
||||||
<!--BEGIN TITLEAREA-->
|
|
||||||
<div id="titlearea">
|
|
||||||
<table cellspacing="0" cellpadding="0">
|
|
||||||
<tbody>
|
|
||||||
<tr style="height: 56px;">
|
|
||||||
<!--BEGIN PROJECT_LOGO-->
|
|
||||||
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
|
||||||
<!--END PROJECT_LOGO-->
|
|
||||||
<!--BEGIN PROJECT_NAME-->
|
|
||||||
<td id="projectalign" style="padding-left: 0.5em;">
|
|
||||||
<div id="projectname">$projectname
|
|
||||||
<!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
|
|
||||||
</div>
|
|
||||||
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
|
||||||
</td>
|
|
||||||
<!--END PROJECT_NAME-->
|
|
||||||
<!--BEGIN !PROJECT_NAME-->
|
|
||||||
<!--BEGIN PROJECT_BRIEF-->
|
|
||||||
<td style="padding-left: 0.5em;">
|
|
||||||
<div id="projectbrief">$projectbrief</div>
|
|
||||||
</td>
|
|
||||||
<!--END PROJECT_BRIEF-->
|
|
||||||
<!--END !PROJECT_NAME-->
|
|
||||||
<!--BEGIN DISABLE_INDEX-->
|
|
||||||
<!--BEGIN SEARCHENGINE-->
|
|
||||||
<td>$searchbox</td>
|
|
||||||
<!--END SEARCHENGINE-->
|
|
||||||
<!--END DISABLE_INDEX-->
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<!--END TITLEAREA-->
|
|
||||||
<!-- end header part -->
|
|
1596
doc/stylesheet.css
1596
doc/stylesheet.css
File diff suppressed because it is too large
Load Diff
|
@ -24,7 +24,7 @@ examples: library hello_world
|
||||||
|
|
||||||
hello_world:
|
hello_world:
|
||||||
$(info compiling: hello world)
|
$(info compiling: hello world)
|
||||||
$(CC) $(EXAMPLES_CFLAGS) \
|
@$(CC) $(EXAMPLES_CFLAGS) \
|
||||||
-o $(OUT_DIR)/hello-world $(EXAMPLES_DIR)/hello-world.c $(EXAMPLES_LDFLAGS)
|
-o $(OUT_DIR)/hello-world $(EXAMPLES_DIR)/hello-world.c $(EXAMPLES_LDFLAGS)
|
||||||
|
|
||||||
# vim:ft=make
|
# vim:ft=make
|
||||||
|
|
|
@ -20,80 +20,85 @@
|
||||||
#include <aisl/aisl.h>
|
#include <aisl/aisl.h>
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_HTTP_PORT 8080 /**< Default HTTP server port */
|
static void
|
||||||
|
hello_world(const struct aisl_evt *evt, void *p_ctx);
|
||||||
|
|
||||||
|
|
||||||
|
static const struct aisl_cfg_srv m_srv[] = {{
|
||||||
|
.host = "0.0.0.0",
|
||||||
|
.port = 8080,
|
||||||
|
.secure = false
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
static const struct aisl_cfg m_cfg = {
|
||||||
|
AISL_CFG_DEFAULTS
|
||||||
|
, .srv = m_srv
|
||||||
|
, .srv_cnt = sizeof (m_srv) / sizeof (m_srv[0])
|
||||||
|
, .ssl = NULL
|
||||||
|
, .ssl_cnt = 0
|
||||||
|
, .callback = hello_world
|
||||||
|
, .p_ctx = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hello_world(const struct aisl_evt *evt, void *p_ctx)
|
hello_world(const struct aisl_evt *evt, void *p_ctx)
|
||||||
{
|
{
|
||||||
if (evt->code != AISL_EVENT_STREAM_REQUEST)
|
AislStream s;
|
||||||
return;
|
|
||||||
|
|
||||||
AislStatus status;
|
const char html[] =
|
||||||
|
"<html>"
|
||||||
|
"<head>"
|
||||||
|
"<title>Hello World</title>"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
"<h1>Hello World</h1>"
|
||||||
|
"<p>Powered by AISL</p>"
|
||||||
|
"</body>"
|
||||||
|
"</html>";
|
||||||
|
|
||||||
|
fprintf(stdout, "Event: %s\n", aisl_event_to_string(evt->code) );
|
||||||
|
|
||||||
AislStream s = evt->source;
|
if (evt->code != AISL_EVENT_STREAM_REQUEST)
|
||||||
|
return;
|
||||||
|
|
||||||
const char html[] =
|
s = evt->source;
|
||||||
"<html>"
|
|
||||||
"<head>"
|
|
||||||
"<title>Hello World</title>"
|
|
||||||
"</head>"
|
|
||||||
"<body>"
|
|
||||||
"<h1>Hello World</h1>"
|
|
||||||
"<p>Powered by AISL</p>"
|
|
||||||
"</body>"
|
|
||||||
"</html>";
|
|
||||||
|
|
||||||
status = aisl_response(s, AISL_HTTP_OK, sizeof (html)-1);
|
if (aisl_response(s, AISL_HTTP_OK, sizeof (html)-1) == AISL_SUCCESS) {
|
||||||
|
if (aisl_write(s, html, sizeof (html)-1) != -1) {
|
||||||
|
aisl_flush(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (status == AISL_SUCCESS)
|
aisl_reject(s);
|
||||||
{
|
(void) p_ctx;
|
||||||
if (aisl_write(s, html, sizeof (html)-1) != -1)
|
|
||||||
{
|
|
||||||
aisl_flush(s);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
aisl_reject(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) p_ctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char ** argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
AislInstance aisl; /**< AISL instance pointer */
|
AislInstance aisl; /**< AISL instance pointer */
|
||||||
AislStatus status; /**< AISL status code */
|
AislStatus status; /**< AISL status code */
|
||||||
struct aisl_cfg cfg = AISL_CFG_DEFAULT;
|
|
||||||
struct aisl_cfg_srv srv = {
|
|
||||||
.host = "0.0.0.0",
|
|
||||||
.port = DEFAULT_HTTP_PORT,
|
|
||||||
.secure = false
|
|
||||||
};
|
|
||||||
|
|
||||||
cfg.srv = &srv;
|
/* Initialize instance */
|
||||||
cfg.srv_cnt = 1;
|
if ( (aisl = aisl_new(&m_cfg)) != NULL ) {
|
||||||
cfg.callback = hello_world;
|
/* launch application loop */
|
||||||
|
fprintf(stdout, "Entering main loop\n" );
|
||||||
|
for(;;) {
|
||||||
|
status = aisl_run_cycle(aisl);
|
||||||
|
|
||||||
/* Initialize instance */
|
if ( status != AISL_SUCCESS )
|
||||||
if ( (aisl = aisl_new(&cfg)) != NULL )
|
aisl_sleep(aisl, 500);
|
||||||
{
|
}
|
||||||
/* launch application loop */
|
|
||||||
fprintf(stdout, "Entering main loop" );
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
status = aisl_run_cycle(aisl);
|
|
||||||
|
|
||||||
if ( status != AISL_SUCCESS )
|
aisl_free(aisl);
|
||||||
aisl_sleep(aisl, 500);
|
} else {
|
||||||
}
|
fprintf(stderr, "Failed to initialize AISL\n");
|
||||||
|
}
|
||||||
|
|
||||||
aisl_free(aisl);
|
return 0;
|
||||||
}
|
|
||||||
else
|
|
||||||
fprintf(stderr, "Failed to initialize AISL");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,11 @@ AislHttpVersion
|
||||||
aisl_client_get_http_version(AislClient client);
|
aisl_client_get_http_version(AislClient client);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copies #AislClient network address to provided sockaddr_in structure.
|
||||||
|
* @param client an #AislClient instance pointer.
|
||||||
|
* @param address a pointer to a sockaddr_in structure
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
aisl_client_get_address(AislClient client, struct sockaddr_in *address);
|
aisl_client_get_address(AislClient client, struct sockaddr_in *address);
|
||||||
|
|
||||||
|
|
|
@ -18,49 +18,47 @@
|
||||||
|
|
||||||
#include <aisl/types.h>
|
#include <aisl/types.h>
|
||||||
|
|
||||||
#define AISL_CFG_DEFAULT { \
|
#define AISL_CFG_DEFAULTS \
|
||||||
.callback = NULL \
|
.client_spool_size = 32 \
|
||||||
, .p_ctx = NULL \
|
|
||||||
, .srv = NULL \
|
|
||||||
, .ssl = NULL \
|
|
||||||
, .srv_cnt = 0 \
|
|
||||||
, .ssl_cnt = 0 \
|
|
||||||
, .client_spool_size = 32 \
|
|
||||||
, .initial_buffer_size = 16536 \
|
, .initial_buffer_size = 16536 \
|
||||||
, .client_accept_limit = 1024 \
|
, .client_accept_limit = 1024 \
|
||||||
, .client_silence_timeout = 30 \
|
, .client_silence_timeout = 30 \
|
||||||
} \
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Server configuration structure
|
||||||
|
*/
|
||||||
struct aisl_cfg_srv {
|
struct aisl_cfg_srv {
|
||||||
const char * host;
|
const char *host; /**< server IP to listen */
|
||||||
uint16_t port;
|
uint16_t port; /**< server port to listen */
|
||||||
bool secure;
|
bool secure; /**< shall server use TLS */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief SSL configuration structure
|
||||||
|
*/
|
||||||
struct aisl_cfg_ssl {
|
struct aisl_cfg_ssl {
|
||||||
const char * host;
|
const char *host; /**< secure server hostname */
|
||||||
const char * key_file;
|
const char *key_file; /**< path to SSL key file */
|
||||||
const char * crt_file;
|
const char *crt_file; /**< path to SSL certificate file */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct aisl_cfg
|
/** @brief AISL initial configuration structure
|
||||||
{
|
*/
|
||||||
/* event handlers */
|
struct aisl_cfg {
|
||||||
AislCallback callback;
|
AislCallback callback; /**< A pointer to #AislCallback event handler */
|
||||||
void *p_ctx;
|
void *p_ctx; /**< User defined context for #AislCallback */
|
||||||
|
|
||||||
struct aisl_cfg_srv *srv;
|
const struct aisl_cfg_srv *srv; /**< A pointer to array of #aisl_cfg_srv */
|
||||||
struct aisl_cfg_ssl *ssl;
|
const struct aisl_cfg_ssl *ssl; /**< A pointer to array of #aisl_cfg_ssl */
|
||||||
|
|
||||||
int srv_cnt;
|
int srv_cnt; /**< Size of #aisl_cfg_srv array */
|
||||||
int ssl_cnt;
|
int ssl_cnt; /**< Size of #aisl_cfg_ssl array */
|
||||||
|
|
||||||
int client_spool_size;
|
int client_spool_size; /**< Initial size of client spool */
|
||||||
int initial_buffer_size;
|
int initial_buffer_size; /**< Initial size of communication buffer */
|
||||||
int client_accept_limit;
|
int client_accept_limit; /**< Maximal number of concurent clients */
|
||||||
int client_silence_timeout;
|
int client_silence_timeout; /**< Client silence timeout */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* !AISL_CONFIG_H */
|
#endif /* !AISL_CONFIG_H */
|
||||||
|
|
|
@ -19,53 +19,109 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <aisl/types.h>
|
#include <aisl/types.h>
|
||||||
|
|
||||||
|
#define aisl_stream_get_instance aisl_get_instance
|
||||||
|
|
||||||
|
/** @brief Gets a value of #AislStream security flag
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return is true if stream is encrypted and false otherwise
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
aisl_is_secure(AislStream stream);
|
aisl_is_secure(AislStream stream);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Gets an #AislClient instance associated with the stream
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return an #AislClient instance pointer
|
||||||
|
*/
|
||||||
AislClient
|
AislClient
|
||||||
aisl_get_client(AislStream stream);
|
aisl_get_client(AislStream stream);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Gets an #AislServer instance associated with the stream
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return an #AislServer instance pointer
|
||||||
|
*/
|
||||||
AislServer
|
AislServer
|
||||||
aisl_get_server(AislStream stream);
|
aisl_get_server(AislStream stream);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Gets an #AislHttpVersion of the stream
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return an #AislHttpVersion value
|
||||||
|
*/
|
||||||
AislHttpVersion
|
AislHttpVersion
|
||||||
aisl_get_http_version(AislStream stream);
|
aisl_get_http_version(AislStream stream);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Gets an #AislInstance pointer associated with the stream
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return an #AislInstance pointer
|
||||||
|
*/
|
||||||
AislInstance
|
AislInstance
|
||||||
aisl_stream_get_instance(AislStream s);
|
aisl_get_instance(AislStream s);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Gets the stream context previously set with #aisl_set_context
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return a pointer to the stream context
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
aisl_get_context(AislStream stream);
|
aisl_get_context(AislStream stream);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Associate a context pointer with the stream until its lifetime.
|
||||||
|
* Previously allocated data should be free'd on #AISL_EVENT_STREAM_CLOSE if
|
||||||
|
* not needed anymore.
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param context a pointer to any user-defined data
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
aisl_set_context(AislStream stream, void *context);
|
aisl_set_context(AislStream stream, void *context);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief A call to start stream data transmission to a client
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return a #AislStatus displaying if stream is ready to be proceed by teh engine
|
||||||
|
*/
|
||||||
AislStatus
|
AislStatus
|
||||||
aisl_flush(AislStream stream);
|
aisl_flush(AislStream stream);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief A call to reject the stream. In HTTP 1.X it also closes client's connection
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
aisl_reject(AislStream stream);
|
aisl_reject(AislStream stream);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief A call to begin the HTTP response
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param status_code of the HTTP response
|
||||||
|
* @param content_length in bytes or #AISL_AUTO_LENGTH if length is not knonw yet
|
||||||
|
* @return #AislStatus code
|
||||||
|
*/
|
||||||
AislStatus
|
AislStatus
|
||||||
aisl_response(AislStream stream,
|
aisl_response(AislStream stream,
|
||||||
AislHttpResponse status_code,
|
AislHttpResponse status_code,
|
||||||
uint64_t content_length);
|
uint64_t content_length);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Adds HTTP header to the stream buffer
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param key of HTTP header
|
||||||
|
* @param value of HTTP header
|
||||||
|
* @return a length of data added to the stream buffer
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
aisl_header(AislStream stream, const char *key, const char *value );
|
aisl_header(AislStream stream, const char *key, const char *value);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Adds printf-like formatted HTTP header to the stream buffer
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param key of HTTP header
|
||||||
|
* @param format of HTTP header value
|
||||||
|
* @return a length of data added to the stream buffer
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
aisl_header_printf(AislStream stream,
|
aisl_header_printf(AislStream stream,
|
||||||
const char *key,
|
const char *key,
|
||||||
|
@ -73,6 +129,13 @@ aisl_header_printf(AislStream stream,
|
||||||
... );
|
... );
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Adds vprintf-like formatted HTTP header to the stream buffer
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param key of HTTP header
|
||||||
|
* @param format of HTTP header value
|
||||||
|
* @param args list for HTTP header value construction
|
||||||
|
* @return a length of data added to the stream buffer
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
aisl_header_vprintf(AislStream stream,
|
aisl_header_vprintf(AislStream stream,
|
||||||
const char *key,
|
const char *key,
|
||||||
|
@ -80,26 +143,56 @@ aisl_header_vprintf(AislStream stream,
|
||||||
va_list args );
|
va_list args );
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Adds printf-like formatted HTTP response to the stream buffer
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param format of the HTTP response
|
||||||
|
* @return a length of data added to the stream buffer
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
aisl_printf(AislStream stream, const char *format, ...);
|
aisl_printf(AislStream stream, const char *format, ...);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Adds vprintf-like formatted HTTP response to the stream buffer
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param format of the HTTP response
|
||||||
|
* @param args list for HTTP response construction
|
||||||
|
* @return a length of data added to the stream buffer
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
aisl_vprintf(AislStream stream, const char *format, va_list args);
|
aisl_vprintf(AislStream stream, const char *format, va_list args);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Adds data of the HTTP response to the stream buffer
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param data a pointer to HTTP response data array
|
||||||
|
* @param d_len size of the HTTP response data array
|
||||||
|
* @return a length of data added to the stream buffer
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
aisl_write(AislStream stream, const char *data, int d_len);
|
aisl_write(AislStream stream, const char *data, int d_len);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Adds a null-terminated string to the stream buffer
|
||||||
|
* @param str_data the HTTP response string
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return a length of data added to the stream buffer
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
aisl_puts(const char *str_data, AislStream stream);
|
aisl_puts(const char *str_data, AislStream stream);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Switches triggering of #AISL_EVENT_STREAM_OUTPUT
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @param value a true to enable or false to disable (default) triggering
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
aisl_set_output_event(AislStream stream, bool value);
|
aisl_set_output_event(AislStream stream, bool value);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Gets state of the #AISL_EVENT_STREAM_OUTPUT triggering
|
||||||
|
* @param stream an #AislStream instance
|
||||||
|
* @return true if triggering is enabled and flase otherwise
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
aisl_get_output_event(AislStream stream);
|
aisl_get_output_event(AislStream stream);
|
||||||
|
|
||||||
|
|
|
@ -20,26 +20,22 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
|
||||||
#include <openssl/ssl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define AISL_AUTO_LENGTH (~0)
|
#define AISL_AUTO_LENGTH (~0)
|
||||||
|
|
||||||
/** type casts */
|
/** type casts */
|
||||||
#define AISL_CALLBACK(x) ((AislCallback) x)
|
#define AISL_CALLBACK(x) ((AislCallback) x)
|
||||||
|
|
||||||
|
|
||||||
/** AISL Instance */
|
/** @brief AISL Instance */
|
||||||
typedef struct aisl_instance * AislInstance;
|
typedef struct aisl_instance * AislInstance;
|
||||||
|
|
||||||
/** HTTP(s) Server */
|
/** @brief HTTP(s) Server */
|
||||||
typedef struct aisl_server * AislServer;
|
typedef struct aisl_server * AislServer;
|
||||||
|
|
||||||
/** HTTP(s) Client */
|
/** @brief HTTP(s) Client */
|
||||||
typedef struct aisl_client * AislClient;
|
typedef struct aisl_client * AislClient;
|
||||||
|
|
||||||
/** Server<->Client Stream */
|
/** @brief Server<->Client Stream */
|
||||||
typedef struct aisl_stream * AislStream;
|
typedef struct aisl_stream * AislStream;
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,15 +50,16 @@ typedef enum {
|
||||||
, AISL_IDLE = 1
|
, AISL_IDLE = 1
|
||||||
} AislStatus;
|
} AislStatus;
|
||||||
|
|
||||||
#ifndef WITHOUT_STRINGIFIERS
|
|
||||||
|
|
||||||
|
/** @brief Converts #AislStatus code to a null terminated string
|
||||||
|
* @param status an #AislStatus code
|
||||||
|
* @return pointer to the string representing #AislStatus
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
aisl_status_to_string(AislStatus status);
|
aisl_status_to_string(AislStatus status);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/** @brief HTTP version enumeration */
|
||||||
/** Generic HTTP Enumerations */
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AISL_HTTP_0_9 = 0x0009
|
AISL_HTTP_0_9 = 0x0009
|
||||||
, AISL_HTTP_1_0 = 0x0100
|
, AISL_HTTP_1_0 = 0x0100
|
||||||
|
@ -71,10 +68,15 @@ typedef enum {
|
||||||
} AislHttpVersion;
|
} AislHttpVersion;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Converts #AislHttpVersion code to a null terminated string
|
||||||
|
* @param version an #AislHttpVersion code
|
||||||
|
* @return pointer to the string representing #AislHttpVersion
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
aisl_http_version_to_string(AislHttpVersion version);
|
aisl_http_version_to_string(AislHttpVersion version);
|
||||||
|
|
||||||
|
|
||||||
|
/** HTTP method enumeration */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AISL_HTTP_METHOD_UNKNOWN
|
AISL_HTTP_METHOD_UNKNOWN
|
||||||
, AISL_HTTP_GET
|
, AISL_HTTP_GET
|
||||||
|
@ -89,10 +91,15 @@ typedef enum {
|
||||||
} AislHttpMethod;
|
} AislHttpMethod;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Converts #AislHttpMethod code to a null terminated string
|
||||||
|
* @param method an #AislHttpMethod code
|
||||||
|
* @return pointer to the string representing #AislHttpMethod
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
aisl_http_method_to_string( AislHttpMethod method );
|
aisl_http_method_to_string(AislHttpMethod method);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief HTTP response status enumeration */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AISL_HTTP_CONTINUE = 100
|
AISL_HTTP_CONTINUE = 100
|
||||||
, AISL_HTTP_SWITCHING_PROTOCOLS
|
, AISL_HTTP_SWITCHING_PROTOCOLS
|
||||||
|
@ -142,11 +149,15 @@ typedef enum {
|
||||||
} AislHttpResponse;
|
} AislHttpResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Converts #AislHttpResponse code to a null terminated string
|
||||||
|
* @param code an #AislHttpResponse code
|
||||||
|
* @return pointer to the string representing #AislHttpResponse
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
aisl_http_response_to_string( AislHttpResponse code );
|
aisl_http_response_to_string(AislHttpResponse code);
|
||||||
|
|
||||||
|
|
||||||
/** Codes of AISL events */
|
/** @brief AISL events enumeration */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AISL_EVENT_SERVER_READY = 100
|
AISL_EVENT_SERVER_READY = 100
|
||||||
, AISL_EVENT_SERVER_ERROR = 190
|
, AISL_EVENT_SERVER_ERROR = 190
|
||||||
|
@ -164,45 +175,52 @@ typedef enum {
|
||||||
} AislEvent;
|
} AislEvent;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief generic AISL event structure */
|
||||||
struct aisl_evt {
|
struct aisl_evt {
|
||||||
void *source;
|
void *source; /**< Pointer to an event source: #AislServer, #AislClient, #AislStream */
|
||||||
AislEvent code;
|
AislEvent code; /**< Event code */
|
||||||
AislStatus status;
|
AislStatus status; /**< Event status */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* void type event callback */
|
/** @brief event handler callback definition
|
||||||
|
* @param evt a pointer to an #aisl_evt structure
|
||||||
|
* @param ctx a pointer to a context defined by user (see #aisl_cfg)
|
||||||
|
*/
|
||||||
typedef void
|
typedef void
|
||||||
(* AislCallback) (const struct aisl_evt *evt, void *ctx);
|
(* AislCallback) (const struct aisl_evt *evt, void *ctx);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief AISL event structue passed on stream opening */
|
||||||
struct aisl_evt_open {
|
struct aisl_evt_open {
|
||||||
struct aisl_evt evt;
|
struct aisl_evt evt; /**< generic #aisl_evt structure */
|
||||||
const char *path;
|
const char *path; /**< HTTP request path */
|
||||||
const char *query;
|
const char *query; /**< HTTP request query (GET params) */
|
||||||
AislHttpMethod http_method;
|
AislHttpMethod http_method; /**< HTTP request method */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief AISL event structue passed on HTTP header reception */
|
||||||
struct aisl_evt_header {
|
struct aisl_evt_header {
|
||||||
struct aisl_evt evt;
|
struct aisl_evt evt; /**< generic #aisl_evt structure */
|
||||||
const char *key;
|
const char *key; /**< low case HTTP header name */
|
||||||
const char *value;
|
const char *value; /**< HTTP header string */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief AISL event structue passed on HTTP request data part received */
|
||||||
struct aisl_evt_input {
|
struct aisl_evt_input {
|
||||||
struct aisl_evt evt;
|
struct aisl_evt evt; /**< generic #aisl_evt structure */
|
||||||
const char *data;
|
const char *data; /**< a pointer to received data array */
|
||||||
int32_t size;
|
int32_t size; /**< data array size */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifndef WITHOUT_STRINGIFIERS
|
/** @brief Converts #AislEvent code to a null terminated string
|
||||||
|
* @param evt an #AislEvent code
|
||||||
|
* @return pointer to the string representing #AislEvent
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
aisl_event_to_string(AislEvent evt);
|
aisl_event_to_string(AislEvent evt);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !AISL_TYPES_H */
|
#endif /* !AISL_TYPES_H */
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
#
|
||||||
|
# Makefile
|
||||||
|
# Ilja Kartašov, 2019-07-13 14:51
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
.POSIX:
|
||||||
|
|
||||||
|
CC ?= gcc
|
||||||
|
AR ?= ar
|
||||||
|
PKG_CONFIG ?= pkg-config
|
||||||
|
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
DESTDIR ?=
|
||||||
|
LIB_DIR ?= lib
|
||||||
|
|
||||||
|
TARGET_NAME = aisl
|
||||||
|
OUT_DIR ?= ../build
|
||||||
|
SRC_DIR ?= .
|
||||||
|
|
||||||
|
# Version
|
||||||
|
|
||||||
|
VERSION_MAJOR = 1
|
||||||
|
VERSION_MINOR = 0
|
||||||
|
VERSION_TWEAK = 5
|
||||||
|
VERSION_LABEL = 0
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
|
||||||
|
SOURCE_FILES := \
|
||||||
|
$(SRC_DIR)/instance.c \
|
||||||
|
$(SRC_DIR)/server.c \
|
||||||
|
$(SRC_DIR)/client.c \
|
||||||
|
$(SRC_DIR)/stream.c \
|
||||||
|
$(SRC_DIR)/http.c \
|
||||||
|
$(SRC_DIR)/ssl.c \
|
||||||
|
$(SRC_DIR)/list.c \
|
||||||
|
$(SRC_DIR)/str-utils.c \
|
||||||
|
$(SRC_DIR)/buffer.c \
|
||||||
|
$(SRC_DIR)/types.c \
|
||||||
|
|
||||||
|
# compilation macro options:
|
||||||
|
|
||||||
|
AISL_WITH_DEBUG ?= 0 # disable debug output
|
||||||
|
AISL_WITH_SSL ?= 1 # enable SSL support
|
||||||
|
AISL_WITH_STRINGIFIERS ?= 1 # enable *_to_string functions
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS := \
|
||||||
|
-std=c99 \
|
||||||
|
-pedantic \
|
||||||
|
-Wall \
|
||||||
|
-Wmissing-prototypes \
|
||||||
|
-Wstrict-prototypes \
|
||||||
|
-Wold-style-definition \
|
||||||
|
-O2 \
|
||||||
|
-s \
|
||||||
|
-fvisibility=hidden \
|
||||||
|
\
|
||||||
|
-I../ \
|
||||||
|
-I../include \
|
||||||
|
\
|
||||||
|
-D_POSIX_C_SOURCE=200809L \
|
||||||
|
-DAISL_WITH_DEBUG=$(AISL_WITH_DEBUG) \
|
||||||
|
-DAISL_WITH_SSL=$(AISL_WITH_SSL) \
|
||||||
|
-DAISL_WITH_STRINGIFIERS=$(AISL_WITH_STRINGIFIERS) \
|
||||||
|
\
|
||||||
|
`$(PKG_CONFIG) --cflags openssl` \
|
||||||
|
$(CFLAGS) \
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
`$(PKG_CONFIG) --libs openssl` \
|
||||||
|
|
||||||
|
# flags
|
||||||
|
|
||||||
|
SOURCE_LIST := $(wildcard $(SOURCE_FILES))
|
||||||
|
SHARED_OBJS := $(addsuffix .o, $(addprefix $(OUT_DIR)/shared/, ${SOURCE_LIST}))
|
||||||
|
STATIC_OBJS := $(addsuffix .o, $(addprefix $(OUT_DIR)/static/, ${SOURCE_LIST}))
|
||||||
|
|
||||||
|
all: lib$(TARGET_NAME).so lib$(TARGET_NAME).a
|
||||||
|
$(info AISL_WITH_DEBUG=$(AISL_WITH_DEBUG))
|
||||||
|
$(info AISL_WITH_SSL=$(AISL_WITH_SSL))
|
||||||
|
$(info AISL_WITH_STRINGIFIERS=$(AISL_WITH_STRINGIFIERS))
|
||||||
|
|
||||||
|
lib$(TARGET_NAME).so: $(SHARED_OBJS)
|
||||||
|
$(info building target: $@)
|
||||||
|
@$(CC) -shared -o $(OUT_DIR)/$@ $(SHARED_OBJS) $(LDFLAGS)
|
||||||
|
$(info done: $@)
|
||||||
|
|
||||||
|
lib$(TARGET_NAME).a: $(STATIC_OBJS)
|
||||||
|
$(info building target: $@)
|
||||||
|
@$(AR) rcs $(OUT_DIR)/$@ $(STATIC_OBJS)
|
||||||
|
$(info done: $@)
|
||||||
|
|
||||||
|
$(OUT_DIR)/shared/%.o: %
|
||||||
|
$(info compiling file: $<)
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@$(CC) $(CFLAGS) -fpic -c $< -o $@
|
||||||
|
|
||||||
|
$(OUT_DIR)/static/%.o: %
|
||||||
|
$(info compiling file: $<)
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
install:lib$(TARGET_NAME).so lib$(TARGET_NAME).a
|
||||||
|
$(info installing files)
|
||||||
|
@mkdir -p $(DESTDIR)$(PREFIX)/$(LIB_DIR)
|
||||||
|
@mkdir -p $(DESTDIR)$(PREFIX)/include
|
||||||
|
@cp $(OUT_DIR)/lib$(LIBRARY_NAME).so $(DESTDIR)$(PREFIX)/$(LIB_DIR)
|
||||||
|
@cp $(OUT_DIR)/lib$(LIBRARY_NAME).a $(DESTDIR)$(PREFIX)/$(LIB_DIR)
|
||||||
|
@cp -R include/aisl $(DESTDIR)$(PREFIX)/include
|
||||||
|
|
||||||
|
|
||||||
|
# vim:ft=make
|
||||||
|
#
|
|
@ -15,20 +15,19 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "debug.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
|
|
||||||
static int32_t
|
static int32_t
|
||||||
buffer_set_size(struct buffer *buffer, int32_t new_size)
|
buffer_set_size(struct buffer *buffer, int32_t new_size)
|
||||||
{
|
{
|
||||||
if (new_size != buffer->size) {
|
if (!buffer->size || new_size != buffer->size) {
|
||||||
char *data;
|
char *data;
|
||||||
|
|
||||||
if (new_size) {
|
if (new_size) {
|
||||||
int32_t s = new_size / 1024;
|
if (new_size % 4096) {
|
||||||
|
new_size = (new_size / 4096 + 1) * 4096;
|
||||||
if ( new_size % 1024 ) {
|
|
||||||
new_size = (s+1) * 1024;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
new_size = 16*1024;
|
new_size = 16*1024;
|
||||||
|
@ -49,7 +48,7 @@ buffer_set_size(struct buffer *buffer, int32_t new_size)
|
||||||
int32_t
|
int32_t
|
||||||
buffer_init(struct buffer *buffer, int32_t size)
|
buffer_init(struct buffer *buffer, int32_t size)
|
||||||
{
|
{
|
||||||
if ( (size = buffer_set_size(buffer, size)) != -1)
|
if ((size = buffer_set_size(buffer, size)) != -1)
|
||||||
buffer->used = 0;
|
buffer->used = 0;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
@ -84,14 +83,14 @@ buffer_move_offset(struct buffer *buffer, int32_t offset, int32_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int32_t
|
||||||
buffer_insert(struct buffer *buffer,
|
buffer_insert(struct buffer *buffer, int32_t offset, const char *data,
|
||||||
int32_t offset,
|
int32_t size)
|
||||||
const char *data,
|
|
||||||
int32_t size)
|
|
||||||
{
|
{
|
||||||
int32_t result;
|
int32_t result;
|
||||||
|
|
||||||
if ( (result = buffer_set_size(buffer, size)) != -1) {
|
DPRINTF("Buffer: %d of %d", buffer->used, buffer->size);
|
||||||
|
|
||||||
|
if ( (result = buffer_set_size(buffer, buffer->size + size)) != -1) {
|
||||||
if ((result = buffer_move_offset(buffer, offset, size)) != -1) {
|
if ((result = buffer_move_offset(buffer, offset, size)) != -1) {
|
||||||
memcpy(&buffer->data[offset], data, size);
|
memcpy(&buffer->data[offset], data, size);
|
||||||
buffer->used += result;
|
buffer->used += result;
|
||||||
|
@ -118,17 +117,18 @@ buffer_append_printf(struct buffer *buffer, const char *format, ...)
|
||||||
int32_t
|
int32_t
|
||||||
buffer_append_vprintf(struct buffer *buffer, const char *format, va_list args)
|
buffer_append_vprintf(struct buffer *buffer, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
|
DPRINTF("Buffer: %d of %d", buffer->used, buffer->size);
|
||||||
int32_t space, result;
|
int32_t space, result;
|
||||||
va_list cp_args;
|
va_list cp_args;
|
||||||
|
|
||||||
va_copy(cp_args, args);
|
va_copy(cp_args, args);
|
||||||
space = buffer->size - buffer->used,
|
space = buffer->size - buffer->used;
|
||||||
result = vsnprintf(&buffer->data[buffer->used], space, format, args);
|
result = vsnprintf(&buffer->data[buffer->used], space, format, args);
|
||||||
|
|
||||||
if (result < space) { /* enough space */
|
if (result < space) { /* enough space */
|
||||||
buffer->used += result;
|
buffer->used += result;
|
||||||
} else {
|
} else {
|
||||||
result = buffer_set_size(buffer, buffer->size + result - space);
|
result = buffer_set_size(buffer, buffer->size + result - space + 1);
|
||||||
if (result != -1)
|
if (result != -1)
|
||||||
result = buffer_append_vprintf(buffer, format, cp_args);
|
result = buffer_append_vprintf(buffer, format, cp_args);
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,7 @@ buffer_append_vprintf(struct buffer *buffer, const char *format, va_list args)
|
||||||
int32_t
|
int32_t
|
||||||
buffer_append(struct buffer *buffer, const char *data, int32_t size)
|
buffer_append(struct buffer *buffer, const char *data, int32_t size)
|
||||||
{
|
{
|
||||||
|
DPRINTF("Buffer: %d of %d", buffer->used, buffer->size);
|
||||||
int32_t used, space;
|
int32_t used, space;
|
||||||
|
|
||||||
used = buffer->used,
|
used = buffer->used,
|
|
@ -6,7 +6,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -47,13 +47,15 @@ aisl_client_parse(AislClient client, char *data, int32_t size)
|
||||||
AislStream s = client->stream;
|
AislStream s = client->stream;
|
||||||
ParserStatus p = HTTP_PARSER_SUCCESS;
|
ParserStatus p = HTTP_PARSER_SUCCESS;
|
||||||
|
|
||||||
int32_t bytes_left = size;
|
int32_t data_size;
|
||||||
|
|
||||||
switch (client->http_version) {
|
switch (client->http_version) {
|
||||||
case AISL_HTTP_0_9:
|
case AISL_HTTP_0_9:
|
||||||
case AISL_HTTP_1_0:
|
case AISL_HTTP_1_0:
|
||||||
case AISL_HTTP_1_1:
|
case AISL_HTTP_1_1:
|
||||||
while (p == HTTP_PARSER_SUCCESS) {
|
while (p == HTTP_PARSER_SUCCESS) {
|
||||||
|
data_size = size;
|
||||||
|
|
||||||
switch (aisl_stream_get_state(s)) {
|
switch (aisl_stream_get_state(s)) {
|
||||||
case AISL_STREAM_STATE_IDLE:
|
case AISL_STREAM_STATE_IDLE:
|
||||||
p = http_10_parse_request(data, &size, client->stream);
|
p = http_10_parse_request(data, &size, client->stream);
|
||||||
|
@ -68,13 +70,13 @@ aisl_client_parse(AislClient client, char *data, int32_t size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* has input data, but request was already parsed */
|
default: /* has input data, but request was already parsed */
|
||||||
|
DPRINTF("misleading request length");
|
||||||
p = HTTP_PARSER_ERROR;
|
p = HTTP_PARSER_ERROR;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// size now has number of parsed bytes
|
// size now has number of parsed bytes
|
||||||
data += size;
|
DPRINTF("%d bytes parsed, %d bytes left", (data_size - size), size);
|
||||||
bytes_left -= size;
|
data += (data_size - size);
|
||||||
size = bytes_left;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -104,8 +106,7 @@ aisl_client_parse(AislClient client, char *data, int32_t size)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size)
|
buffer_shift(&client->in, client->in.used - size); /* reset buffer */
|
||||||
buffer_shift(&client->in, client->in.used - size); /* reset buffer */
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +123,7 @@ aisl_client_input(AislClient client)
|
||||||
char *data = &client->in.data[ client->in.used ];
|
char *data = &client->in.data[ client->in.used ];
|
||||||
int32_t size = client->in.size - client->in.used;
|
int32_t size = client->in.size - client->in.used;
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
if (client->ssl) {
|
if (client->ssl) {
|
||||||
DPRINTF("SSL_read");
|
DPRINTF("SSL_read");
|
||||||
if (!(client->flags & FLAG_HANDSHAKE)) {
|
if (!(client->flags & FLAG_HANDSHAKE)) {
|
||||||
|
@ -155,7 +156,7 @@ aisl_client_input(AislClient client)
|
||||||
return aisl_client_parse(client, data, size);
|
return aisl_client_parse(client, data, size);
|
||||||
} else if (l<0) {
|
} else if (l<0) {
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
if (client->ssl) {
|
if (client->ssl) {
|
||||||
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
|
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
|
||||||
return AISL_IDLE;
|
return AISL_IDLE;
|
||||||
|
@ -215,17 +216,16 @@ aisl_client_output(AislClient client)
|
||||||
if ( !l )
|
if ( !l )
|
||||||
return AISL_IDLE;
|
return AISL_IDLE;
|
||||||
|
|
||||||
#ifdef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
l = send( client->fd, data, l, 0);
|
l = (client->ssl) ? SSL_write(client->ssl, data, l) :
|
||||||
|
send(client->fd, data, l, 0);
|
||||||
#else
|
#else
|
||||||
l = (client->ssl) ?
|
l = send(client->fd, data, l, 0);
|
||||||
SSL_write(client->ssl, data, l) :
|
|
||||||
send( client->fd, data, l, 0);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (l > 0) {
|
if (l > 0) {
|
||||||
aisl_stream_shift(s, l);
|
aisl_stream_shift(s, l);
|
||||||
if ( aisl_stream_is_done(s) ) {
|
if (aisl_stream_is_done(s)) {
|
||||||
/* data has been sent */
|
/* data has been sent */
|
||||||
if (client->flags & FLAG_KEEPALIVE) {
|
if (client->flags & FLAG_KEEPALIVE) {
|
||||||
aisl_stream_free(s);
|
aisl_stream_free(s);
|
||||||
|
@ -234,8 +234,8 @@ aisl_client_output(AislClient client)
|
||||||
if (client->stream != NULL )
|
if (client->stream != NULL )
|
||||||
return AISL_SUCCESS;
|
return AISL_SUCCESS;
|
||||||
|
|
||||||
/* in case of malloc error it will not be error as long as request was
|
/* in case of malloc error it will not be an error as long as the
|
||||||
* handled and we just close the connection.
|
* request was handled and we just close the connection.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ aisl_client_output(AislClient client)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* l < 0 */
|
/* l < 0 */
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
if (client->ssl) {
|
if (client->ssl) {
|
||||||
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE)
|
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE)
|
||||||
return AISL_IDLE;
|
return AISL_IDLE;
|
||||||
|
@ -288,7 +288,7 @@ aisl_client_new(AislServer server, int fd, struct sockaddr_in *addr)
|
||||||
client->stream = stream;
|
client->stream = stream;
|
||||||
DPRINTF("client stream alocated");
|
DPRINTF("client stream alocated");
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
if (server->ssl) {
|
if (server->ssl) {
|
||||||
SSL_CTX * ssl_ctx = aisl_get_ssl_ctx(server->instance, NULL);
|
SSL_CTX * ssl_ctx = aisl_get_ssl_ctx(server->instance, NULL);
|
||||||
|
|
||||||
|
@ -315,7 +315,7 @@ aisl_client_free(AislClient client)
|
||||||
{
|
{
|
||||||
aisl_client_close(client, AISL_SUCCESS);
|
aisl_client_close(client, AISL_SUCCESS);
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
if (client->ssl)
|
if (client->ssl)
|
||||||
SSL_free(client->ssl);
|
SSL_free(client->ssl);
|
||||||
#endif
|
#endif
|
||||||
|
@ -406,10 +406,10 @@ __attribute__ ((visibility ("default") ))
|
||||||
bool
|
bool
|
||||||
aisl_client_is_secure(AislClient client)
|
aisl_client_is_secure(AislClient client)
|
||||||
{
|
{
|
||||||
#ifdef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
return (client->ssl == NULL) ? false : true;
|
return (client->ssl == NULL) ? false : true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#if AISL_WITH_SSL == 1
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <aisl/client.h>
|
#include <aisl/client.h>
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
|
@ -29,7 +33,7 @@ struct aisl_client {
|
||||||
struct buffer out; /**< Client's output buffer. */
|
struct buffer out; /**< Client's output buffer. */
|
||||||
AislServer server; /**< Server instance. */
|
AislServer server; /**< Server instance. */
|
||||||
AislStream stream; /**< Pending client's stream. */
|
AislStream stream; /**< Pending client's stream. */
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
SSL *ssl; /**< SSL pointer for HTTPS. */
|
SSL *ssl; /**< SSL pointer for HTTPS. */
|
||||||
#endif
|
#endif
|
||||||
time_t timestamp; /**< Last communication timestamp. */
|
time_t timestamp; /**< Last communication timestamp. */
|
|
@ -16,7 +16,7 @@
|
||||||
#ifndef AISL_DEBUG_H_703E22F9_4A6E_426F_B708_81BCA019049B
|
#ifndef AISL_DEBUG_H_703E22F9_4A6E_426F_B708_81BCA019049B
|
||||||
#define AISL_DEBUG_H_703E22F9_4A6E_426F_B708_81BCA019049B
|
#define AISL_DEBUG_H_703E22F9_4A6E_426F_B708_81BCA019049B
|
||||||
|
|
||||||
#ifdef DEBUG
|
#if AISL_WITH_DEBUG == 1
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
|
@ -124,12 +124,14 @@ http_10_parse_request(char *data, int32_t *p_size, AislStream stream)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
if (uri && !host)
|
if (uri && !host) {
|
||||||
host = data+3;
|
host = data+3;
|
||||||
else if (host && !port)
|
} else if (host && !port) {
|
||||||
port = data+1;
|
port = data+1;
|
||||||
else if (version)
|
} else if (version) {
|
||||||
|
DPRINTF("bad character in HTTP version (%c)", *data);
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '/':
|
case '/':
|
||||||
|
@ -138,15 +140,18 @@ http_10_parse_request(char *data, int32_t *p_size, AislStream stream)
|
||||||
if (!uri)
|
if (!uri)
|
||||||
uri = path;
|
uri = path;
|
||||||
} else if (version && data-version != 4) {
|
} else if (version && data-version != 4) {
|
||||||
|
DPRINTF("wrong HTTP version length");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
if (!query)
|
if (!query) {
|
||||||
query = data+1;
|
query = data+1;
|
||||||
else if (version)
|
} else if (version) {
|
||||||
|
DPRINTF("bad character in HTTP version (%c)", *data);
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '\n':
|
case '\n':
|
||||||
|
@ -154,54 +159,68 @@ http_10_parse_request(char *data, int32_t *p_size, AislStream stream)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '\r':
|
case '\r':
|
||||||
if (!version)
|
if (!version) {
|
||||||
|
DPRINTF("unexpected end of HTTP request");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (!uri && method_end)
|
if (!uri && method_end) {
|
||||||
uri = data;
|
uri = data;
|
||||||
else if (!version && uri_end)
|
} else if (!version && uri_end) {
|
||||||
version = data;
|
version = data;
|
||||||
else if (version && data-version > 7)
|
} else if (version && data-version > 7) {
|
||||||
|
DPRINTF("bad HTTP version length");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
data++;
|
data++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STEP 2. Verifly splitting was completed */
|
/* STEP 2. Verify splitting was completed */
|
||||||
|
|
||||||
/* Was request sent? */
|
/* Was request sent? */
|
||||||
if (!newline)
|
if (!newline)
|
||||||
return HTTP_PARSER_HUNGRY;
|
return HTTP_PARSER_HUNGRY;
|
||||||
|
|
||||||
/* Check mandatory parts presence */
|
/* Check mandatory parts presence */
|
||||||
if (!method_end || !path || !uri_end || !version)
|
if (!method_end || !path || !uri_end || !version) {
|
||||||
|
DPRINTF("parser error: method=%d, path=%d, uri_end=%d, version=%d",
|
||||||
|
(method_end ? 1 : 0), (path ? 1 : 0), (uri_end ? 1 : 0),
|
||||||
|
(version ? 1: 0));
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
*method_end = 0;
|
*method_end = 0;
|
||||||
*newline = 0;
|
*newline = 0;
|
||||||
*uri_end = 0;
|
*uri_end = 0;
|
||||||
|
|
||||||
http_method = http_method_from_string(method, method_end - method);
|
http_method = http_method_from_string(method, method_end - method);
|
||||||
if (http_method == AISL_HTTP_METHOD_UNKNOWN)
|
if (http_method == AISL_HTTP_METHOD_UNKNOWN) {
|
||||||
|
DPRINTF("invalid HTTP method");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if ((http_version = http_version_from_string(version))==0)
|
if ((http_version = http_version_from_string(version))==0) {
|
||||||
|
DPRINTF("invalid HTTP version");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
*(query-1)=0;
|
*(query - 1) = 0;
|
||||||
} else {
|
} else {
|
||||||
query = uri_end;
|
query = uri_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host) {
|
if (host) {
|
||||||
if (strncmp(uri, "http://", 7) || strncmp(uri, "https://", 8))
|
if (strncmp(uri, "http://", 7) || strncmp(uri, "https://", 8)) {
|
||||||
|
DPRINTF("invalid HTTP uri");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (port)
|
if (port)
|
||||||
*(port-1)=0;
|
*(port - 1) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->client->http_version = http_version;
|
stream->client->http_version = http_version;
|
||||||
|
@ -210,7 +229,7 @@ http_10_parse_request(char *data, int32_t *p_size, AislStream stream)
|
||||||
if (host)
|
if (host)
|
||||||
aisl_stream_set_header(stream, "host", host);
|
aisl_stream_set_header(stream, "host", host);
|
||||||
/* how many characters has been read */
|
/* how many characters has been read */
|
||||||
*(p_size)-=size;
|
*(p_size) = size;
|
||||||
return HTTP_PARSER_SUCCESS;
|
return HTTP_PARSER_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +244,9 @@ http_10_parse_header(char *data, int32_t *p_size, AislStream stream)
|
||||||
*val_end = NULL,
|
*val_end = NULL,
|
||||||
*newline = NULL;
|
*newline = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
DPRINTF("parse header: %p, %d, %02X %02X", data, *p_size, *data & 0xFF, *(data+1) & 0xFF);
|
||||||
|
|
||||||
while(!newline && size-- ) {
|
while(!newline && size-- ) {
|
||||||
switch(*data) {
|
switch(*data) {
|
||||||
case ' ':
|
case ' ':
|
||||||
|
@ -234,8 +256,10 @@ http_10_parse_header(char *data, int32_t *p_size, AislStream stream)
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
if (!colon) {
|
if (!colon) {
|
||||||
if (colon == key)
|
if (colon == key) {
|
||||||
|
DPRINTF("parser error: nameless HTTP header");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
colon = data;
|
colon = data;
|
||||||
}
|
}
|
||||||
|
@ -266,17 +290,21 @@ http_10_parse_header(char *data, int32_t *p_size, AislStream stream)
|
||||||
if (!newline)
|
if (!newline)
|
||||||
return HTTP_PARSER_HUNGRY;
|
return HTTP_PARSER_HUNGRY;
|
||||||
|
|
||||||
|
/* DPRINTF("(%p == %p); *key == 0x%02x", newline, key, *key & 0xFF); */
|
||||||
|
|
||||||
if (colon && val && val_end) {
|
if (colon && val && val_end) {
|
||||||
*colon = 0;
|
*colon = 0;
|
||||||
*val_end = 0;
|
*val_end = 0;
|
||||||
aisl_stream_set_header(stream, key, val);
|
aisl_stream_set_header(stream, key, val);
|
||||||
*p_size -= size;
|
*p_size = size;
|
||||||
return HTTP_PARSER_SUCCESS;
|
return HTTP_PARSER_SUCCESS;
|
||||||
} else if (newline == key || (newline == key+1 && *key == '\r')) {
|
} else if (newline == key || (newline == key+1 && *key == '\r')) {
|
||||||
*p_size -= size;
|
*p_size = size;
|
||||||
|
DPRINTF("end of headers received");
|
||||||
return (aisl_stream_set_end_of_headers(stream) == 0) ?
|
return (aisl_stream_set_end_of_headers(stream) == 0) ?
|
||||||
HTTP_PARSER_SUCCESS : HTTP_PARSER_READY;
|
HTTP_PARSER_READY : HTTP_PARSER_SUCCESS;
|
||||||
}
|
}
|
||||||
|
DPRINTF("parser error: invalid HTTP header");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,10 +317,13 @@ http_10_parse_body(char *data, int32_t *p_size, AislStream stream)
|
||||||
if (!size)
|
if (!size)
|
||||||
return HTTP_PARSER_HUNGRY;
|
return HTTP_PARSER_HUNGRY;
|
||||||
|
|
||||||
|
*p_size = 0;
|
||||||
|
|
||||||
switch (aisl_stream_set_body(stream, data, size)) {
|
switch (aisl_stream_set_body(stream, data, size)) {
|
||||||
case 0:
|
case 0:
|
||||||
return HTTP_PARSER_READY;
|
return HTTP_PARSER_READY;
|
||||||
case -1:
|
case -1:
|
||||||
|
DPRINTF("parser error: invalid HTTP body length");
|
||||||
return HTTP_PARSER_ERROR;
|
return HTTP_PARSER_ERROR;
|
||||||
default:
|
default:
|
||||||
return HTTP_PARSER_SUCCESS;
|
return HTTP_PARSER_SUCCESS;
|
|
@ -15,7 +15,7 @@
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
#include "instance.h"
|
#include "instance.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
|
|
||||||
static uint32_t m_instances = 0;
|
static uint32_t m_instances = 0;
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ aisl_new(const struct aisl_cfg *cfg)
|
||||||
goto release;
|
goto release;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
if ((m_instances++) == 0) {
|
if ((m_instances++) == 0) {
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
OpenSSL_add_ssl_algorithms();
|
OpenSSL_add_ssl_algorithms();
|
||||||
|
@ -140,7 +140,7 @@ aisl_free(AislInstance instance)
|
||||||
|
|
||||||
list_release(&instance->client_spool, (list_destructor_t)aisl_client_free);
|
list_release(&instance->client_spool, (list_destructor_t)aisl_client_free);
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
if (instance->ssl) {
|
if (instance->ssl) {
|
||||||
struct aisl_ssl **ssl = instance->ssl;
|
struct aisl_ssl **ssl = instance->ssl;
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ aisl_free(AislInstance instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
|
|
||||||
SSL_CTX *
|
SSL_CTX *
|
||||||
aisl_get_ssl_ctx(AislInstance instance, const char * host)
|
aisl_get_ssl_ctx(AislInstance instance, const char * host)
|
||||||
|
@ -185,10 +185,10 @@ aisl_get_ssl_ctx(AislInstance instance, const char * host)
|
||||||
void
|
void
|
||||||
aisl_raise_evt(AislInstance instance, const struct aisl_evt *evt)
|
aisl_raise_evt(AislInstance instance, const struct aisl_evt *evt)
|
||||||
{
|
{
|
||||||
#ifdef AISL_WITHOUT_STRINGIFIERS
|
#if AISL_WITH_STRINGIFIERS == 1
|
||||||
DPRINTF("! %d", evt->code);
|
|
||||||
#else
|
|
||||||
DPRINTF("! %s", aisl_event_to_string(evt->code));
|
DPRINTF("! %s", aisl_event_to_string(evt->code));
|
||||||
|
#else
|
||||||
|
DPRINTF("! %d", evt->code);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (instance->callback)
|
if (instance->callback)
|
|
@ -16,7 +16,7 @@
|
||||||
#ifndef AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
#ifndef AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
||||||
#define AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
#define AISL_INSTANCE_H_814CF474_A646_45B7_B6B2_3F4C7BEFA484
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
struct aisl_instance {
|
struct aisl_instance {
|
||||||
AislServer *srv;
|
AislServer *srv;
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
struct aisl_ssl * *ssl;
|
struct aisl_ssl * *ssl;
|
||||||
#endif
|
#endif
|
||||||
struct list client_spool;
|
struct list client_spool;
|
||||||
|
@ -40,7 +40,7 @@ struct aisl_instance {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
/**
|
/**
|
||||||
* @brief Gets SSL context for appropriate server name.
|
* @brief Gets SSL context for appropriate server name.
|
||||||
* @param instance a pointer to #AislInstance instance.
|
* @param instance a pointer to #AislInstance instance.
|
|
@ -157,7 +157,7 @@ aisl_server_get_address(AislServer server, struct sockaddr_in *address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
bool
|
bool
|
|
@ -11,7 +11,7 @@
|
||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
#if AISL_WITH_SSL == 1
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
|
@ -24,14 +24,14 @@ static void
|
||||||
aisl_stream_reset(AislStream stream, bool initial)
|
aisl_stream_reset(AislStream stream, bool initial)
|
||||||
{
|
{
|
||||||
if (!initial) {
|
if (!initial) {
|
||||||
aisl_raise(aisl_stream_get_instance(stream), (void*) stream,
|
aisl_raise(aisl_get_instance(stream), (void*) stream,
|
||||||
AISL_EVENT_STREAM_CLOSE, AISL_SUCCESS);
|
AISL_EVENT_STREAM_CLOSE, AISL_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_release(&stream->buffer);
|
buffer_release(&stream->buffer);
|
||||||
|
|
||||||
stream->u_ptr = NULL;
|
stream->u_ptr = NULL;
|
||||||
stream->content_length = AISL_AUTO_LENGTH;
|
stream->content_length = 0; //AISL_AUTO_LENGTH;
|
||||||
stream->head_offset = 0;
|
stream->head_offset = 0;
|
||||||
stream->flags = 0;
|
stream->flags = 0;
|
||||||
stream->state = AISL_STREAM_STATE_IDLE;
|
stream->state = AISL_STREAM_STATE_IDLE;
|
||||||
|
@ -125,7 +125,7 @@ aisl_stream_set_request(AislStream stream,
|
||||||
on_open.path = path;
|
on_open.path = path;
|
||||||
on_open.query = query;
|
on_open.query = query;
|
||||||
|
|
||||||
aisl_raise_evt(aisl_stream_get_instance(stream), (struct aisl_evt *)&on_open);
|
aisl_raise_evt(aisl_get_instance(stream), (struct aisl_evt *)&on_open);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ aisl_stream_set_header(AislStream stream, const char *key, const char *value)
|
||||||
on_header.key = key;
|
on_header.key = key;
|
||||||
on_header.value = value;
|
on_header.value = value;
|
||||||
|
|
||||||
aisl_raise_evt(aisl_stream_get_instance(stream),
|
aisl_raise_evt(aisl_get_instance(stream),
|
||||||
(struct aisl_evt *) &on_header);
|
(struct aisl_evt *) &on_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,9 +162,12 @@ aisl_stream_set_end_of_headers(AislStream stream)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
DPRINTF("stream->content_length == %"PRIu64"", stream->content_length);
|
||||||
|
|
||||||
if (stream->state == AISL_STREAM_STATE_WAIT_HEADER) {
|
if (stream->state == AISL_STREAM_STATE_WAIT_HEADER) {
|
||||||
stream->state = AISL_STREAM_STATE_WAIT_BODY;
|
result = (stream->content_length != 0);
|
||||||
result = (stream->content_length == 0);
|
stream->state = (result) ? AISL_STREAM_STATE_WAIT_BODY :
|
||||||
|
AISL_STREAM_STATE_READY;
|
||||||
} else {
|
} else {
|
||||||
result = 2;
|
result = 2;
|
||||||
}
|
}
|
||||||
|
@ -241,6 +244,14 @@ aisl_set_context(AislStream s, void *u_ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__ ((visibility ("default") ))
|
||||||
|
bool
|
||||||
|
aisl_is_secure(AislStream stream)
|
||||||
|
{
|
||||||
|
return aisl_client_is_secure(stream->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
AislClient
|
AislClient
|
||||||
aisl_get_client(AislStream s)
|
aisl_get_client(AislStream s)
|
||||||
|
@ -579,7 +590,7 @@ aisl_puts(const char *str, AislStream stream)
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
AislInstance
|
AislInstance
|
||||||
aisl_stream_get_instance(AislStream stream)
|
aisl_get_instance(AislStream stream)
|
||||||
{
|
{
|
||||||
return stream->client->server->instance;
|
return stream->client->server->instance;
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
#include <aisl/types.h>
|
#include <aisl/types.h>
|
||||||
|
|
||||||
|
|
||||||
#ifndef WITHOUT_STRINGIFIERS
|
#if AISL_WITH_STRINGIFIERS == 1
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
__attribute__ ((visibility ("default") ))
|
||||||
const char *
|
const char *
|
63
project.mk
63
project.mk
|
@ -1,63 +0,0 @@
|
||||||
#
|
|
||||||
# config.mk
|
|
||||||
# Löwenware Makefile Config, 2019-03-02 17:35
|
|
||||||
#
|
|
||||||
|
|
||||||
PREFIX ?= /usr/local
|
|
||||||
PKG_CONFIG ?= pkg-config
|
|
||||||
|
|
||||||
PROJECT_NAME = aisl
|
|
||||||
|
|
||||||
# Version
|
|
||||||
|
|
||||||
PROJECT_VERSION_MAJOR = 1
|
|
||||||
PROJECT_VERSION_MINOR = 0
|
|
||||||
PROJECT_VERSION_TWEAK = 0
|
|
||||||
PROJECT_VERSION_LABEL = 0
|
|
||||||
|
|
||||||
#SRC_DIR = src
|
|
||||||
#SDK_DIR = sdk
|
|
||||||
#OUT_DIR = ./build
|
|
||||||
|
|
||||||
|
|
||||||
# Source files
|
|
||||||
|
|
||||||
PROJECT_SOURCES := \
|
|
||||||
$(SRC_DIR)/instance.c \
|
|
||||||
$(SRC_DIR)/server.c \
|
|
||||||
$(SRC_DIR)/client.c \
|
|
||||||
$(SRC_DIR)/stream.c \
|
|
||||||
$(SRC_DIR)/http.c \
|
|
||||||
$(SRC_DIR)/ssl.c \
|
|
||||||
$(SRC_DIR)/list.c \
|
|
||||||
$(SRC_DIR)/str-utils.c \
|
|
||||||
$(SRC_DIR)/buffer.c \
|
|
||||||
$(SRC_DIR)/types.c \
|
|
||||||
|
|
||||||
|
|
||||||
# includes
|
|
||||||
PROJECT_INCLUDES = -I./ \
|
|
||||||
-I./include \
|
|
||||||
`$(PKG_CONFIG) --cflags openssl` \
|
|
||||||
|
|
||||||
# libraries
|
|
||||||
PROJECT_LIBRARIES = \
|
|
||||||
`$(PKG_CONFIG) --libs openssl` \
|
|
||||||
|
|
||||||
|
|
||||||
# compilation macro options:
|
|
||||||
# AISL_WITHOUT_SSL - exclude HTTPS support
|
|
||||||
# AISL_WITHOUT_STRINGIFIERS - exclude several *_to_string functions not
|
|
||||||
|
|
||||||
# flags
|
|
||||||
PROJECT_CFLAGS = -D_POSIX_C_SOURCE=200809L
|
|
||||||
#PROJECT_CFLAGS += -DDEBUG
|
|
||||||
#PROJECT_CFLAGS += -DAISL_WITHOUT_SSL
|
|
||||||
#PROJECT_CFLAGS += -DAISL_WITHOUT_STRINGIFIERS
|
|
||||||
|
|
||||||
|
|
||||||
# PROJECT_LDFLAGS = -L
|
|
||||||
|
|
||||||
|
|
||||||
# vim:ft=make
|
|
||||||
#
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit e00ffe6f708f1460ca1d2b00d94c739ebb2cb184
|
539
src/)
539
src/)
|
@ -1,539 +0,0 @@
|
||||||
#include <time.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
|
||||||
#include <openssl/err.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <aisl/aisl.h>
|
|
||||||
#include "debug.h"
|
|
||||||
#include "stream.h"
|
|
||||||
#include "http.h"
|
|
||||||
#include "server.h"
|
|
||||||
#include "instance.h"
|
|
||||||
#include "client.h"
|
|
||||||
|
|
||||||
#define FLAG_KEEPALIVE (1<<0)
|
|
||||||
#define FLAG_HANDSHAKE (1<<1)
|
|
||||||
#define FLAG_CAN_READ (1<<2)
|
|
||||||
#define FLAG_CAN_WRITE (1<<3)
|
|
||||||
|
|
||||||
#define BUFFER_SIZE (16*1024)
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
aisl_client_close(AislClient client, AislStatus status)
|
|
||||||
{
|
|
||||||
if (client->fd != -1)
|
|
||||||
{
|
|
||||||
aisl_raise(
|
|
||||||
client->server->instance
|
|
||||||
, (void *)client
|
|
||||||
, AISL_EVENT_CLIENT_DISCONNECT
|
|
||||||
, status
|
|
||||||
);
|
|
||||||
|
|
||||||
close(client->fd);
|
|
||||||
shutdown(client->fd, SHUT_RDWR);
|
|
||||||
client->fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static AislStatus
|
|
||||||
aisl_client_parse(AislClient client, char * data, int32_t size)
|
|
||||||
{
|
|
||||||
AislStatus result = AISL_SUCCESS;
|
|
||||||
AislStream s = client->stream;
|
|
||||||
ParserStatus p = HTTP_PARSER_SUCCESS;
|
|
||||||
|
|
||||||
|
|
||||||
int32_t bytes_left = size;
|
|
||||||
|
|
||||||
switch (client->http_version)
|
|
||||||
{
|
|
||||||
case AISL_HTTP_0_9:
|
|
||||||
case AISL_HTTP_1_0:
|
|
||||||
case AISL_HTTP_1_1:
|
|
||||||
|
|
||||||
/* s = client->stream; */
|
|
||||||
|
|
||||||
while ( p == HTTP_PARSER_SUCCESS )
|
|
||||||
{
|
|
||||||
|
|
||||||
switch ( aisl_stream_get_state(s) )
|
|
||||||
{
|
|
||||||
case AISL_STREAM_STATE_IDLE:
|
|
||||||
p = http_10_parse_request(data, &size, client->stream);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AISL_STREAM_STATE_WAIT_HEADER:
|
|
||||||
p = http_10_parse_header(data, &size, client->stream);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AISL_STREAM_STATE_WAIT_BODY:
|
|
||||||
p = http_10_parse_body(data, &size, client->stream);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: /* has input data, but request was already parsed */
|
|
||||||
p = HTTP_PARSER_ERROR;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// size now has number of parsed bytes
|
|
||||||
data += size;
|
|
||||||
bytes_left -= size;
|
|
||||||
size = bytes_left;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AISL_HTTP_2_0:
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(p)
|
|
||||||
{
|
|
||||||
case HTTP_PARSER_READY:
|
|
||||||
client->flags &= ~FLAG_CAN_READ;
|
|
||||||
client->flags |= FLAG_CAN_WRITE;
|
|
||||||
|
|
||||||
aisl_raise(
|
|
||||||
client->server->instance
|
|
||||||
, (void *) s
|
|
||||||
, AISL_EVENT_STREAM_REQUEST
|
|
||||||
, result
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTTP_PARSER_ERROR:
|
|
||||||
/* reply Bad Request here */
|
|
||||||
client->stream->http_response = AISL_HTTP_BAD_REQUEST;
|
|
||||||
|
|
||||||
aisl_raise(
|
|
||||||
client->server->instance
|
|
||||||
, (void *) s
|
|
||||||
, AISL_EVENT_STREAM_ERROR
|
|
||||||
, result
|
|
||||||
);
|
|
||||||
|
|
||||||
aisl_client_close(client, result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size)
|
|
||||||
buffer_shift(&client->in, client->in.used - size); /* reset buffer */
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* In HTTP 2.0 client->stream will be NULL if stream related data was completely
|
|
||||||
* parsed. If it is not NULL, then stream expects additional data -> same like
|
|
||||||
* in mono stream HTTP 1.0
|
|
||||||
*/
|
|
||||||
static AislStatus
|
|
||||||
aisl_client_input(AislClient client)
|
|
||||||
{
|
|
||||||
int l;
|
|
||||||
|
|
||||||
char * data = &client->in.data[ client->in.used ];
|
|
||||||
int32_t size = client->in.size - client->in.used;
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
|
||||||
if (client->ssl)
|
|
||||||
{
|
|
||||||
DPRINTF("SSL_read");
|
|
||||||
if ( !(client->flags & FLAG_HANDSHAKE) )
|
|
||||||
{
|
|
||||||
if ( (l = SSL_accept(client->ssl)) != 1 )
|
|
||||||
{
|
|
||||||
l = SSL_get_error(client->ssl, l);
|
|
||||||
|
|
||||||
if (l == SSL_ERROR_WANT_READ || l == SSL_ERROR_WANT_WRITE)
|
|
||||||
return AISL_IDLE;
|
|
||||||
|
|
||||||
DPRINTF("SSL handshake fail: %s\n", ERR_error_string(l, NULL) );
|
|
||||||
|
|
||||||
aisl_client_close(client, AISL_EXTCALL_ERROR);
|
|
||||||
return AISL_EXTCALL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
client->flags &= ~FLAG_HANDSHAKE;
|
|
||||||
}
|
|
||||||
|
|
||||||
l = SSL_read(client->ssl, data, size) ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
l = recv( client->fd, data, size, 0);
|
|
||||||
|
|
||||||
if (l > 0)
|
|
||||||
{
|
|
||||||
DPRINTF("%d bytes received from client", l);
|
|
||||||
|
|
||||||
data = client->in.data;
|
|
||||||
size = client->in.used + l;
|
|
||||||
|
|
||||||
client->in.used = size;
|
|
||||||
|
|
||||||
return aisl_client_parse(client, data, size);
|
|
||||||
}
|
|
||||||
else if (l<0)
|
|
||||||
{
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
|
||||||
if (client->ssl)
|
|
||||||
{
|
|
||||||
if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ)
|
|
||||||
return AISL_IDLE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if(errno == EWOULDBLOCK)
|
|
||||||
return AISL_IDLE;
|
|
||||||
|
|
||||||
DPRINTF("client - %s", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* both: client disconnect + on read error */
|
|
||||||
/* todo: raise client error here */
|
|
||||||
aisl_client_close(client, AISL_SYSCALL_ERROR);
|
|
||||||
|
|
||||||
return AISL_SYSCALL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static AislStatus
|
|
||||||
aisl_client_output(AislClient client)
|
|
||||||
{
|
|
||||||
int l;
|
|
||||||
char * data;
|
|
||||||
|
|
||||||
AislStream s = client->stream;
|
|
||||||
|
|
||||||
/* while stream is not flushed, we should raise event */
|
|
||||||
if( aisl_get_output_event(s) )
|
|
||||||
{
|
|
||||||
/* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
|
|
||||||
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
|
|
||||||
* buffer->size will be used to carry amount of stored bytes
|
|
||||||
* */
|
|
||||||
l = aisl_stream_get_buffer_space(s);
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (bsz < OUTPUT_BUFFER_SIZE)
|
|
||||||
{
|
|
||||||
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
s->buffer->size = bsz;
|
|
||||||
bsz = OUTPUT_BUFFER_SIZE;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( !(l < aisl_stream_get_buffer_size(s) / 2) )
|
|
||||||
{
|
|
||||||
aisl_raise(
|
|
||||||
client->server->instance
|
|
||||||
, (void*)s
|
|
||||||
, AISL_EVENT_STREAM_OUTPUT
|
|
||||||
, AISL_SUCCESS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data = aisl_stream_get_data(s, &l);
|
|
||||||
|
|
||||||
if ( !l )
|
|
||||||
return AISL_IDLE;
|
|
||||||
|
|
||||||
#ifdef AISL_WITHOUT_SSL
|
|
||||||
l = send( client->fd, data, l, 0);
|
|
||||||
#else
|
|
||||||
l = (client->ssl) ?
|
|
||||||
SSL_write(client->ssl, data, l) :
|
|
||||||
send( client->fd, data, l, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (l > 0)
|
|
||||||
{
|
|
||||||
aisl_stream_shift(s, l);
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (s->state == STREAM_RESPONSE_READY && / * flushed * /
|
|
||||||
s->buffer->size == 0) / * all sent * /
|
|
||||||
*/
|
|
||||||
if ( aisl_stream_is_done(s) )
|
|
||||||
{
|
|
||||||
/* buffer_clear(s->buffer, 0); */
|
|
||||||
|
|
||||||
/* data has been sent */
|
|
||||||
|
|
||||||
if (client->flags & FLAG_KEEPALIVE)
|
|
||||||
{
|
|
||||||
aisl_stream_free(s);
|
|
||||||
|
|
||||||
client->stream = aisl_stream_new(client, client->next_id++);
|
|
||||||
if (client->stream != NULL )
|
|
||||||
return AISL_SUCCESS;
|
|
||||||
|
|
||||||
/* in case of malloc error it will not be error as long as request was
|
|
||||||
* handled and we just close the connection.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
aisl_client_close(client, AISL_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
return AISL_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* l < 0 */
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
|
||||||
if (client->ssl)
|
|
||||||
{
|
|
||||||
if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE )
|
|
||||||
return AISL_IDLE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (errno == EWOULDBLOCK)
|
|
||||||
return AISL_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
aisl_client_close(client, AISL_SYSCALL_ERROR);
|
|
||||||
|
|
||||||
return AISL_SYSCALL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AislClient
|
|
||||||
aisl_client_new( AislServer server,
|
|
||||||
int fd,
|
|
||||||
struct sockaddr_in * addr )
|
|
||||||
{
|
|
||||||
AislClient client;
|
|
||||||
AislStream stream;
|
|
||||||
|
|
||||||
if ( (client = calloc(1, sizeof (struct aisl_client))) != NULL )
|
|
||||||
{
|
|
||||||
DPRINTF("client alocated");
|
|
||||||
memcpy(&client->address, addr, sizeof (struct sockaddr_in));
|
|
||||||
client->server = server;
|
|
||||||
client->fd = fd;
|
|
||||||
client->next_id = 2;
|
|
||||||
client->http_version = AISL_HTTP_1_0;
|
|
||||||
client->timestamp = time(NULL);
|
|
||||||
client->flags = FLAG_KEEPALIVE | FLAG_HANDSHAKE | FLAG_CAN_READ;
|
|
||||||
|
|
||||||
if (buffer_init(&client->in, 2*BUFFER_SIZE) != -1)
|
|
||||||
{
|
|
||||||
DPRINTF("client buffer alocated");
|
|
||||||
memcpy(&client->out, &client->in, sizeof (struct buffer));
|
|
||||||
|
|
||||||
stream = aisl_stream_new(client, 0);
|
|
||||||
|
|
||||||
if (stream != NULL)
|
|
||||||
{
|
|
||||||
client->stream = stream;
|
|
||||||
|
|
||||||
DPRINTF("client stream alocated");
|
|
||||||
|
|
||||||
#ifdef AISL_WITHOUT_SSL
|
|
||||||
|
|
||||||
return client;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
SSL_CTX * ssl_ctx;
|
|
||||||
|
|
||||||
if ( !server->ssl )
|
|
||||||
return client;
|
|
||||||
|
|
||||||
ssl_ctx = aisl_get_ssl_ctx(server->instance, NULL);
|
|
||||||
|
|
||||||
if ((client->ssl = SSL_new(ssl_ctx)) != NULL )
|
|
||||||
{
|
|
||||||
SSL_set_fd(client->ssl, fd);
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
aisl_client_free(client);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
aisl_client_free(AislClient client)
|
|
||||||
{
|
|
||||||
aisl_client_close(client, AISL_SUCCESS);
|
|
||||||
|
|
||||||
#ifndef AISL_WITHOUT_SSL
|
|
||||||
if (client->ssl)
|
|
||||||
SSL_free(client->ssl);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (client->in.data)
|
|
||||||
free(client->in.data);
|
|
||||||
|
|
||||||
/* out buffer is a shared part of input buffer, so no need to free it */
|
|
||||||
|
|
||||||
if (client->stream)
|
|
||||||
aisl_stream_free(client->stream);
|
|
||||||
|
|
||||||
free(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AislStatus
|
|
||||||
AislClientouch(AislClient client, int32_t timeout)
|
|
||||||
{
|
|
||||||
AislStatus result = AISL_IDLE,
|
|
||||||
status = AISL_IDLE;
|
|
||||||
|
|
||||||
/* input */
|
|
||||||
if (client->flags & FLAG_CAN_READ)
|
|
||||||
{
|
|
||||||
if ( (result = aisl_client_input(client)) < 0 )
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* output */
|
|
||||||
if (client->flags & FLAG_CAN_WRITE)
|
|
||||||
{
|
|
||||||
if ( (status = aisl_client_output(client)) < 0 )
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
if ((client->http_version==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
|
|
||||||
(client_input(client)) ) result = true;
|
|
||||||
*/
|
|
||||||
/* output */
|
|
||||||
/*
|
|
||||||
s = list_index(client->streams, client->ostream);
|
|
||||||
|
|
||||||
if ( s->flags & (STREAM_FLAG_OUTPUT_READY | STREAM_FLAG_OUTPUT_CHUNKED) )
|
|
||||||
result = client_output(client);
|
|
||||||
*/
|
|
||||||
/* update timestamp */
|
|
||||||
|
|
||||||
if (result == AISL_IDLE)
|
|
||||||
result = status;
|
|
||||||
|
|
||||||
if (result == AISL_SUCCESS)
|
|
||||||
client->timestamp = time(NULL);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
time_t now;
|
|
||||||
time(&now);
|
|
||||||
|
|
||||||
if ( !(now - client->timestamp < timeout) )
|
|
||||||
{
|
|
||||||
aisl_client_close(client, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
aisl_client_get_socket(AislClient client)
|
|
||||||
{
|
|
||||||
return client->fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
aisl_client_get_keepalive(AislClient client)
|
|
||||||
{
|
|
||||||
return (client->flags & FLAG_KEEPALIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
aisl_client_set_keepalive(AislClient client, bool value)
|
|
||||||
{
|
|
||||||
if (value)
|
|
||||||
client->flags |= FLAG_KEEPALIVE;
|
|
||||||
else
|
|
||||||
client->flags &= ~FLAG_KEEPALIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* API Level ---------------------------------------------------------------- */
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
|
||||||
AislServer
|
|
||||||
aisl_client_get_server(AislClient client)
|
|
||||||
{
|
|
||||||
return client->server;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
|
||||||
bool
|
|
||||||
aisl_client_is_secure(AislClient client)
|
|
||||||
{
|
|
||||||
#ifdef AISL_WITHOUT_SSL
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
return (client->ssl == NULL) ? false : true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
|
||||||
bool
|
|
||||||
aisl_client_is_online(AislClient client)
|
|
||||||
{
|
|
||||||
return (client->fd == -1) ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
|
||||||
void
|
|
||||||
aisl_client_disconnect(AislClient client)
|
|
||||||
{
|
|
||||||
aisl_client_close(client, AISL_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
|
||||||
AislHttpVersion
|
|
||||||
aisl_client_get_http_version(AislClient client)
|
|
||||||
{
|
|
||||||
return client->http_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__ ((visibility ("default") ))
|
|
||||||
void
|
|
||||||
aisl_client_get_address( AislClient client, struct sockaddr_in * address)
|
|
||||||
{
|
|
||||||
memcpy(address, &client->address, sizeof (struct sockaddr_in));
|
|
||||||
}
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
#
|
||||||
|
# Makefile
|
||||||
|
# Ilja Kartašov, 2019-07-13 14:51
|
||||||
|
#
|
||||||
|
|
||||||
|
.POSIX:
|
||||||
|
|
||||||
|
CC ?= gcc
|
||||||
|
PKG_CONFIG ?= pkg-config
|
||||||
|
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
DESTDIR ?=
|
||||||
|
BIN_DIR ?= bin
|
||||||
|
|
||||||
|
TARGET_NAME = aisl
|
||||||
|
OUT_DIR ?= ../build
|
||||||
|
SRC_DIR ?= .
|
||||||
|
SDK_DIR ?= ../sdk
|
||||||
|
CSTUFF_DIR ?= ../cStuff
|
||||||
|
|
||||||
|
# Version
|
||||||
|
|
||||||
|
VERSION_MAJOR = 0
|
||||||
|
VERSION_MINOR = 1
|
||||||
|
VERSION_TWEAK = 0
|
||||||
|
VERSION_LABEL = 0
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
|
||||||
|
SOURCE_FILES := \
|
||||||
|
$(SRC_DIR)/main.c \
|
||||||
|
$(SRC_DIR)/option.c \
|
||||||
|
$(SRC_DIR)/compose.c \
|
||||||
|
\
|
||||||
|
$(SDK_DIR)/components/html.c \
|
||||||
|
\
|
||||||
|
$(CSTUFF_DIR)/list.c \
|
||||||
|
$(CSTUFF_DIR)/string.c \
|
||||||
|
|
||||||
|
# compilation macro options:
|
||||||
|
|
||||||
|
CFLAGS := \
|
||||||
|
-std=c99 \
|
||||||
|
-pedantic \
|
||||||
|
-Wall \
|
||||||
|
-Wmissing-prototypes \
|
||||||
|
-Wstrict-prototypes \
|
||||||
|
-Wold-style-definition \
|
||||||
|
-O2 \
|
||||||
|
-s \
|
||||||
|
\
|
||||||
|
-I../ \
|
||||||
|
-I$(SDK_DIR) \
|
||||||
|
\
|
||||||
|
-D_POSIX_C_SOURCE=200809L \
|
||||||
|
-DEXECUTABLE="$(TARGET_NAME)" \
|
||||||
|
-DVERSION_MAJOR=$(VERSION_MAJOR) \
|
||||||
|
-DVERSION_MINOR=$(VERSION_MINOR) \
|
||||||
|
-DVERSION_TWEAK=$(VERSION_TWEAK) \
|
||||||
|
-DVERSION_LABEL=$(VERSION_LABEL) \
|
||||||
|
\
|
||||||
|
$(CFLAGS) \
|
||||||
|
|
||||||
|
LDFLAGS :=
|
||||||
|
|
||||||
|
# flags
|
||||||
|
|
||||||
|
SOURCE_LIST := $(wildcard $(SOURCE_FILES))
|
||||||
|
OBJECT_LIST := $(addsuffix .o, $(addprefix $(OUT_DIR)/tool/, ${SOURCE_LIST}))
|
||||||
|
|
||||||
|
all: $(TARGET_NAME)
|
||||||
|
|
||||||
|
$(TARGET_NAME): $(OBJECT_LIST)
|
||||||
|
$(info building target: $@)
|
||||||
|
@$(CC) -o $(OUT_DIR)/$@ $(OBJECT_LIST) $(LDFLAGS)
|
||||||
|
$(info done: $@)
|
||||||
|
|
||||||
|
$(OUT_DIR)/tool/%.o: %
|
||||||
|
$(info compiling file: $<)
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
install: $(TARGET_NAME)
|
||||||
|
$(info installing files)
|
||||||
|
@cp $(OUT_DIR)/$< $(DESTDIR)$(PREFIX)/$(BIN_DIR)
|
||||||
|
|
||||||
|
# vim:ft=make
|
||||||
|
#
|
|
@ -0,0 +1,84 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file compose.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <components/html.h>
|
||||||
|
|
||||||
|
#include "option.h"
|
||||||
|
#include "compose.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compose_help(void)
|
||||||
|
{
|
||||||
|
printf("NAME\n");
|
||||||
|
printf("\taisl-compose - Compose plain text resource\n\n");
|
||||||
|
printf("SYNOPSIS\n");
|
||||||
|
printf("\taisl compose [--format=auto|html|js|css] <source> <target>\n\n");
|
||||||
|
printf("DESCRIPTION\n");
|
||||||
|
printf("\tComposes a plain text resource to its production version.");
|
||||||
|
printf("OPTIONS\n");
|
||||||
|
printf("\t--format=auto|html|js|css\n");
|
||||||
|
printf("\t Manually set format for the composer. Usefull when file "
|
||||||
|
"extension does not allow to determine type automatically.\n\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
compose_execute(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
struct cstuff_list list;
|
||||||
|
struct ax_html_options opts = {0};
|
||||||
|
|
||||||
|
if (g_options & OPTION_FLAG_HELP) {
|
||||||
|
return compose_help();
|
||||||
|
}
|
||||||
|
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
if (!(argc == 1 || argc == 2)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_source = argv[0];
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
g_target = argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.offset = "\t";
|
||||||
|
opts.path = g_target ? g_target : ".";
|
||||||
|
opts.name = "html";
|
||||||
|
opts.minimize = true;
|
||||||
|
|
||||||
|
if (!cstuff_list_init(&list, 128)) {
|
||||||
|
if (ax_html_import(&list, g_source) == AISL_SUCCESS) {
|
||||||
|
if (ax_html_export(&list, &opts) == AISL_SUCCESS) {
|
||||||
|
result = 0;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Export failed\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Import failed: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
cstuff_list_release(&list, (CStuffListFree)ax_html_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file compose.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPOSE_H_006245E9_DAFB_4160_AB48_2268FA6E0769
|
||||||
|
#define COMPOSE_H_006245E9_DAFB_4160_AB48_2268FA6E0769
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
compose_execute(int argc, char **argv);
|
||||||
|
|
||||||
|
#endif /* !COMPOSE_H */
|
|
@ -0,0 +1,23 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file globals.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GLOBALS_H_ECAB54AF_855F_408C_9CC1_65B994859848
|
||||||
|
#define GLOBALS_H_ECAB54AF_855F_408C_9CC1_65B994859848
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern uint32_t g_options;
|
||||||
|
|
||||||
|
#endif /* !GLOBALS_H */
|
|
@ -0,0 +1,40 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file main.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "option.h"
|
||||||
|
#include "compose.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = option_read_args(argc, argv)) != -1) {
|
||||||
|
switch (g_options & 0xFF) {
|
||||||
|
case OPTION_COMMAND_COMPOSE:
|
||||||
|
if (!compose_execute(argc - result, &argv[result]))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("For usage guideance run `%s --help`\n", argv[0]);
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file option.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "option.h"
|
||||||
|
|
||||||
|
uint32_t g_options = 0;
|
||||||
|
const char *g_format = NULL;
|
||||||
|
const char *g_source = NULL;
|
||||||
|
const char *g_target = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
option_set_command(int command)
|
||||||
|
{
|
||||||
|
if (!(g_options & 0xFF)) {
|
||||||
|
g_options |= command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
option_read_args(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char c = 0;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
switch (c) {
|
||||||
|
case 'f':
|
||||||
|
g_format = argv[i];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (strcmp(argv[i], "-f") == 0) {
|
||||||
|
c = 'f';
|
||||||
|
} else if (!strncmp(argv[i], "--format=", 9)) {
|
||||||
|
g_format = &argv[i][9];
|
||||||
|
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
|
||||||
|
g_options |= OPTION_FLAG_HELP;
|
||||||
|
} else if (!strcmp(argv[i], "compose")) {
|
||||||
|
option_set_command(OPTION_COMMAND_COMPOSE);
|
||||||
|
} else {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c) {
|
||||||
|
fprintf(stderr, "No value for -%c argument", c);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i - 1;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file option.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPTION_H_FC8ABD38_1EF9_4DD2_A94A_3C4F53E0A437
|
||||||
|
#define OPTION_H_FC8ABD38_1EF9_4DD2_A94A_3C4F53E0A437
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define OPTION_FLAG_HELP (1 << 16)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPTION_COMMAND_UNKNOWN
|
||||||
|
, OPTION_COMMAND_COMPOSE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern uint32_t g_options;
|
||||||
|
extern const char *g_format;
|
||||||
|
extern const char *g_source;
|
||||||
|
extern const char *g_target;
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
option_read_args(int argc, char **argv);
|
||||||
|
|
||||||
|
#endif /* !OPTION_H */
|
Loading…
Reference in New Issue