diff --git a/httpd.c b/httpd.c index 823b10d..795041f 100644 --- a/httpd.c +++ b/httpd.c @@ -140,11 +140,6 @@ void configure_context(SSL_CTX *ctx) #endif -void schedule_task(antd_task_t* task) -{ - antd_add_task(&scheduler, task); -} - void stop_serve(int dummy) { UNUSED(dummy); diff --git a/lib/h2.c b/lib/h2.c index e84f22a..ed1d49d 100644 --- a/lib/h2.c +++ b/lib/h2.c @@ -1,9 +1,57 @@ #include "h2.h" #include "scheduler.h" +static int antd_h2_read_frame_header(antd_client_t* cl, antd_h2_frame_header_t* frame) +{ + frame->length = 0; + frame->type = 0; + frame->flags = 0; + frame->identifier= 0; + uint8_t header[9]; + if( antd_recv(cl,& header,sizeof(header)) != sizeof(header)) return 0; + // network byte order is big endian + // read frame length + frame->length = (*header << 16) + (*(header + 1)<< 8) + *(header+2); + // frame type + frame->type = *(header + 3); + // frame flags + frame->flags = *(header + 4); + // frame identifier + frame->identifier = ((*(header + 5) & 0x7F) << 24) + (*(header + 6)<< 16) + (*(header + 7)<< 8) + *(header + 8); + + return 1; +} + + +static int process_frame(void* source, antd_h2_frame_header_t* frame_h) +{ + // verify frame + printf("Frame type: %d\n", frame_h->type & 0xff); + printf("Frame flag: %d\n",frame_h->flags); + printf("frame identifier: %d\n", frame_h->identifier); + uint8_t* frame_data = (uint8_t*)malloc(frame_h->length); + if(!frame_data) + { + return 0; + } + antd_request_t* rq = (antd_request_t*) source; + if(antd_recv(rq->client,frame_data,frame_h->length) != frame_h->length) + { + // TODO error + // go away + ERROR("Cannot read all frame data"); + free(frame_data); + return H2_NO_ERROR; + } + + free(frame_data); + return H2_NO_ERROR; +} + void* antd_h2_preface_ck(void* data) { char buf[25]; + antd_h2_frame_header_t frame_h; antd_request_t* rq = (antd_request_t*) data; int count = antd_recv(rq->client,buf,24); if(count != 24) @@ -11,7 +59,7 @@ void* antd_h2_preface_ck(void* data) // 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); + return antd_empty_task((void *)rq,rq->client->last_io); } buf[24] = '\0'; if(strcmp(buf, H2_CONN_PREFACE) != 0) @@ -19,8 +67,19 @@ void* antd_h2_preface_ck(void* data) 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_empty_task((void *)rq, rq->client->last_io); } + // read the setting frame + if(!antd_h2_read_frame_header(rq->client, &frame_h) || frame_h.type != H2_FRM_SETTINGS) + { + // TODO: frame error + // + // send go away with PROTOCOL_ERROR + printf("error reading setting frame\n"); + ERROR("Unable to read setting frame from client %d",rq->client->sock); + return antd_empty_task((void *)rq, rq->client->last_io); + } + process_frame(rq, &frame_h); return antd_create_task(antd_h2_handle, (void *)rq, NULL, rq->client->last_io); } @@ -30,15 +89,11 @@ void* antd_h2_handle(void* 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); + antd_h2_read(data); } 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); + antd_h2_write(data); } task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io); @@ -46,56 +101,26 @@ void* antd_h2_handle(void* data) 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_h2_frame_header_t frame_h; antd_request_t* rq = (antd_request_t*) data; - antd_task_t* task; - if(!antd_h2_read_frame(rq->client, &frame)) + if(!antd_h2_read_frame_header(rq->client, &frame_h)) { // TODO: frame error - printf("error reading frame\n"); + // send goaway frame 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; + return antd_empty_task(data, rq->client->last_io); } - // verify frame - printf("Frame type: %d\n", frame.type & 0xff); - return antd_create_task(NULL, data, NULL, time(NULL)); + process_frame(data, &frame_h); + return antd_empty_task(data, rq->client->last_io); } void* antd_h2_write(void* data) { + antd_request_t* rq = (antd_request_t*) data; printf("write task\n"); - return antd_create_task(NULL, data, NULL, time(NULL)); + return antd_empty_task(data, rq->client->last_io); } \ No newline at end of file diff --git a/lib/h2.h b/lib/h2.h index f169897..0a9edf7 100644 --- a/lib/h2.h +++ b/lib/h2.h @@ -16,6 +16,81 @@ #define H2_FRM_WINDOW_UPDATE 0x8 #define H2_FRM_CONTINUATION 0x9 +// ERROR code +/* +The associated condition is not a result of an +error. For example, a GOAWAY might include this code to indicate +graceful shutdown of a connection. +*/ +#define H2_NO_ERROR 0x0 +/* +The endpoint detected an unspecific protocol +error. This error is for use when a more specific error code is +not available. +*/ +#define H2_PROTOCOL_ERROR 0x1 +/* +The endpoint encountered an unexpected +internal error. +*/ +#define H2_INTERNAL_ERROR 0x2 +/* +The endpoint detected that its peer +violated the flow-control protocol. +*/ +#define H2_FLOW_CONTROL_ERROR 0x3 +/* +The endpoint sent a SETTINGS frame but did +not receive a response in a timely manner. See Section 6.5.3 +("Settings Synchronization"). +*/ +#define H2_SETTINGS_TIMEOUT 0x4 +/* +The endpoint received a frame after a stream +was half-closed. +*/ +#define H2_STREAM_CLOSED 0x5 +/* +The endpoint received a frame with an invalid size. +*/ +#define H2_FRAME_SIZE_ERROR 0x6 +/* +The endpoint refused the stream prior to +performing any application processing (see Section 8.1.4 for +details). +*/ +#define H2_REFUSED_STREAM 0x7 +/* +Used by the endpoint to indicate that the stream is no +longer needed. +*/ +#define H2_CANCEL 0x8 +/* +The endpoint is unable to maintain the +header compression context for the connection. +*/ +#define H2_COMPRESSION_ERROR 0x9 +/* +The connection established in response to a CONNECT request (Section 8.3) was reset or abnormally closed. +*/ +#define H2_CONNECT_ERROR 0xa +/* +The endpoint detected that its peer is +exhibiting a behavior that might be generating excessive load. +*/ +#define H2_ENHANCE_YOUR_CALM 0xb +/* +The underlying transport has properties +that do not meet minimum security requirements (see Section 9.2). +*/ +#define H2_INADEQUATE_SECURITY 0xc +/* +The endpoint requires that HTTP/1.1 be used +instead of HTTP/2. +*/ +#define H2_HTTP_1_1_REQUIRED 0xd + + /** * Struct that holds a * h2 connection @@ -33,7 +108,7 @@ typedef struct { } antd_h2_stream_t; /** - * a H2 frame + * a H2 frame header */ typedef struct { // 24 bits length @@ -44,8 +119,9 @@ typedef struct { uint8_t flags; // 31 bits identifier unsigned int identifier; - uint8_t* data; -} antd_h2_frame_t; +} antd_h2_frame_header_t; + + void* antd_h2_read(void* rq); void* antd_h2_write(void* rq); diff --git a/lib/handle.c b/lib/handle.c index 048e454..6ceb10e 100644 --- a/lib/handle.c +++ b/lib/handle.c @@ -83,11 +83,6 @@ 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"); diff --git a/lib/handle.h b/lib/handle.h index 91d1bda..bd7a995 100644 --- a/lib/handle.h +++ b/lib/handle.h @@ -119,7 +119,6 @@ void __attribute__((weak)) dbdir(char* dest); void __attribute__((weak)) tmpdir(char* dest); void __attribute__((weak)) plugindir(char* dest); 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); diff --git a/lib/scheduler.c b/lib/scheduler.c index e685a59..9fdcd31 100644 --- a/lib/scheduler.c +++ b/lib/scheduler.c @@ -379,3 +379,10 @@ void antd_scheduler_wait(antd_scheduler_t* scheduler) } } } + +antd_task_t* antd_empty_task(void* data,time_t t) +{ + antd_task_t* task = antd_create_task(NULL,data,NULL,t); + task->priority++; + return task; +} \ No newline at end of file diff --git a/lib/scheduler.h b/lib/scheduler.h index baa4ea0..781df38 100644 --- a/lib/scheduler.h +++ b/lib/scheduler.h @@ -115,6 +115,8 @@ void antd_scheduler_destroy(antd_scheduler_t *); */ antd_task_t *antd_create_task(void *(*handle)(void *), void *data, void *(*callback)(void *), time_t); +antd_task_t* antd_empty_task(void* data, time_t); + /* add a task */