Add basic aisl tool implementation
This commit is contained in:
parent
ce7eda1820
commit
043d414df4
65
library.mk
65
library.mk
|
@ -1,65 +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 = 5
|
|
||||||
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_WITH_DEBUG ?= 0 # disable debug output
|
|
||||||
AISL_WITH_SSL ?= 1 # enable SSL support
|
|
||||||
AISL_WITH_STRINGIFIERS ?= 1 # enable *_to_string functions
|
|
||||||
|
|
||||||
|
|
||||||
# flags
|
|
||||||
PROJECT_CFLAGS = -D_POSIX_C_SOURCE=200809L
|
|
||||||
PROJECT_CFLAGS += -DAISL_WITH_DEBUG=$(AISL_WITH_DEBUG)
|
|
||||||
PROJECT_CFLAGS += -DAISL_WITH_SSL=$(AISL_WITH_SSL)
|
|
||||||
PROJECT_CFLAGS += -DAISL_WITH_STRINGIFIERS=$(AISL_WITH_STRINGIFIERS)
|
|
||||||
|
|
||||||
# PROJECT_LDFLAGS = -L
|
|
||||||
|
|
||||||
|
|
||||||
# vim:ft=make
|
|
||||||
#
|
|
539
library/)
539
library/)
|
@ -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));
|
|
||||||
}
|
|
2
sdk
2
sdk
|
@ -1 +1 @@
|
||||||
Subproject commit b9e247b88f43dfeae69ac1371a78787950d859ed
|
Subproject commit e00ffe6f708f1460ca1d2b00d94c739ebb2cb184
|
|
@ -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