Update to version 1.0.5

This commit is contained in:
2019-07-13 14:04:06 +02:00
parent 2d67fdd5fb
commit f7a9f255df
77 changed files with 4552 additions and 4264 deletions
-367
View File
@@ -1,367 +0,0 @@
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>
#include <sys/time.h>
#include <aisl/aisl.h>
#include <cStuff/list.h>
#include <cStuff/str-utils.h>
#include "handle.h"
#include "client.h"
#include "server.h"
#include "globals.h"
#include "stream.h"
#include "buffer.h"
/* Globals ------------------------------------------------------------------ */
#define AISL_TERMINATED 1
aisl_handle_t gHandle = NULL;
/* DEPRECATED --------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_init( )
{
gHandle = aisl_handle_new( AISL_MIN_CLIENTS, AISL_BUFFER_SIZE );
return (gHandle != NULL) ? AISL_SUCCESS : AISL_MALLOC_ERROR;
}
/* DEPRECATED --------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_release()
{
aisl_handle_free(gHandle);
}
/* DEPRECATED --------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_select(const char * address, int port)
{
return aisl_bind(gHandle, address, port, 0);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_run( int * flags )
{
aisl_status_t exit_code = AISL_SUCCESS;
struct timeval timeout = {0,0};
while( !(*flags & AISL_TERMINATED) )
{
if ( (exit_code = aisl_run_cycle( gHandle )) == AISL_IDLE )
{
timeout.tv_usec = 300;
timeout.tv_sec = 0;
select(0, NULL, NULL, NULL, &timeout);
}
}
return exit_code;
}
/* Event calls -------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_delay( aisl_callback_t cb, uint32_t usec, void * u_data )
{
return aisl_set_delay(gHandle, cb, usec, u_data);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_listen( void * source, aisl_event_t e_id, aisl_callback_t cb )
{
return aisl_set_callback( gHandle, source, e_id, cb );
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
bool
aisl_raise( void *source, aisl_event_t e_id, ... )
{
bool result;
va_list vl;
va_start(vl, e_id);
result = aisl_raise_event_vl( gHandle, source, e_id, vl);
va_end(vl);
return result;
}
__attribute__ ((visibility ("default") ))
const char *
aisl_header_get(aisl_stream_t stream, const char *key)
{
int i;
if (STREAM(stream)->headers)
{
for (i=0; i< STREAM(stream)->headers->count; i++)
{
if (str_cmpi(((pair_t)list_index(STREAM(stream)->headers,i))->key,key)==0)
return ((pair_t) list_index(STREAM(stream)->headers,i))->value;
}
}
return NULL;
}
/* response functions ------------------------------------------------------- */
static char *
get_response_begin(stream_t stream)
{
char * r;
client_t cli = CLIENT(ASTREAM(stream)->client);
r = str_printf(
"%s %d %s\r\n"
"Server: AISL\r\n"
"Connection: %s\r\n\r\n",
aisl_http_version_to_string(cli->protocol),
stream->response,
aisl_http_response_to_string(stream->response),
((cli->flags & CLIENT_FLAG_KEEPALIVE) ? "keep-alive" : "close")
);
return r;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
const char *content_type,
uint32_t content_length)
{
char * pch;
int l;
/* check if those headers were already sent */
if (STREAM(stream)->state > STREAM_REQUEST_READY) return AISL_IDLE;
STREAM(stream)->response = status_code;
STREAM(stream)->c_type = content_type;
STREAM(stream)->c_length = content_length;
if ( !(pch = get_response_begin(STREAM(stream))) )
return AISL_MALLOC_ERROR;
l = strlen(pch);
STREAM(stream)->c_offset = l-2;
buffer_clear(STREAM(stream)->buffer, content_length);
l = buffer_add( STREAM(stream)->buffer, pch, l );
free(pch);
if (l == BUFFER_EOB) return AISL_MALLOC_ERROR;
if (content_length)
{
if (!aisl_header_printf( stream, "Content-Length", "%u", content_length ))
return AISL_MALLOC_ERROR;
}
if (content_type)
{
if (!aisl_header( stream, "Content-Type", content_type ))
return AISL_MALLOC_ERROR;
}
STREAM(stream)->state = STREAM_RESPONSE_HEADER;
return AISL_SUCCESS;
}
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_flush(aisl_stream_t stream)
{
stream_t s = STREAM(stream);
if ( ! s->c_length )
{
s->c_length = s->buffer->size - s->c_offset - 2;
if (!aisl_header_printf(stream, "Content-Length", "%u", s->c_length))
return AISL_MALLOC_ERROR;
}
/*
fprintf(stdout, "(%lu bytes)------->\n", STREAM(stream)->buffer->size);
fwrite(STREAM(stream)->buffer->data, 1, STREAM(stream)->buffer->size, stdout);
fprintf(stdout, "<------\n");
*/
s->state = STREAM_RESPONSE_READY;
s->flags |= STREAM_FLAG_OUTPUT_READY;
return AISL_SUCCESS;
}
/* header functions --------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_header(aisl_stream_t stream, const char *key, const char *value)
{
int ret;
char * pch;
if ( (pch = str_printf("%s: %s\r\n", key, value)) != NULL )
{
ret = strlen(pch);
if ( buffer_insert(
STREAM(stream)->buffer,
STREAM(stream)->c_offset,
pch,
ret
) == BUFFER_EOB )
{
ret = -1;
}
else
STREAM(stream)->c_offset += ret;
free(pch);
}
else
ret = -1;
return ret;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_header_printf(aisl_stream_t stream, const char *key,
const char *f_value, ...)
{
int ret;
va_list arg;
va_start(arg, f_value);
ret = aisl_header_vprintf(stream, key, f_value, arg);
va_end(arg);
return ret;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_header_vprintf(aisl_stream_t stream, const char *key,
const char *format,
va_list args)
{
int ret;
char * value;
if ( (value = str_vprintf(format, args)) != NULL )
{
ret = aisl_header( stream, key, value );
free(value);
}
else
ret = -1;
return ret;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_printf(aisl_stream_t stream, const char *format, ...)
{
va_list arg;
va_start(arg, format);
int result = aisl_vprintf(stream, format, arg);
va_end(arg);
/* No need to update length there, because vprintf do that
*
* if (STREAM(stream)->c_length_unknown)
STREAM(stream)->c_length += result;
*/
return result;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
{
int result;
char * r;
if ( (r = str_vprintf(format, args)) != NULL)
{
result = strlen(r);
if (buffer_add(STREAM(stream)->buffer, r, result) == BUFFER_EOB)
result = -1;
free(r);
}
else
result = -1;
return result;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_write(aisl_stream_t stream, const char *data, int d_len)
{
if (d_len < 0)
d_len = strlen(data);
if (buffer_add(STREAM(stream)->buffer, data, d_len) == BUFFER_EOB)
d_len = -1;
return d_len;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_puts(const char *str, aisl_stream_t stream)
{
return aisl_write( stream, str, strlen(str));
}
/* -------------------------------------------------------------------------- */
-129
View File
@@ -1,129 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "buffer.h"
/* -------------------------------------------------------------------------- */
buffer_t
buffer_new( size_t initial_size )
{
buffer_t self;
if ( (self = calloc(1, sizeof(struct buffer))) != NULL)
{
if ( (self->size = initial_size) > 0 )
{
if ( !(self->data = calloc( initial_size+1, sizeof(char) )) )
{
free(self);
self = NULL;
}
}
}
return self;
}
/* -------------------------------------------------------------------------- */
void
buffer_free( buffer_t self )
{
if (self->data)
free(self->data);
free(self);
}
/* -------------------------------------------------------------------------- */
size_t
buffer_add( buffer_t self, const char * data, size_t size )
{
size_t result = size+self->size;
char * ptr;
if ( (ptr = realloc(self->data, result+1)) != NULL )
{
memcpy( &ptr[self->size], data, size );
ptr[ result ] = 0;
self->data = ptr;
self->size = result;
}
else
result = BUFFER_EOB;
return result;
}
/* -------------------------------------------------------------------------- */
size_t
buffer_clear( buffer_t self, size_t to_alloc )
{
char * data;
self->size = 0;
if (to_alloc)
{
if ( (data = realloc(self->data, to_alloc)) != NULL )
{
self->data = data;
return to_alloc;
}
}
free(self->data);
self->data = NULL;
return 0;
}
/* -------------------------------------------------------------------------- */
size_t
buffer_shift( buffer_t self, size_t size )
{
size_t result;
if (size && !(size > self->size))
{
result = self->size - size;
memmove(self->data, &self->data[size], result);
self->size = result;
}
else
result = BUFFER_EOB;
return result;
}
/* -------------------------------------------------------------------------- */
size_t
buffer_insert( buffer_t self, size_t offset, const char * data, size_t size )
{
size_t result = size + self->size;
char * ptr;
if ( (ptr = realloc(self->data, result+1)) != NULL )
{
memmove( &ptr[offset+size], &ptr[offset], self->size - offset );
memcpy( &ptr[offset], data, size );
ptr[ result ] = 0;
self->data = ptr;
self->size = result;
}
else
result = BUFFER_EOB;
return result;
}
/* -------------------------------------------------------------------------- */
-49
View File
@@ -1,49 +0,0 @@
#ifndef _AISL_BUFFER_H_
#define _AISL_BUFFER_H_
#include <sys/types.h>
/* -------------------------------------------------------------------------- */
struct buffer
{
char * data;
size_t size;
};
typedef struct buffer * buffer_t;
#define BUFFER_EOB ( ~0 )
/* -------------------------------------------------------------------------- */
buffer_t
buffer_new( size_t initial_size );
/* -------------------------------------------------------------------------- */
void
buffer_free( buffer_t self );
/* -------------------------------------------------------------------------- */
size_t
buffer_insert( buffer_t self, size_t offset, const char * data, size_t size );
/* -------------------------------------------------------------------------- */
size_t
buffer_add( buffer_t self, const char * data, size_t size );
/* -------------------------------------------------------------------------- */
size_t
buffer_clear( buffer_t self, size_t to_alloc );
/* -------------------------------------------------------------------------- */
size_t
buffer_shift( buffer_t self, size_t size );
/* -------------------------------------------------------------------------- */
#endif
-460
View File
@@ -1,460 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <aisl/aisl.h>
#include "client.h"
#include "stream.h"
#include "parser.h"
#include "globals.h"
#include "handle.h"
#ifndef OUTPUT_BUFFER_SIZE
#define OUTPUT_BUFFER_SIZE 4096
#endif
/* -------------------------------------------------------------------------- */
void
client_close(client_t self)
{
close(self->fd);
/* will provide double free
if (self->ssl)
SSL_free(self->ssl);
*/
shutdown(self->fd, SHUT_RDWR);
self->fd=-1;
}
/* -------------------------------------------------------------------------- */
static bool
client_input(client_t self)
{
int l;
parser_status_t p_status = PARSER_PENDING;
char *ptr;
buffer_t buffer = self->server->owner->buffer;
stream_t s = list_index(self->streams, self->istream);
if (self->ssl)
{
if (self->flags & CLIENT_FLAG_HANDSHAKE)
{
if ( (l = SSL_accept(self->ssl)) != 1 )
{
l = SSL_get_error(self->ssl, l);
if (l == SSL_ERROR_WANT_READ || l == SSL_ERROR_WANT_WRITE)
return false;
client_close(self);
fprintf(stderr, "SSL handshake fail: %s\n", ERR_error_string(l, NULL));
return true;
}
self->flags ^= CLIENT_FLAG_HANDSHAKE;
}
l = SSL_read(self->ssl, buffer->data, buffer->size) ;
}
else
l = recv( self->fd, buffer->data, buffer->size, 0);
if (l>0)
{
if( buffer_add(s->buffer, buffer->data, l) == BUFFER_EOB )
{
client_close(self);
return true;
}
ptr = s->buffer->data;
l = s->buffer->size;
/* parse next data chunk */
while ( p_status == PARSER_PENDING )
{
switch(s->state)
{
case STREAM_REQUEST_METHOD:
p_status = parse_request_method(self, &ptr, &l);
break;
case STREAM_REQUEST_PATH:
p_status = parse_request_path(self, &ptr, &l);
break;
case STREAM_REQUEST_PROTOCOL:
p_status = parse_request_protocol(self, &ptr, &l);
break;
case STREAM_REQUEST_HEADER_KEY:
p_status = parse_request_header_key(self, &ptr, &l);
break;
case STREAM_REQUEST_HEADER_VALUE:
p_status = parse_request_header_value(self, &ptr, &l);
break;
case STREAM_REQUEST_CONTENT:
p_status = parse_request_content(self, &ptr, &l);
break;
default:
p_status = PARSER_FINISHED;
/* this is error actually */
}
}
if (p_status == PARSER_FAILED)
{
/* reply Bad Request here */
client_close(self);
}
else if (l)
{
buffer_shift(s->buffer, s->buffer->size-l); /* reset buffer */
}
/*
else
buffer_clear(s->buffer, 0);*/
return true;
}
else if (l<0)
{
if (self->ssl)
{
if (SSL_get_error(self->ssl, l) == SSL_ERROR_WANT_READ)
return false;
}
else
{
if(errno == EWOULDBLOCK)
return false;
}
}
/* both: client disconnect + on read error */
/* todo: raise client error here */
client_close(self);
return true;
}
static bool
client_output(client_t self)
{
if (self->fd < 0)
{
fprintf(stderr, "[aisl] assertion !(client->fd<0) failed\n");
return true;
}
stream_t s;
int l;
s = list_index(self->streams, self->ostream);
/*
if (!s->c_length_unknown && s->buffer && s->buffer->len)
buffer_move(gBuffer, s->buffer);
*/
/* while stream is not flushed, we should raise event */
if(s->flags & STREAM_FLAG_OUTPUT_CHUNKED)
{
/* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
* buffer->size will be used to carry amount of stored bytes
* */
size_t bsz = s->buffer->size;
if (bsz < OUTPUT_BUFFER_SIZE)
{
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
return false;
s->buffer->size = bsz;
bsz = OUTPUT_BUFFER_SIZE;
}
if ( (l = bsz - s->buffer->size) > OUTPUT_BUFFER_SIZE / 2 )
aisl_raise_event( self->server->owner, s, AISL_STREAM_OUTPUT, l);
}
if (s->buffer->size == 0)
return false;
l = (self->ssl) ?
SSL_write(self->ssl, s->buffer->data, s->buffer->size) :
send( self->fd, s->buffer->data, s->buffer->size, 0);
if (l > 0)
{
buffer_shift(s->buffer, l);
if (s->state == STREAM_RESPONSE_READY && /* flushed */
s->buffer->size == 0) /* all sent */
{
buffer_clear(s->buffer, 0);
/* data has been sent */
/*
if (self->protocol == AISL_HTTP_2_0)
{
}
else*/
if (self->flags & CLIENT_FLAG_KEEPALIVE)
{
list_remove(self->streams, s);
stream_free(s);
s = stream_new((struct sockaddr_in *) self, self->next_id++, STREAM_REQUEST_METHOD );
list_append(self->streams, s);
}
else
{
client_close(self);
}
}
return true;
}
/* l < 0 */
if (self->ssl)
{
if ( SSL_get_error(self->ssl, l) == SSL_ERROR_WANT_WRITE )
return false;
}
else
{
if (errno == EWOULDBLOCK)
return false;
}
client_close(self);
return true;
}
bool
client_touch(client_t self)
{
bool result = false;
stream_t s;
/* input */
s = list_index(self->streams, self->istream);
if ((self->protocol==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
(client_input(self)) ) result = true;
/* output */
s = list_index(self->streams, self->ostream);
if ( s->flags & (STREAM_FLAG_OUTPUT_READY | STREAM_FLAG_OUTPUT_CHUNKED) )
result = client_output(self);
/* update timestamp */
if (result)
self->timestamp = time(NULL);
return result;
}
/* constructor -------------------------------------------------------------- */
static client_t
client_new( int fd, struct sockaddr_in * addr )
{
client_t self;
stream_t stream;
if ( !(self = calloc(1, sizeof(struct client))) )
goto finally;
memcpy(&self->address, addr, sizeof(struct sockaddr_in));
self->fd = fd;
self->next_id = 2;
/*
self->istream = 0;
self->ostream = 0;
* UTPUT
*/
self->protocol = AISL_HTTP_1_0;
self->timestamp = time(NULL);
self->flags = CLIENT_FLAG_KEEPALIVE | CLIENT_FLAG_HANDSHAKE;
if ( !(self->streams = list_new(AISL_MIN_STREAMS)) )
goto except;
if ( !(stream = stream_new((struct sockaddr_in *)self, 0, STREAM_REQUEST_METHOD)) )
goto e_stream;
if (list_append(self->streams, stream) == -1)
goto e_append;
goto finally;
e_append:
stream_free(stream);
e_stream:
list_free(self->streams, NULL);
except:
free(self);
self=NULL;
finally:
return self;
}
aisl_status_t
client_accept(client_t * p_self, server_t server)
{
aisl_status_t result;
const char * e_detail = NULL;
int fd;
struct sockaddr_in addr;
socklen_t len = sizeof(struct sockaddr_in);
SSL * ssl = NULL;
SSL_CTX * ssl_ctx;
*p_self = NULL;
if ( (fd = accept(server->fd, (struct sockaddr *) &addr, &len)) < 0 )
{
if (errno != EWOULDBLOCK)
{
result = AISL_SYSCALL_ERROR;
e_detail = strerror(errno);
goto raise;
}
result = AISL_IDLE;
goto finally;
}
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1)
{
result = AISL_SYSCALL_ERROR;
e_detail = strerror(errno);
goto raise;
}
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) != 0)
{
result = AISL_SYSCALL_ERROR;
e_detail = strerror(errno);
goto raise;
}
if (server->flags & AISL_FLAG_SSL)
{
if ( !(ssl_ctx = aisl_get_ssl_ctx( server->owner, NULL )) )
goto except;
if ( !(ssl = SSL_new(ssl_ctx)) )
{
e_detail = "SSL_new";
result = AISL_EXTCALL_ERROR;
goto except;
}
SSL_set_fd(ssl, fd);
}
else
ssl = NULL;
if ( !(*p_self = client_new(fd, &addr)) )
{
result = AISL_MALLOC_ERROR;
e_detail = "client_t";
goto raise;
}
(*p_self)->server = server;
(*p_self)->ssl = ssl;
result = AISL_SUCCESS;
goto finally;
except:
close(fd);
if (ssl)
SSL_free(ssl);
raise:
aisl_raise_event(
server->owner,
server,
AISL_SERVER_ERROR,
server->flags,
e_detail
);
finally:
return result;
}
/* destructor --------------------------------------------------------------- */
void
client_free(client_t self)
{
if (self->fd > -1)
close(self->fd);
if (self->ssl)
SSL_free(self->ssl);
list_free(self->streams, (list_destructor_t)stream_free);
aisl_raise_event(
self->server->owner,
self->server,
AISL_CLIENT_DISCONNECT,
self
);
free(self);
}
/* check if communication time with client is expired ----------------------- */
bool
client_is_timeout(client_t self)
{
bool result = false;
stream_t s;
if (self->protocol == AISL_HTTP_2_0)
{
}
else
{
s = list_index(self->streams, self->istream);
if ( (s->state < STREAM_REQUEST_READY) && /* still waiting for data */
(time(NULL)-self->timestamp > AISL_MAX_CLIENT_SILENCE) ) result=true;
}
if (result)
client_close(self);
return result;
}
/* -------------------------------------------------------------------------- */
-67
View File
@@ -1,67 +0,0 @@
#ifndef _AISL_CLIENT_H_
#define _AISL_CLIENT_H_
#include <time.h>
#include <arpa/inet.h>
#include <aisl/aisl.h>
#include <aisl/http.h>
#include <cStuff/list.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "server.h"
#define CLIENT_FLAG_KEEPALIVE (1<<0)
#define CLIENT_FLAG_HANDSHAKE (1<<1)
struct client
{
struct sockaddr_in address;
server_t server;
int fd;
int next_id; /* server id generator (even, starts from 2) */
int istream; /* input stream id */
int ostream; /* output stream id */
list_t streams;
SSL * ssl;
time_t timestamp;
aisl_http_version_t protocol;
int flags;
};
typedef struct client * client_t;
#define CLIENT(x) ((client_t)x)
/* constructor -------------------------------------------------------------- */
aisl_status_t
client_accept(client_t * self, server_t server);
/* destructor --------------------------------------------------------------- */
void
client_free(client_t self);
/* all regular client routines. return true if something happened ----------- */
bool
client_touch(client_t self);
/* check if communication time with client is expired ----------------------- */
bool
client_is_timeout(client_t self);
/* -------------------------------------------------------------------------- */
void
client_close(client_t self);
/* -------------------------------------------------------------------------- */
#endif
-28
View File
@@ -1,28 +0,0 @@
#include <aisl/event.h>
__attribute__ ((visibility ("default") ))
const char *
aisl_event_get_text( aisl_event_t e_id )
{
switch(e_id)
{
case AISL_SERVER_OPEN: return "AISL_SERVER_OPEN";
case AISL_SERVER_ERROR: return "AISL_SERVER_ERROR";
case AISL_CLIENT_CONNECT: return "AISL_CLIENT_CONNECT";
case AISL_CLIENT_DISCONNECT: return "AISL_CLIENT_DISCONNECT";
case AISL_CLIENT_TIMEOUT: return "AISL_CLIENT_TIMEOUT";
case AISL_STREAM_OPEN: return "AISL_STREAM_OPEN";
case AISL_STREAM_INPUT: return "AISL_STREAM_INPUT";
case AISL_STREAM_REQUEST: return "AISL_STREAM_REQUEST";
case AISL_STREAM_OUTPUT: return "AISL_STREAM_OUTPUT";
case AISL_STREAM_CLOSE: return "AISL_STREAM_CLOSE";
case AISL_STREAM_ERROR: return "AISL_STREAM_ERROR";
default:
break;
}
return "AISL_CUSTOM_EVENT";
}
-48
View File
@@ -1,48 +0,0 @@
#ifndef _AISL_GLOBALS_H_
#define _AISL_GLOBALS_H_
#pragma GCC diagnostic ignored "-Wuninitialized"
#include <aisl/handle.h>
/* MACOS FIX AND OTHER OS */
#ifndef SOCK_NONBLOCK
#define SOCK_NONBLOCK 0
#endif
#ifndef AISL_MIN_SERVERS
#define AISL_MIN_SERVERS 1
#endif
#ifndef AISL_MIN_STREAMS
#define AISL_MIN_STREAMS 1
#endif
#ifndef AISL_MIN_CLIENTS
#define AISL_MIN_CLIENTS 32
#endif
#ifndef AISL_MIN_LISTENERS
#define AISL_MIN_LISTENERS 8
#endif
#ifndef AISL_MIN_DELAYS
#define AISL_MIN_DELAYS 8
#endif
#ifndef AISL_BUFFER_SIZE
#define AISL_BUFFER_SIZE 4096
#endif
#ifndef AISL_MIN_HEADERS
#define AISL_MIN_HEADERS 8
#endif
#ifndef AISL_MAX_CLIENT_SILENCE
#define AISL_MAX_CLIENT_SILENCE 10
#endif
extern aisl_handle_t gHandle;
#endif
-802
View File
@@ -1,802 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <openssl/err.h>
#include <aisl/handle.h>
#include <cStuff/str-utils.h>
#include <cStuff/list.h>
#include "stream.h"
#include "server.h"
#include "client.h"
#include "globals.h"
#include "handle.h"
/* -------------------------------------------------------------------------- */
struct listener
{
void *source;
aisl_callback_t cb;
aisl_event_t e_id;
};
typedef struct listener * listener_t;
/* -------------------------------------------------------------------------- */
struct delay
{
struct timespec next;
uint32_t delay;
void *u_data;
aisl_callback_t cb;
};
typedef struct delay * delay_t;
/* -------------------------------------------------------------------------- */
struct crypter
{
char * keyFile;
char * crtFile;
char * srvName;
SSL_CTX * sslCtx;
};
typedef struct crypter * crypter_t;
/* -------------------------------------------------------------------------- */
static int gHandles = 0;
/* -------------------------------------------------------------------------- */
static listener_t
listener_new( void * source, aisl_event_t e_id, aisl_callback_t cb)
{
listener_t self = malloc(sizeof(struct listener));
if (self)
{
self->source = source;
self->e_id = e_id;
self->cb = cb;
}
return self;
}
/* -------------------------------------------------------------------------- */
void
aisl_remove_listeners_for( aisl_handle_t self, void * source )
{
int i=self->listeners->count-1;
while ( !(i < 0) )
{
listener_t listener = list_index(self->listeners, i);
if ( listener->source == source )
{
free(listener);
list_remove_index(self->listeners, i);
}
i--;
}
}
/* -------------------------------------------------------------------------- */
static void
crypter_free( crypter_t self )
{
if (self->srvName)
free(self->srvName);
if (self->keyFile)
{
free(self->keyFile);
SSL_CTX_free(self->sslCtx);
}
if (self->crtFile)
free(self->crtFile);
free(self);
}
/* -------------------------------------------------------------------------- */
static crypter_t
crypter_new( const char * server_name,
const char * key_file,
const char * crt_file )
{
crypter_t self;
if ( (self=calloc(1, sizeof(struct crypter))) != NULL )
{
if (!(self->srvName = str_copy( server_name ? server_name : "*" )))
goto release;
if ( key_file && !(self->keyFile = str_copy(key_file)))
goto release;
if ( crt_file && !(self->crtFile = str_copy(crt_file)))
goto release;
}
goto finally;
release:
crypter_free(self);
self = NULL;
finally:
return self;
}
/* -------------------------------------------------------------------------- */
static bool
delay_is_expired(delay_t self)
{
if (!self->delay) return true;
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
/*
printf("> %ld.%ld & %ld.%ld\n", self->next.tv_sec, self->next.tv_nsec,
tv.tv_sec, tv.tv_nsec);
*/
if (tv.tv_sec > self->next.tv_sec)
return true;
else if (tv.tv_sec == self->next.tv_sec && tv.tv_nsec >= self->next.tv_nsec)
return true;
return false;
}
/* -------------------------------------------------------------------------- */
static void
delay_reset(delay_t self)
{
clock_gettime(CLOCK_REALTIME, &self->next);
self->next.tv_sec += self->delay / 1000;
self->next.tv_nsec += (self->delay % 1000) * 1000000;
self->next.tv_sec += self->next.tv_nsec / 1000000000;
self->next.tv_nsec = self->next.tv_nsec % 1000000000;
}
/* -------------------------------------------------------------------------- */
static delay_t
delay_new(aisl_callback_t cb, uint32_t delay, void *u_data)
{
delay_t self = malloc(sizeof(struct delay));
if (self)
{
self->cb = cb;
self->u_data = u_data;
self->delay = delay;
delay_reset(self);
}
return self;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_handle_t
aisl_handle_new( size_t min_clients, size_t buffer_size )
{
aisl_handle_t self;
if ((gHandles++) == 0)
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
if ( !(self = calloc(1, sizeof(struct aisl_handle))) )
goto finally;
if ( !(self->servers = list_new(1)) )
goto release;
if ( !(self->clients = list_new(min_clients)) )
goto release;
if ( !(self->listeners = list_new(16)) )
goto release;
if ( !(self->buffer = buffer_new(buffer_size)) )
goto release;
if ( !(self->crypters = list_new(0)) )
goto release;
if ( !(self->delays = list_new(0)) )
goto release;
goto finally;
release:
aisl_handle_free(self);
self = NULL;
finally:
return self;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_handle_t
aisl_handle_from_stream( aisl_stream_t s )
{
return ((client_t)s->client)->server->owner;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_handle_free( aisl_handle_t self )
{
if ((--gHandles) == 0)
{
EVP_cleanup();
}
if (self->clients)
list_free(self->clients, (list_destructor_t) client_free );
if (self->servers)
list_free(self->servers, (list_destructor_t) server_free );
if (self->listeners)
list_free(self->listeners, free);
if (self->delays)
list_free(self->delays, free);
if (self->buffer)
buffer_free(self->buffer);
if (self->crypters)
list_free(self->crypters, (list_destructor_t) crypter_free );
if (self->lastError)
free(self->lastError);
free(self);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_handle_set_error( aisl_handle_t self, const char * err_msg )
{
if (self->lastError)
free(self->lastError);
self->lastError = str_copy(err_msg);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_bind( aisl_handle_t self, const char * address, int port, int flags )
{
server_t server;
if ( !(server = server_new(address, port)) )
goto finally;
server->owner = self;
server->flags |= (flags & AISL_FLAG_SSL);
if ( list_append(self->servers, server) == -1 )
goto release;
goto finally;
release:
server_free(server);
server = NULL;
finally:
return server ? AISL_SUCCESS : AISL_MALLOC_ERROR;
}
/* -------------------------------------------------------------------------- */
static int
get_ssl_context( SSL * ssl, int * ptr, void * handle )
{
const char * server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
SSL_CTX * ctx = aisl_get_ssl_ctx( (aisl_handle_t) handle, server_name );
if (ctx)
{
SSL_set_SSL_CTX(ssl, ctx);
}
return SSL_TLSEXT_ERR_OK;
}
/* -------------------------------------------------------------------------- */
static SSL_CTX *
create_ssl_context( aisl_handle_t self,
const char * key_file,
const char * crt_file )
{
const SSL_METHOD * method;
SSL_CTX * ctx;
method = SSLv23_server_method();
if ( !(ctx = SSL_CTX_new(method)) )
goto except;
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tlsext_servername_callback( ctx, get_ssl_context );
SSL_CTX_set_tlsext_servername_arg( ctx, (void *) self );
if (!(SSL_CTX_use_certificate_file(ctx, crt_file, SSL_FILETYPE_PEM) > 0))
goto release;
if (!(SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) > 0))
goto release;
goto finally;
release:
SSL_CTX_free(ctx);
ctx = NULL;
except:
aisl_handle_set_error( self, ERR_error_string(ERR_get_error(),NULL) );
finally:
return ctx;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_ssl( aisl_handle_t self, const char * server_name,
const char * key_file,
const char * crt_file )
{
SSL_CTX * ssl_ctx = NULL;
int i;
crypter_t crypter;
/* lookup for existing contexts */
for (i=0; i<self->crypters->count; i++)
{
crypter = list_index(self->crypters, i);
if (crypter->keyFile && strcmp(crypter->keyFile, key_file)==0 &&
crypter->crtFile && strcmp(crypter->crtFile, crt_file)==0 )
{
ssl_ctx = crypter->sslCtx;
key_file = NULL;
crt_file = NULL;
break;
}
}
if (! (crypter = crypter_new(server_name, key_file, crt_file)) )
{
return AISL_MALLOC_ERROR;
}
if (! ssl_ctx)
{
if (!(ssl_ctx = create_ssl_context(self, key_file, crt_file)))
{
crypter_free(crypter);
return AISL_EXTCALL_ERROR;
}
}
crypter->sslCtx = ssl_ctx;
if (list_append(self->crypters, crypter)==-1)
{
crypter_free(crypter);
return AISL_MALLOC_ERROR;
}
return AISL_SUCCESS;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
SSL_CTX *
aisl_get_ssl_ctx( aisl_handle_t self, const char * server_name )
{
int i;
crypter_t crypter;
for (i=0; i<self->crypters->count; i++)
{
crypter = list_index(self->crypters, i);
if (server_name)
{
if (strcmp(crypter->srvName, server_name)!=0)
continue;
}
return crypter->sslCtx;
}
return NULL;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_callback( aisl_handle_t self,
void * source,
aisl_event_t e_id,
aisl_callback_t cb )
{
listener_t listener;
if (! (listener = listener_new(source, e_id, cb)) )
return AISL_MALLOC_ERROR;
if (list_append(self->listeners, listener) == -1)
{
free(listener);
return AISL_MALLOC_ERROR;
}
if (e_id == AISL_STREAM_OUTPUT) /* subscribtion for chunked output */
{
if (source)
{
( (stream_t) source )->flags |= STREAM_FLAG_OUTPUT_CHUNKED;
}
}
else if (e_id == AISL_STREAM_OPEN)
{
self->flags |= AISL_HANDLE_HAS_STREAM_LISTENERS;
}
return AISL_SUCCESS;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_set_delay( aisl_handle_t self,
aisl_callback_t cb,
uint32_t usec,
void * u_data )
{
delay_t delay = delay_new(cb, usec, u_data);
if (!delay)
return AISL_MALLOC_ERROR;
if (list_append(self->delays, delay) == -1)
{
free(delay);
return AISL_MALLOC_ERROR;
}
return AISL_SUCCESS;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
bool
aisl_raise_event( aisl_handle_t self,
void * source,
aisl_event_t e_id,
... )
{
va_list vl;
bool result;
va_start(vl, e_id);
result = aisl_raise_event_vl(self, source, e_id, vl);
va_end(vl);
return result;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
bool
aisl_raise_event_vl( aisl_handle_t self,
void * source,
aisl_event_t e_id,
va_list vl )
{
int i,
i_val;
listener_t lst;
bool res = false;
char * c_ptr,
* c_ptr2;
for(i=self->listeners->count-1; i>=0; i--)
{
lst = list_index(self->listeners, i);
/*printf("AISL> raise %s:%s, %p:%p\n", _event_text(e_id), _event_text(lst->e_id), source, lst->source);*/
if (lst->e_id == e_id && (source == lst->source || lst->source == NULL))
{
/*
if (e_id == AISL_STREAM_HEADER)
fprintf(stderr,"FOUND HANDLER %d\n", i);
*/
/*printf(" catch\n");*/
switch(e_id)
{
/* server events */
case AISL_SERVER_OPEN:
i_val = va_arg(vl, aisl_status_t);
res = ((aisl_server_open_t) lst->cb)( source, i_val );
break;
case AISL_SERVER_ERROR:
i_val = va_arg(vl, aisl_status_t);
c_ptr = va_arg(vl, char *);
res = ((aisl_server_error_t) lst->cb)( source, i_val, c_ptr );
break;
/* client events */
case AISL_CLIENT_CONNECT:
res = ((aisl_client_connect_t) lst->cb)(source, va_arg(vl, void *));
break;
case AISL_CLIENT_DISCONNECT:
res = ((aisl_client_disconnect_t) lst->cb)(source, va_arg(vl, void*));
aisl_remove_listeners_for( self, source );
break;
case AISL_CLIENT_TIMEOUT:
res = ((aisl_client_timeout_t) lst->cb)(source, va_arg(vl, void *));
break;
/* request events */
case AISL_STREAM_OPEN:
i_val = va_arg(vl, int);
c_ptr = va_arg(vl, char *);
c_ptr2 = va_arg(vl, char *);
res = ((aisl_stream_open_t) lst->cb)(source, i_val, c_ptr, c_ptr2);
break;
case AISL_STREAM_HEADER:
c_ptr = va_arg(vl, char *);
c_ptr2 = va_arg(vl, char *);
res = ((aisl_stream_header_t) lst->cb)(source, c_ptr, c_ptr2);
break;
case AISL_STREAM_INPUT:
/*printf("AISL> raise AISL_STREAM_INPUT\n");*/
c_ptr = va_arg(vl, char *);
i_val = va_arg(vl, int );
res = ((aisl_stream_input_t) lst->cb)(source, c_ptr, i_val);
break;
case AISL_STREAM_REQUEST:
/*printf("AISL> raise AISL_STREAM_REQUEST\n");*/
buffer_clear( STREAM(source)->buffer, 0);
res = ((aisl_stream_request_t) lst->cb)(source);
break;
case AISL_STREAM_ERROR:
res = ((aisl_stream_error_t) lst->cb)( source, va_arg(vl, char *));
break;
/* response events */
case AISL_STREAM_OUTPUT:
res = ((aisl_stream_output_t)lst->cb)(
source,
va_arg(vl, uint32_t)
);
break;
case AISL_STREAM_CLOSE:
res = ((aisl_stream_close_t)lst->cb)( source );
aisl_remove_listeners_for( self, source );
((aisl_stream_t) source)->u_ptr=NULL;
break;
default:
res = ((aisl_custom_event_t) lst->cb)(source, vl);
}
if (res) break;
}
}
return res;
}
/* -------------------------------------------------------------------------- */
/*
aisl_status_t
aisl_run( int * flags )
{
aisl_status_t exit_code = AISL_SUCCESS;
struct timeval timeout;
while( !(*flags & (1<<0)) )
{
exit_code = aisl_run_cycle( gHandle );
if (exit_code == AISL_IDLE)
{
timeout.tv_usec = 300;
timeout.tv_sec = 0;
select(0, NULL, NULL, NULL, &timeout);
}
}
return exit_code;
}
*/
/* -------------------------------------------------------------------------- */
#define STAGE_SERVER 0
#define STAGE_CLIENT 1
#define STAGE_DELAY 2
__attribute__ ((visibility ("default") ))
aisl_status_t
aisl_run_cycle( aisl_handle_t self )
{
int max = self->servers->count+self->clients->count+self->delays->count,
cnt = 0;
switch (self->stage)
{
case STAGE_SERVER:
while (self->iterator < self->servers->count )
{
server_t srv = (server_t)list_index(self->servers, self->iterator++);
if ( server_touch(srv) != AISL_IDLE )
return AISL_SUCCESS;
if ( ! (++cnt < max) ) return AISL_IDLE;
}
if ( ! (self->flags & AISL_HANDLE_HAS_STREAM_LISTENERS) )
return AISL_IDLE;
self->iterator = 0;
self->stage++;
case STAGE_CLIENT:
while (self->iterator < self->clients->count )
{
int i = self->iterator++;
client_t cli = list_index(self->clients, i);
bool r = client_touch( cli );
if (client_is_timeout( cli ) )
aisl_raise_event( self, cli->server, AISL_CLIENT_TIMEOUT, cli );
if ( cli->fd == -1 )
{
client_free( cli );
list_remove_index(self->clients, i);
}
if (r) return AISL_SUCCESS;
if ( ! (++cnt < max) ) return AISL_IDLE;
}
self->iterator = 0;
self->stage++;
case STAGE_DELAY:
while (self->iterator < self->delays->count )
{
int i = self->iterator++;
delay_t dly = list_index(self->delays, i);
if( delay_is_expired(dly) )
{
if ( ((aisl_delay_timeout_t) dly->cb)(dly->u_data))
{
delay_reset(dly);
}
else
list_remove_index(self->delays, i);
return AISL_SUCCESS;
}
if ( ! (++cnt < max) ) return AISL_IDLE;
}
self->iterator = 0;
self->stage = 0;
}
return AISL_IDLE;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_handle_get_error( aisl_handle_t self )
{
return self->lastError;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
int
aisl_sleep( aisl_handle_t self, unsigned long usec )
{
int maxfd=0;
size_t i;
struct timeval timeout = {0,usec};
fd_set fs;
FD_ZERO (&fs);
for (i=0; i<self->servers->count; i++)
{
server_t s = list_index(self->servers, i);
if (s->fd != -1)
{
FD_SET(s->fd, &fs);
if (s->fd > maxfd) maxfd = s->fd;
}
}
for (i=0; i<self->clients->count; i++)
{
client_t c = list_index(self->clients, i);
if (c->fd != -1)
{
FD_SET(c->fd, &fs);
if (c->fd > maxfd) maxfd = c->fd;
}
}
return select(maxfd+1, &fs, NULL, NULL, &timeout);
}
-61
View File
@@ -1,61 +0,0 @@
#ifndef _AISL_HANDLE_H__
#define _AISL_HANDLE_H__
#include <stdbool.h>
#include <stdarg.h>
#include <aisl/handle.h>
#include <cStuff/list.h>
#include <openssl/ssl.h>
#include "buffer.h"
#define AISL_HANDLE_HAS_STREAM_LISTENERS (1<<8)
/* -------------------------------------------------------------------------- */
struct aisl_handle
{
list_t servers;
list_t clients;
list_t delays; /* deprecated */
list_t listeners;
list_t crypters;
buffer_t buffer;
char * lastError;
int iterator;
int stage;
int flags;
};
/* -------------------------------------------------------------------------- */
aisl_status_t
aisl_set_delay( aisl_handle_t self,
aisl_callback_t cb,
uint32_t usec,
void * u_data );
/* -------------------------------------------------------------------------- */
bool
aisl_raise_event_vl( aisl_handle_t self,
void * source,
aisl_event_t e_id,
va_list vl );
/* -------------------------------------------------------------------------- */
SSL_CTX *
aisl_get_ssl_ctx( aisl_handle_t self, const char * server_name );
/* -------------------------------------------------------------------------- */
void
aisl_remove_listeners_for( aisl_handle_t self, void * source );
/* -------------------------------------------------------------------------- */
#endif
-112
View File
@@ -1,112 +0,0 @@
#include <aisl/http.h>
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_http_version_to_string(aisl_http_version_t version)
{
switch (version)
{
case AISL_HTTP_1_0: return "HTTP/1.0";
case AISL_HTTP_1_1: return "HTTP/1.1";
case AISL_HTTP_2_0: return "HTTP/2.0";
}
return "";
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_http_response_to_string(aisl_http_response_t code)
{
switch (code)
{
/* most common for faster behavior */
case AISL_HTTP_OK: return "OK";
case AISL_HTTP_MOVED_PERMANENTLY: return "Moved Permanently";
/* informational */
case AISL_HTTP_CONTINUE: return "Continue";
case AISL_HTTP_SWITCHING_PROTOCOLS: return "Switching Protocols";
/* Successful */
case AISL_HTTP_CREATED: return "Created";
case AISL_HTTP_ACCEPTED: return "Accepted";
case AISL_HTTP_NON_AUTHORITATIVE_INFORMATION: return "Non-Authoritative Information";
case AISL_HTTP_NO_CONTENT: return "No Content";
case AISL_HTTP_RESET_CONTENT: return "Reset Content";
case AISL_HTTP_PARTIAL_CONTENT: return "Partial Content";
/* redirection */
case AISL_HTTP_MULTIPLE_CHOICES: return "Multiple Choices";
case AISL_HTTP_FOUND: return "Found";
case AISL_HTTP_SEE_OTHER: return "See other";
case AISL_HTTP_NOT_MODIFIED: return "Not Modified";
case AISL_HTTP_USE_PROXY: return "Use Proxy";
case AISL_HTTP_UNUSED: return "(unused)";
case AISL_HTTP_TEMPORARY_REDIRECT: return "Temporary Redirect";
/* client error */
case AISL_HTTP_BAD_REQUEST: return "Bad Request";
case AISL_HTTP_UNAUTHORIZED: return "Unauthorized";
case AISL_HTTP_PAYMENT_REQUIRED: return "Payment Required";
case AISL_HTTP_FORBIDDEN: return "Forbidden";
case AISL_HTTP_NOT_FOUND: return "Not Found";
case AISL_HTTP_METHOD_NOT_ALLOWED: return "Method Not Allowed";
case AISL_HTTP_NOT_ACCEPTABLE: return "Not Acceptable";
case AISL_HTTP_PROXY_AUTHENTICATION_REQUIRED: return "Proxy Authentication Required";
case AISL_HTTP_REQUEST_TIMEOUT: return "Request Timeout";
case AISL_HTTP_CONFLICT: return "Conflict";
case AISL_HTTP_GONE: return "Gone";
case AISL_HTTP_LENGTH_REQUIRED: return "Length Required";
case AISL_HTTP_PRECONDITION_FAILED: return "Precondition Failed";
case AISL_HTTP_REQUEST_ENTITY_TOO_LARGE: return "Request Entity Too Large";
case AISL_HTTP_REQUEST_URI_TOO_LONG: return "Request-URI Too Long";
case AISL_HTTP_UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type";
case AISL_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: return "Requested Range Not Satisfiable";
case AISL_HTTP_EXPECTATION_FAILED: return "Expectation Failed";
/* server error */
case AISL_HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
case AISL_HTTP_NOT_IMPLEMENTED: return "Not Implemented";
case AISL_HTTP_BAD_GATEWAY: return "Bad Gateway";
case AISL_HTTP_SERVICE_UNAVAILABLE: return "Service Unavailable";
case AISL_HTTP_GATEWAY_TIMEOUT: return "Gateway Timeout";
case AISL_HTTP_VERSION_NOT_SUPPORTED: return "HTTP Version Not Supported";
}
return "";
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_http_secure_to_string( int is_secure )
{
return (is_secure ? "HTTPS" : "HTTP");
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_http_method_to_string( aisl_http_method_t method )
{
switch(method)
{
case AISL_HTTP_GET: return "GET";
case AISL_HTTP_PUT: return "PUT";
case AISL_HTTP_POST: return "POST";
case AISL_HTTP_HEAD: return "HEAD";
case AISL_HTTP_TRACE: return "TRACE";
case AISL_HTTP_DELETE: return "DELETE";
case AISL_HTTP_OPTIONS: return "OPTIONS";
case AISL_HTTP_CONNECT: return "CONNECT";
case AISL_HTTP_PRI: return "PRI";
}
return "";
}
/* -------------------------------------------------------------------------- */
-490
View File
@@ -1,490 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <cStuff/str-utils.h>
#include <aisl/http.h>
#include "parser.h"
#include "globals.h"
#include "stream.h"
/* length(multipart/form-data; boundary=) = 30 */
#define B_OFFSET 30
/* common HTTP headers */
static const char cCookie[] = "Cookie";
static const char cContentType[] = "Content-Type";
static const char cContentLength[] = "Content-Length";
/*
static const char cConnection[] = "Connection";
static const char cHost[] = "Host";
static const char cUserAgent[] = "User-Agent";
static const char cAccept[] = "Accept";
static const char cAcceptLanguage[] = "Accept-Language";
static const char cAcceptEncoding[] = "Accept-Encoding";
*/
#define CLI_STREAM(x) ( ((stream_t)list_index(x->streams,x->istream)) )
/*
static void
debug(const char * label, char * buffer, int len)
{
printf("<<< %s [", label);
fwrite(buffer, 1, len, stdout);
printf("]\n");
}
*/
static pair_t
pair_new(const char * key, int length)
{
pair_t p = calloc(1, sizeof(struct pair));
if (p)
{
p->key = str_ncopy(key, length);
if (!p->key)
{
free(p);
p = NULL;
}
}
return p;
}
/* HTTP METHOD -------------------------------------------------------------- */
parser_status_t
parse_request_method(client_t cli, char ** b_ptr, int *b_len)
{
char * cur = memchr(*b_ptr, ' ', *b_len);
if (!cur)
{
if (*b_len < 8)
return PARSER_HUNGRY;
else
return PARSER_FAILED;
}
int l = (int) (cur - *b_ptr);
stream_t s = list_index(cli->streams, cli->istream);
switch( l )
{
case 3:
if (strncmp(*b_ptr, "GET", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_GET;
else if (strncmp(*b_ptr, "PRI", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_PRI;
else if (strncmp(*b_ptr, "PUT", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_PUT;
else
return PARSER_FAILED;
break;
case 4:
if (strncmp(*b_ptr, "POST", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_POST;
else if (strncmp(*b_ptr, "HEAD", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_HEAD;
else
return PARSER_FAILED;
break;
case 5:
if (strncmp(*b_ptr, "TRACE", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_TRACE;
else
return PARSER_FAILED;
break;
case 6:
if (strncmp(*b_ptr, "DELETE", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_DELETE;
else
return PARSER_FAILED;
break;
case 7:
if (strncmp(*b_ptr, "OPTIONS", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_OPTIONS;
else if (strncmp(*b_ptr, "CONNECT", l)==0)
ASTREAM(s)->request_method = AISL_HTTP_CONNECT;
else
return PARSER_FAILED;
break;
default:
return PARSER_FAILED;
}
*b_ptr += ++l;
*b_len -= l; /* count method + space character */
s->state = STREAM_REQUEST_PATH;
return PARSER_PENDING;
}
/* HTTP REQUEST_URI and HOST ------------------------------------------------ */
static void
str_to_lower( char * src )
{
while (*src)
{
*src = tolower(*src);
src++;
}
}
parser_status_t
parse_request_path(client_t cli, char ** b_ptr, int *b_len)
{
parser_status_t result = PARSER_PENDING;
stream_t s = list_index(cli->streams, cli->istream);
int i;
char * host = NULL,
* path = NULL,
* query = NULL;
for ( i=0; i<*b_len; i++)
{
switch( (*b_ptr)[i] )
{
case ':':
if (host) /* if host is set, we parse host and it could not contain : */
{
result = PARSER_FAILED;
break;
}
else /* could be protocol separator */
{
if (i==5)
{
if (*b_len > 7 && strncmp(*b_ptr, "http://", 7)==0 ) /* protocol defined */
{
host = &(*b_ptr)[i+3];
i+=2;
continue;
}
result = PARSER_FAILED; /* something is wrong */
break;
}
}
continue;
case '?':
query = (*b_ptr) +i;
continue;
case ' ':
if (! path) path = *b_ptr;
if (query)
{
ASTREAM(s)->path = str_ncopy(path, (uint32_t) (query-path));
query++;
ASTREAM(s)->query = str_ncopy(query, (uint32_t)(&(*b_ptr)[i]-query));
}
else
ASTREAM(s)->path = str_ncopy(path, (uint32_t) (&(*b_ptr)[i]-path));
*b_len -= ++i;
*b_ptr += i;
s->state = STREAM_REQUEST_PROTOCOL;
return PARSER_PENDING;
break;
case '/':
if (host)
{
/* debug(" > host", host, (int) (&(*b_ptr)[i] - host)); */
pair_t p = malloc(sizeof(struct pair));
if (p)
{
p->key = str_copy("host");
p->value = str_ncopy(host, (uint32_t) (&(*b_ptr)[i] - host));
}
s->headers = list_new(AISL_MIN_HEADERS);
list_append(s->headers, p);
host = NULL;
path = &(*b_ptr)[i];
}
default:
continue;
}
break;
}
if (result == PARSER_PENDING) /* end space was not found */
result = PARSER_HUNGRY;
/*
if (result == PARSER_HUNGRY && *b_len == gBuffer->size)
result = PARSER_FAILED;*/ /* buffer is overloaded */
return result;
}
/* HTTP VERSION ------------------------------------------------------------- */
parser_status_t
parse_request_protocol(client_t cli, char ** b_ptr, int *b_len)
{
stream_t stream = CLI_STREAM(cli);
/* HTTP/X.X = 8 characters minimal */
if (*b_len < 8) return PARSER_HUNGRY;
char * ptr = memchr(*b_ptr, '\n', *b_len);
if (!ptr) return PARSER_HUNGRY;
int l = (int) (ptr - *b_ptr);
if (strncmp(*b_ptr, "HTTP/", 5)==0)
{
if (strncmp(&(*b_ptr)[5], "2.0", 3)==0) cli->protocol = AISL_HTTP_2_0; else
if (strncmp(&(*b_ptr)[5], "1.1", 3)==0) cli->protocol = AISL_HTTP_1_1; else
if (strncmp(&(*b_ptr)[5], "1.0", 3)==0) cli->protocol = AISL_HTTP_1_0; else
return PARSER_FAILED;
if ( (l==10 && *b_ptr[8]=='\r') || (l==9) )
{
/*r->version = str_ncopy(*b_ptr, 8); */
*b_ptr += ++l;
*b_len -=l;
stream->state=STREAM_REQUEST_HEADER_KEY;
aisl_raise_event(
cli->server->owner,
stream,
AISL_STREAM_OPEN,
ASTREAM(stream)->request_method,
ASTREAM(stream)->path,
ASTREAM(stream)->query
);
if (!stream->headers)
stream->headers = list_new(AISL_MIN_HEADERS);
else if (stream->headers->count == 1)
{
/* raise event for Host header */
pair_t p = list_index(stream->headers, 0);
aisl_raise_event(
cli->server->owner,
stream,
AISL_STREAM_HEADER,
p->key, p->value
);
}
return PARSER_PENDING;
}
}
return PARSER_FAILED;
}
/* HTTP HEADER KEY ---------------------------------------------------------- */
parser_status_t
parse_request_header_key(client_t cli, char ** b_ptr, int *b_len)
{
stream_t stream = CLI_STREAM(cli);
int l;
/* check end of headers */
switch (*b_ptr[0])
{
case '\r':
if (*b_len>1)
{
if( strncmp(*b_ptr, "\r\n", 2)==0 )
{
l=2;
}
else
return PARSER_FAILED;
}
else
return PARSER_HUNGRY;
break;
case '\n':
l=1;
break;
default:
l=0;
}
if (l)
{
/* end of headers */
*b_len -= l;
*b_ptr += l;
stream->state = STREAM_REQUEST_CONTENT;
/* aisl_raise_event(cli->server->owner, CLI_STREAM(cli), AISL_STREAM_OPEN);
* */
return PARSER_PENDING;
}
/* header key */
char * ptr = memchr(*b_ptr, ':', *b_len);
if (!ptr)
{
/*
if (*b_len == gBuffer->size)
return PARSER_FAILED;
*/
return PARSER_HUNGRY;
}
l = (int) (ptr-*b_ptr);
pair_t ppp = pair_new(*b_ptr, l);
str_to_lower(ppp->key);
if (ppp)
list_append(stream->headers, ppp);
*b_len -= ++l;
*b_ptr += l;
stream->state=STREAM_REQUEST_HEADER_VALUE;
return PARSER_PENDING;
}
/* HTTP HEADER VALUE -------------------------------------------------------- */
parser_status_t
parse_request_header_value(client_t cli, char ** b_ptr, int *b_len)
{
stream_t stream = CLI_STREAM(cli);
/* skip first space */
if (*b_len)
{
if ((*b_ptr)[0]==' ')
{
(*b_ptr)++;
(*b_len)--;
if (*b_len == 0)
return PARSER_HUNGRY;
}
}
else
return PARSER_HUNGRY;
char * ptr = memchr(*b_ptr, '\n', *b_len);
int l;
l = (ptr) ? (int) (ptr-*b_ptr) : *b_len;
uint32_t index = stream->headers->count -1;
pair_t p = list_index(stream->headers, index);
p->value = str_ncat(p->value, *b_ptr, (l && (*b_ptr)[l-1]=='\r') ? l-1 : l);
*b_len -= ++l;
*b_ptr += l;
stream->state=STREAM_REQUEST_HEADER_KEY;
/* todo: add limit for maximal header length */
if (ptr)
{
if (str_cmpi(p->key, cCookie )==0)
{
/* parse cookies */
}
else if (str_cmpi(p->key, cContentType )==0)
{
/* CLI(r)->c_type_index = index; */
}
else if (str_cmpi(p->key, cContentLength )==0)
{
stream->c_length = strtol(p->value, NULL, 0);
}
/* CLI(r)->c_length = strtol(p->value, NULL, 10); */
aisl_raise_event(
cli->server->owner,
stream,
AISL_STREAM_HEADER,
p->key, p->value
);
return PARSER_PENDING;
}
else
return PARSER_HUNGRY;
}
parser_status_t
parse_request_content(client_t cli, char ** b_ptr, int *b_len)
{
stream_t stream = CLI_STREAM(cli);
/*
fprintf(stdout, "AISL [%d]> ", CLI_STREAM(cli)->c_length);
fwrite(*b_ptr, 1, *b_len, stdout);
fprintf(stdout, "\n<");
*/
if (stream->c_length)
{
int l = *b_len;
aisl_raise_event(
cli->server->owner,
stream,
AISL_STREAM_INPUT,
*b_ptr,
l
);
*b_ptr += l;
*b_len = 0;
stream->c_length -= l;
}
else
goto request_ready;
if ( stream->c_length == 0 )
{
request_ready:
stream->state=STREAM_REQUEST_READY;
aisl_raise_event( cli->server->owner, stream, AISL_STREAM_REQUEST );
return PARSER_FINISHED;
}
else
return PARSER_HUNGRY;
}
-52
View File
@@ -1,52 +0,0 @@
#ifndef _AISL_PARSER_H_
#define _AISL_PARSER_H_
#include <aisl/aisl.h>
#include "client.h"
/* parser status ------------------------------------------------------------ */
typedef enum
{
PARSER_PENDING, /* process pending */
PARSER_FINISHED, /* successful finish */
PARSER_HUNGRY, /* not enough data in buffer */
PARSER_FAILED /* error happened */
} parser_status_t;
/* parse HTTP Request ------------------------------------------------------- */
parser_status_t
parse_request_method(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP Request URI --------------------------------------------------- */
parser_status_t
parse_request_path(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP Version ------------------------------------------------------- */
parser_status_t
parse_request_protocol(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP header key ---------------------------------------------------- */
parser_status_t
parse_request_header_key(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP header value -------------------------------------------------- */
parser_status_t
parse_request_header_value(client_t cli, char ** b_ptr, int *b_len);
/* parse HTTP data ---------------------------------------------------------- */
parser_status_t
parse_request_content(client_t cli, char ** b_ptr, int *b_len);
/* -------------------------------------------------------------------------- */
#endif
-188
View File
@@ -1,188 +0,0 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <cStuff/str-utils.h>
#include "server.h"
#include "handle.h"
#include "client.h"
#include "globals.h"
/* -------------------------------------------------------------------------- */
static bool
_set_addres_from_host_and_port( struct sockaddr_in * sa,
const char * host,
int port )
{
int rs;
struct addrinfo * ai;
memset(sa, 0, sizeof( struct sockaddr_in ));
sa->sin_family = AF_INET;
rs = getaddrinfo(host, NULL, NULL, &ai);
if(rs != 0)
{
return false;
}
sa->sin_addr.s_addr=((struct sockaddr_in*)(ai->ai_addr))->sin_addr.s_addr;
sa->sin_port =htons(port);
freeaddrinfo(ai);
return true;
}
/* -------------------------------------------------------------------------- */
static void
server_close(server_t self)
{
close(self->fd);
self->fd=-1;
}
/* -------------------------------------------------------------------------- */
static aisl_status_t
server_open(server_t self)
{
aisl_status_t result = AISL_SUCCESS;
int s_opt = 1;
if (!_set_addres_from_host_and_port(&self->address, self->host, self->port))
return AISL_EXTCALL_ERROR;
self->fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (self->fd != -1)
{
setsockopt(
self->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&s_opt, sizeof(int)
);
#ifdef __APPLE__
int on = 1;
ioctl(self->fd, FIONBIO, (char *)&on);
fcntl(self->fd, F_SETFL, fcntl(self->fd, F_GETFL) | O_NONBLOCK);
#endif
if (bind( self->fd,
(struct sockaddr *) &self->address,
sizeof(struct sockaddr_in) )==0)
{
if (listen(self->fd, SOMAXCONN) == 0)
return result;
}
server_close(self);
}
result = AISL_SYSCALL_ERROR;
return result;
}
/* -------------------------------------------------------------------------- */
bool
server_touch(server_t self)
{
aisl_status_t result;
client_t cli;
if (self->fd == -1)
{
result = server_open(self);
if (result == AISL_SUCCESS)
aisl_raise_event(
self->owner,
self,
AISL_SERVER_OPEN,
self->flags
);
else
aisl_raise_event(
self->owner,
self,
AISL_SERVER_ERROR,
self->flags,
strerror(errno)
);
return result;
}
result = client_accept(&cli, self);
if (result == AISL_SUCCESS)
{
if (list_append(self->owner->clients, cli) == -1)
{
client_free(cli);
result = AISL_MALLOC_ERROR;
}
else
aisl_raise_event(self->owner, self, AISL_CLIENT_CONNECT, cli);
}
return result;
}
/* -------------------------------------------------------------------------- */
server_t
server_new(const char * address, int port)
{
server_t self;
if ( (self = calloc(1, sizeof(struct server))) != NULL )
{
self->fd = -1;
self->port = port;
if ( !(self->host = str_copy(address)) )
{
free(self);
self = NULL;
}
}
return self;
}
/* -------------------------------------------------------------------------- */
void
server_free(server_t self)
{
if (self)
{
if (self->fd > -1)
server_close(self);
if (self->host)
free(self->host);
free(self);
}
}
/* -------------------------------------------------------------------------- */
-47
View File
@@ -1,47 +0,0 @@
#ifndef _AISL_SERVER_H_
#define _AISL_SERVER_H_
#include <aisl/status.h>
#include <aisl/handle.h>
#include <arpa/inet.h>
#ifdef __APPLE__
#include <fcntl.h>
#include <sys/ioctl.h>
#endif
/* types -------------------------------------------------------------------- */
struct server
{
struct sockaddr_in address;
aisl_handle_t owner;
char * host;
int fd;
int port;
int flags;
};
typedef struct server * server_t;
#define SERVER(x) ((server_t) x)
/* -------------------------------------------------------------------------- */
server_t
server_new(const char * address, int port);
/* -------------------------------------------------------------------------- */
void
server_free(server_t self);
/* -------------------------------------------------------------------------- */
bool
server_touch(server_t self);
/* -------------------------------------------------------------------------- */
#endif
-21
View File
@@ -1,21 +0,0 @@
#include <aisl/status.h>
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
const char *
aisl_status_to_string(aisl_status_t status)
{
switch( status )
{
case AISL_SUCCESS: return "success";
case AISL_IDLE: return "idle";
case AISL_MALLOC_ERROR: return "malloc error";
case AISL_SYSCALL_ERROR: return "system call error";
case AISL_EXTCALL_ERROR: return "external call error";
}
return "";
}
/* -------------------------------------------------------------------------- */
-196
View File
@@ -1,196 +0,0 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <aisl/status.h>
#include "stream.h"
#include "globals.h"
#include "client.h"
#include "handle.h"
static void
pair_free( pair_t self )
{
if (!self) return;
if(self->key) free(self->key);
if(self->value) free(self->value);
free(self);
}
/* -------------------------------------------------------------------------- */
stream_t
stream_new(struct sockaddr_in *client, int id, stream_state_t state)
{
stream_t self = malloc(sizeof(struct stream));
if (self)
{
/* public data */
ASTREAM(self)->client = client;
ASTREAM(self)->host = NULL;
ASTREAM(self)->path = NULL;
ASTREAM(self)->query = NULL;
ASTREAM(self)->scheme = NULL;
ASTREAM(self)->u_ptr = NULL;
ASTREAM(self)->request_method = AISL_HTTP_GET;
/* private data */
self->headers = NULL; /* request headers */
self->buffer = buffer_new(0);
self->c_type = NULL;
self->response = AISL_HTTP_OK;
self->state = STREAM_REQUEST_METHOD;
self->c_length = 0;
self->c_offset = 0; /* headers length */
self->id = id;
self->c_length_unknown = true;
self->flags = 0;
}
return self;
}
/*
stream_t
stream_reset(stream_t self)
{
if (ASTREAM(self)->path)
{
free( (char*) ASTREAM(self)->path);
ASTREAM(self)->path = NULL;
}
if (ASTREAM(self)->query)
{
free( (char*) ASTREAM(self)->query);
ASTREAM(self)->query = NULL;
}
ASTREAM(self)->u_ptr = NULL;
ASTREAM(self)->request_method = AISL_HTTP_GET;
if (self->headers)
{
list_free(self->headers, (list_destructor_t) pair_free);
self->headers = NULL;
}
self->c_type = NULL;
self->response = AISL_HTTP_OK;
self->state = STREAM_REQUEST_METHOD;
self->c_length = 0;
self->c_offset = 0; / * headers length * /
self->c_length_unknown = true;
self->flags = 0;
return self;
}
*/
/* -------------------------------------------------------------------------- */
void
stream_free(stream_t self)
{
if (self->buffer) buffer_free(self->buffer);
if (self->headers) list_free(self->headers, (list_destructor_t) pair_free);
if (ASTREAM(self)->path) free( (char*) ASTREAM(self)->path);
if (ASTREAM(self)->query) free( (char*) ASTREAM(self)->query);
aisl_handle_t hd = ((client_t) ASTREAM(self)->client)->server->owner;
aisl_raise_event(hd, self, AISL_STREAM_CLOSE);
ASTREAM(self)->u_ptr = NULL;
aisl_remove_listeners_for(hd, self);
free(self);
}
/* -------------------------------------------------------------------------- */
int
stream_write(stream_t self, const char * data, uint32_t d_len)
{
return buffer_add( self->buffer, data, d_len);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_cancel(aisl_stream_t s)
{
client_close( (client_t) s->client );
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
bool
aisl_is_secure(aisl_stream_t s)
{
client_t cli = (client_t) s->client;
return (cli->ssl) ? true : false;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void *
aisl_get_context(aisl_stream_t s)
{
return s->u_ptr;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_set_context(aisl_stream_t s, void * u_ptr)
{
s->u_ptr = u_ptr;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_client_t
aisl_get_client(aisl_stream_t s)
{
return s->client;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_server_t
aisl_get_server(aisl_stream_t s)
{
return (aisl_server_t) (((client_t) s->client)->server);
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
aisl_http_version_t
aisl_get_http_version(aisl_stream_t s)
{
client_t cli = (client_t) s->client;
return cli->protocol;
}
/* -------------------------------------------------------------------------- */
__attribute__ ((visibility ("default") ))
void
aisl_reject(aisl_stream_t s)
{
client_t cli = (client_t) s->client;
client_close( cli );
}
/* -------------------------------------------------------------------------- */
-93
View File
@@ -1,93 +0,0 @@
#ifndef _AISL_STREAM_H__
#define _AISL_STREAM_H__
#include <stdbool.h>
#include <aisl/stream.h>
#include <cStuff/list.h>
#include "buffer.h"
/* -------------------------------------------------------------------------- */
#define STREAM_FLAG_OUTPUT_READY (1<<0)
#define STREAM_FLAG_OUTPUT_CHUNKED (1<<1)
/* -------------------------------------------------------------------------- */
struct pair
{
char *key;
char *value;
};
typedef struct pair * pair_t;
/* -------------------------------------------------------------------------- */
typedef enum {
STREAM_REQUEST_METHOD,
STREAM_REQUEST_PATH,
STREAM_REQUEST_PROTOCOL,
STREAM_REQUEST_HEADER_KEY, /* HTTP1 header key */
STREAM_REQUEST_HEADER_VALUE, /* HTTP1 header value */
STREAM_REQUEST_CONTENT, /* HTTP1 data value */
/* states below show stream state
* and do not show what data was sent to client
* */
STREAM_REQUEST_READY,
STREAM_RESPONSE_HEADER,
STREAM_RESPONSE_CONTENT,
STREAM_RESPONSE_READY
} stream_state_t;
/* real wrapper for aisl_stream_t */
struct stream
{
struct aisl_stream _public;
/* private data */
list_t headers; /* request headers */
buffer_t buffer;
const char *c_type;
aisl_http_response_t response;
stream_state_t state;
uint32_t c_length;
uint32_t c_offset;
int id;
int flags;
bool c_length_unknown;
};
typedef struct stream * stream_t;
#define STREAM(x) ((stream_t) x)
#define ASTREAM(x) ((aisl_stream_t) x)
/* -------------------------------------------------------------------------- */
stream_t
stream_new(struct sockaddr_in *client, int id, stream_state_t state);
/* -------------------------------------------------------------------------- */
void
stream_free(stream_t self);
/* -------------------------------------------------------------------------- */
stream_t
stream_reset(stream_t self);
/* -------------------------------------------------------------------------- */
#endif