add h2 implement

This commit is contained in:
lxsang
2020-01-15 18:27:28 +01:00
parent 357b45aee9
commit 353323f93a
15 changed files with 397 additions and 122 deletions

View File

@ -23,6 +23,7 @@ THE SOFTWARE.
*/
#include "dictionary.h"
#include "utils.h"
#include "list.h"
dictionary_t dict()
{
@ -66,8 +67,13 @@ chain_t __put_el_with_key(dictionary_t dic, const char* key)
if(dic->map == NULL) return NULL;
if ((np = dlookup(dic,key)) == NULL) { /* not found */
np = (chain_t) malloc(sizeof(*np));
if (np == NULL || (np->key = strdup(key)) == NULL)
if (np == NULL)
return NULL;
if((np->key = strdup(key)) == NULL)
{
free(np);
return NULL;
}
np->value = NULL;
hashval = hash(key, dic->cap);
np->next = dic->map[hashval];
@ -77,18 +83,43 @@ chain_t __put_el_with_key(dictionary_t dic, const char* key)
// found
return np;
}
chain_t dput(dictionary_t dic,const char* key, void* value)
static void free_ditem_value(void* value, antd_dict_item_type_t type)
{
switch (type)
{
case ANTD_DI_HEAP:
if(value)
free(value);
break;
case ANTD_DI_LIST:
if(value)
list_free((list_t*)&value);
break;
case ANTD_DI_DIC:
if(value)
freedict(value);
default:
break;
}
}
chain_t insert(dictionary_t dic,const char* key, void* value, antd_dict_item_type_t type)
{
chain_t np = __put_el_with_key(dic,key);
if(np == NULL)
{
if(value) free(value);
free_ditem_value(value, type);
return NULL;
}
if(np->value && value) free(np->value);
if(np->value && value) free_ditem_value(np->value, np->type);
np->type = type;
np->value = value;
return np;
}
chain_t dremove(dictionary_t dic, const char* key)
{
if(dic->map == NULL) return 0;
@ -131,7 +162,7 @@ void free_association(chain_t * asoc)
if(a->key)
{
free(a->key);
if(a->value) free(a->value);
if(a->value) free_ditem_value(a->value, a->type);
}
free(a);
}

View File

@ -25,18 +25,24 @@ THE SOFTWARE.
#define DICTIONARY_H
#define DHASHSIZE 16
#define dput(d,k,v) (insert(d,k,v,ANTD_DI_HEAP))
#define dput_static(d,k,v) (insert(d,k,v,ANTD_DI_STATIC))
#define dput_list(d,k,v) (insert(d,k,v,ANTD_DI_LIST))
#define dput_dict(d,k,v) (insert(d,k,v,ANTD_DI_DIC))
#define for_each_assoc(assoc, dic) \
for(unsigned int i = 0; i < dic->cap; i++) \
for(assoc = dic->map[i];assoc!= NULL; assoc = assoc->next)
typedef enum{ANTD_DI_STATIC, ANTD_DI_HEAP, ANTD_DI_LIST, ANTD_DI_DIC} antd_dict_item_type_t;
/**
* Dictionary for header
*/
typedef struct __assoc{
struct __assoc *next;
char *key;
antd_dict_item_type_t type;
void* value;
//char *value;
} * chain_t;
typedef chain_t* map_t;
@ -51,7 +57,7 @@ dictionary_t dict();
dictionary_t dict_n(unsigned int n);
chain_t dlookup(dictionary_t,const char*);
void* dvalue(dictionary_t, const char*);
chain_t dput(dictionary_t,const char*, void*);
chain_t insert(dictionary_t,const char*, void*, antd_dict_item_type_t type);
chain_t dremove(dictionary_t, const char*);
void freedict(dictionary_t);

101
lib/h2.c Normal file
View File

@ -0,0 +1,101 @@
#include "h2.h"
#include "scheduler.h"
void* antd_h2_preface_ck(void* data)
{
char buf[25];
antd_request_t* rq = (antd_request_t*) data;
int count = antd_recv(rq->client,buf,24);
if(count != 24)
{
// TODO servers MUST treat an invalid connection preface as a
// connection error (Section 5.4.1) of type PROTOCOL_ERROR
ERROR("Unable to read preface for client %d: [%s]",rq->client->sock,buf);
return antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
}
buf[24] = '\0';
if(strcmp(buf, H2_CONN_PREFACE) != 0)
{
ERROR("Connection preface is not correct for client %d: [%s]",rq->client->sock,buf);
// TODO servers MUST treat an invalid connection preface as a
// connection error (Section 5.4.1) of type PROTOCOL_ERROR
return antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
}
return antd_create_task(antd_h2_handle, (void *)rq, NULL, rq->client->last_io);
}
void* antd_h2_handle(void* data)
{
antd_request_t* rq = (antd_request_t*) data;
antd_task_t* task;
if(rq->client->flags & CLIENT_FL_READABLE)
{
task = antd_create_task(antd_h2_read,(void *)rq, NULL, rq->client->last_io);
task->priority++;
schedule_task(task);
}
if(rq->client->flags & CLIENT_FL_WRITABLE)
{
task = antd_create_task(antd_h2_write,(void *)rq, NULL, rq->client->last_io);
task->priority++;
schedule_task(task);
}
task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
task->priority++;
return task;
}
static int antd_h2_read_frame(antd_client_t* cl, antd_h2_frame_t* frame)
{
uint8_t tmp;
frame->length = 0;
frame->type = 0;
frame->flags = 0;
frame->identifier= 0;
if( antd_recv(cl,& frame->length,24) != 24) return 0;
printf("length is %d\n", frame->length);
// TODO:
// Values greater than 2^14 (16,384) MUST NOT be
// sent unless the receiver has set a larger value for
// SETTINGS_MAX_FRAME_SIZE.
if( antd_recv(cl,& frame->type,8) != 8) return 0;
printf("type is %d\n", frame->type);
if( antd_recv(cl,& frame->flags,8) != 8) return 0;
if( antd_recv(cl,& tmp,1) != 1) return 0;
// identifier
if( antd_recv(cl,& frame->identifier,31) != 31) return 0;
frame->data = (uint8_t*) malloc(frame->length);
if(!frame->data) return 0;
if( antd_recv(cl,frame->data, frame->length) != frame->length)
{
free(frame->data);
return 0;
}
return 1;
}
void* antd_h2_read(void* data)
{
antd_h2_frame_t frame;
antd_request_t* rq = (antd_request_t*) data;
antd_task_t* task;
if(!antd_h2_read_frame(rq->client, &frame))
{
// TODO: frame error
printf("error reading frame\n");
ERROR("Unable to read frame from client %d",rq->client->sock);
task = antd_create_task(NULL, (void *)rq, NULL, time(NULL));
task->priority++;
return task;
}
// verify frame
printf("Frame type: %d\n", frame.type & 0xff);
return antd_create_task(NULL, data, NULL, time(NULL));
}
void* antd_h2_write(void* data)
{
printf("write task\n");
return antd_create_task(NULL, data, NULL, time(NULL));
}

57
lib/h2.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef HTTP2_H
#define HTTP2_H
#include "handle.h"
#include "hpack.h"
#define H2_CONN_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
#define H2_FRM_DATA 0x0
#define H2_FRM_HEADER 0x1
#define H2_FRM_PRIORITY 0x2
#define H2_FRM_RST_STREAM 0x3
#define H2_FRM_SETTINGS 0x4
#define H2_FRM_PUSH_PROMISE 0x5
#define H2_FRM_PING 0x6
#define H2_FRM_GOAWAY 0x7
#define H2_FRM_WINDOW_UPDATE 0x8
#define H2_FRM_CONTINUATION 0x9
/**
* Struct that holds a
* h2 connection
*/
typedef struct {
} antd_h2_conn_t;
/**
* Struct that holds a
* h2 stream
*/
typedef struct {
} antd_h2_stream_t;
/**
* a H2 frame
*/
typedef struct {
// 24 bits length
unsigned int length;
// 8 bits type
uint8_t type;
// 8 bits flags
uint8_t flags;
// 31 bits identifier
unsigned int identifier;
uint8_t* data;
} antd_h2_frame_t;
void* antd_h2_read(void* rq);
void* antd_h2_write(void* rq);
void* antd_h2_preface_ck(void* rq);
void* antd_h2_handle(void* rq);
#endif

View File

@ -1,4 +1,5 @@
#include "handle.h"
#include "handle.h"
#define HTML_TPL "<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><h2>%s</h2></BODY></HTML>"
static const char* S_100 = "Continue";
@ -82,6 +83,11 @@ int compressable(char* ctype)
return 0;
}
void schedule_task(antd_task_t* task)
{
UNUSED(task);
}
void htdocs(antd_request_t* rq, char* dest)
{
dictionary_t xheader = (dictionary_t)dvalue(rq->request, "REQUEST_HEADER");
@ -210,7 +216,7 @@ void antd_send_header(void* cl, antd_response_header_t* res)
}
else
{
client->status = Z_NO_FLUSH;
//client->status = Z_NO_FLUSH;
dput(res->header,"Content-Encoding", strdup("gzip"));
}
}
@ -224,7 +230,7 @@ void antd_send_header(void* cl, antd_response_header_t* res)
}
else
{
client->status = Z_NO_FLUSH;
//client->status = Z_NO_FLUSH;
dput(res->header,"Content-Encoding", strdup("deflate"));
}
}
@ -282,6 +288,7 @@ int antd_send(void *src, const void* data_in, int len_in)
antd_client_t * source = (antd_client_t *) src;
#ifdef USE_ZLIB
int status = (source->flags & CLIENT_FL_COMPRESSION_END)?Z_NO_FLUSH:Z_FINISH;
if(source->zstream && source->z_level != ANTD_CNONE)
{
antd_compress_t current_zlevel = source->z_level;
@ -296,7 +303,7 @@ int antd_send(void *src, const void* data_in, int len_in)
{
zstream->avail_out = BUFFLEN;
zstream->next_out = buf;
if(deflate(zstream, source->status) == Z_STREAM_ERROR)
if(deflate(zstream,status) == Z_STREAM_ERROR)
{
source->z_level = current_zlevel;
data = NULL;
@ -643,9 +650,9 @@ int antd_close(void* src)
//TODO: send finish data to the socket before quit
if(source->zstream)
{
if(source->status == Z_NO_FLUSH && source->z_level != ANTD_CNONE)
if(!(source->flags & CLIENT_FL_COMPRESSION_END) && source->z_level != ANTD_CNONE)
{
source->status = Z_FINISH;
source->flags |= CLIENT_FL_COMPRESSION_END;
antd_send(source, "", 0);
}
deflateEnd(source->zstream);

View File

@ -21,6 +21,7 @@
#include "dictionary.h"
#include "list.h"
#include "ini.h"
#include "scheduler.h"
#define SERVER_NAME "Antd"
#define IS_POST(method) (strcmp(method,"POST")== 0)
@ -37,7 +38,12 @@
typedef enum {ANTD_CGZ, ANTD_CDEFL, ANTD_CNONE} antd_compress_t;
//extern config_t server_config;
// define the client flag
#define CLIENT_FL_ACCEPTED 0x01
#define CLIENT_FL_COMPRESSION_END 0x02
#define CLIENT_FL_HTTP_1_1 0x04
#define CLIENT_FL_READABLE 0x08
#define CLIENT_FL_WRITABLE 0x10
typedef struct {
unsigned int port;
@ -50,9 +56,9 @@ typedef struct {
typedef struct{
int sock;
void* ssl;
int status;
uint8_t flags;
time_t last_io;
// compress
// compress option
antd_compress_t z_level;
void* zstream;
} antd_client_t;
@ -72,7 +78,7 @@ typedef struct
typedef struct {
typedef struct {
//int port;
char *plugins_dir;
char *plugins_ext;
@ -108,14 +114,15 @@ typedef struct {
int raw_body;
} plugin_header_t;
int __attribute__((weak)) require_plugin(const char*);
// some functions that allows access to server
// private data
int __attribute__((weak)) require_plugin(const char*);
void __attribute__((weak)) htdocs(antd_request_t* rq, char* dest);
void __attribute__((weak)) dbdir(char* dest);
void __attribute__((weak)) tmpdir(char* dest);
void __attribute__((weak)) plugindir(char* dest);
int __attribute__((weak)) compressable(char* ctype);
int __attribute__((weak)) compressable(char* ctype);
void __attribute__((weak)) schedule_task(antd_task_t* task);
void set_nonblock(int socket);
//void set_block(int socket);

1
lib/hpack.c Normal file
View File

@ -0,0 +1 @@
#include "hpack.h"

6
lib/hpack.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef HPACK_H
#define HPACK_H
// HPACK header compression implementation
#endif

View File

@ -155,8 +155,9 @@ void antd_scheduler_init(antd_scheduler_t* scheduler, int n)
scheduler->status = 1;
scheduler->workers_queue = NULL;
scheduler->pending_task = 0 ;
scheduler->validate_data = 0;
scheduler->validate_data = NULL;
scheduler->destroy_data = NULL;
scheduler->task_ready = NULL;
// init semaphore
scheduler->scheduler_sem = sem_open("scheduler", O_CREAT, 0600, 0);
if (scheduler->scheduler_sem == SEM_FAILED)
@ -323,7 +324,7 @@ int antd_task_schedule(antd_scheduler_t* scheduler)
}
// has the task now
// validate the task
if(scheduler->validate_data && difftime( time(NULL), it->task->access_time) > MAX_VALIDITY_INTERVAL)
if(scheduler->validate_data && ! scheduler->validate_data(it->task))
{
// data task is not valid
LOG("Task data is not valid, task will be killed");
@ -336,6 +337,16 @@ int antd_task_schedule(antd_scheduler_t* scheduler)
return 0;
}
// check if the task is ready
if(scheduler->task_ready && !scheduler->task_ready(it->task))
{
// task is not ready, put it back to the queue
antd_add_task(scheduler, it->task);
free(it);
return 0;
}
// task is ready for execute, now figure out how it will be executed
// check the type of task
if(it->task->type == LIGHT || scheduler->n_workers <= 0)
{
@ -355,7 +366,7 @@ int antd_task_schedule(antd_scheduler_t* scheduler)
}
return 1;
}
void antd_wait(antd_scheduler_t* scheduler)
void antd_scheduler_wait(antd_scheduler_t* scheduler)
{
int stat;
while(scheduler->status)

View File

@ -9,7 +9,7 @@
#define NORMAL_PRIORITY ((int)((N_PRIORITY - 1) / 2))
#define LOW_PRIORITY (N_PRIORITY - 1)
#define HIGH_PRIORITY 0
#define MAX_VALIDITY_INTERVAL 20 // 10 s for task validity
typedef enum
{
LIGHT,
@ -92,7 +92,8 @@ typedef struct
default to NULL
*/
void* (*destroy_data)(void*);
int validate_data;
int (*validate_data)(antd_task_t*);
int (*task_ready)(antd_task_t*);
} antd_scheduler_t;
/*
@ -133,7 +134,7 @@ int antd_task_schedule(antd_scheduler_t *);
/*
wait for event
*/
void antd_wait(antd_scheduler_t *);
void antd_scheduler_wait(antd_scheduler_t *);
antd_callback_t* callback_of( void* (*callback)(void*) );
#endif

View File

@ -403,7 +403,7 @@ int ws_client_connect(ws_client_t* wsclient, port_config_t pcnf)
}
// will be free
wsclient->antdsock->sock = sock;
wsclient->antdsock->status = 0;
wsclient->antdsock->flags = 0;
wsclient->antdsock->last_io = time(NULL);
wsclient->antdsock->zstream = NULL;
#ifdef USE_OPENSSL