From: Urban Wallasch Date: Sat, 26 Oct 2019 00:59:31 +0000 (+0200) Subject: * Support HTTP connection keep-alive. X-Git-Tag: v0.1.0~6 X-Git-Url: https://git.packet-gain.de/?a=commitdiff_plain;h=5ea57f78e7b252572faeb7b07169bb88bf1166b1;p=ets2_tele.git * Support HTTP connection keep-alive. * Fixed some minor issues. --- diff --git a/telehttpd.c b/telehttpd.c index 845d91a..95363c4 100644 --- a/telehttpd.c +++ b/telehttpd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "net.h" #include "log.h" @@ -24,7 +25,6 @@ struct thread_data_t { int sock; - struct telemetry_state_t tele; }; struct { @@ -122,7 +122,7 @@ static size_t copy_field_val( char *buf, size_t bufsz, const char *needle, const static inline ssize_t sockwrite( int fd, const void *buf, size_t len ) { ssize_t n; - n = write_tm( fd, buf, len, 1000 ); + n = write_tm( fd, buf, len, 50 ); if ( 0 > n ) { EPRINT( "write_tm: %s\n", strerror(errno) ); } @@ -132,9 +132,9 @@ static inline ssize_t sockwrite( int fd, const void *buf, size_t len ) { return n; } -static void respond( struct thread_data_t *td, const char *req ) { - int n; - char buf[4096]; // Must be large enough to satisfy tele2json()! +static int respond( int sock, const char *req ) { + int n, ret = -1; + char hdr[512]; char origin[256]; char host[256]; enum respond_code { @@ -153,45 +153,62 @@ static void respond( struct thread_data_t *td, const char *req ) { copy_field_val( host, sizeof host, "Host: ", req, cfg.host ); switch (code) { - case r_json: + case r_json: { + struct telemetry_state_t tele; + char jbuf[4096]; // Must be large enough to satisfy tele2json()! + size_t jsz; + if ( 0 != tele_cpy( &tele, telemetry ) ) { + DPRINT( "No telemetry, serving dummy data\n" ); + } + jsz = tele2json( jbuf, sizeof jbuf, &tele ); + if ( 0 == jsz ) + goto SEND_500; copy_field_val( origin, sizeof origin, "Origin: ", req, cfg.origin ); - n = snprintf( buf, sizeof buf, + n = snprintf( hdr, sizeof hdr, "HTTP/1.1 200 OK\r\n" "Host: %s\r\n" "Access-Control-Allow-Origin: %s\r\n" "Content-type: text/json\r\n" - "Connection: close\r\n" + "Connection: keep-alive\r\n" + "Content-Length: %lu\r\n" "\r\n", host, - origin + origin, + (unsigned long)jsz ); - if ( 0 < n && (size_t)n < sizeof buf && n == sockwrite( td->sock, buf, n ) ) - sockwrite( td->sock, buf, tele2json( buf, sizeof buf, &td->tele ) ); + if ( 0 < n && (size_t)n < sizeof hdr && n == sockwrite( sock, hdr, n ) ) + ret = sockwrite( sock, jbuf, jsz ); break; + } case r_index: { int fi; + struct stat st; fi = open( cfg.idxfile, O_RDONLY ); - if ( 0 <= fi ){ - n = snprintf( buf, sizeof buf, - "HTTP/1.1 200 OK\r\n" - "Host: %s\r\n" - "Content-type: text/html\r\n" - "Connection: close\r\n" - "\r\n", - host - ); - if ( 0 < n && (size_t)n < sizeof buf && n == sockwrite( td->sock, buf, n ) ) { - sendfile_tm( td->sock, fi, -1, 5000 ); - } + if ( 0 > fi ) + goto SEND_404; + if ( 0 > fstat(fi, &st) ) { close( fi ); - } - else goto SEND_404; + } + n = snprintf( hdr, sizeof hdr, + "HTTP/1.1 200 OK\r\n" + "Host: %s\r\n" + "Content-type: text/html\r\n" + "Connection: keep-alive\r\n" + "Content-Length: %ld\r\n" + "\r\n", + host, + (long)st.st_size + ); + if ( 0 < n && (size_t)n < sizeof hdr && n == sockwrite( sock, hdr, n ) ) { + ret = sendfile_tm( sock, fi, st.st_size, 1000 ); + } + close( fi ); break; } case r_none: SEND_404: - n = snprintf( buf, sizeof buf, + n = snprintf( hdr, sizeof hdr, "HTTP/1.1 404 Not Found\r\n" "Host: %s\r\n" "Content-type: text/plain\r\n" @@ -200,11 +217,12 @@ static void respond( struct thread_data_t *td, const char *req ) { "404 Not Found", host ); - if ( 0 < n && (size_t)n < sizeof buf ) - sockwrite( td->sock, buf, n ); + if ( 0 < n && (size_t)n < sizeof hdr ) + sockwrite( sock, hdr, n ); break; default: - n = snprintf( buf, sizeof buf, + SEND_500: + n = snprintf( hdr, sizeof hdr, "HTTP/1.1 500 Internal Server Error\r\n" "Host: %s\r\n" "Content-type: text/plain\r\n" @@ -213,10 +231,11 @@ static void respond( struct thread_data_t *td, const char *req ) { "500 Internal Server Error", host ); - if ( 0 < n && (size_t)n < sizeof buf ) - sockwrite( td->sock, buf, n ); + if ( 0 < n && (size_t)n < sizeof hdr ) + sockwrite( sock, hdr, n ); break; } + return ret; } static int rcv_request(int sock, char *buf, size_t size, int timeout) { @@ -230,7 +249,8 @@ static int rcv_request(int sock, char *buf, size_t size, int timeout) { if ( 0 > bread ) { if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) continue; - EPRINT( "read: %s\n", strerror(errno) ); + if ( errno != ETIME ) + EPRINT( "read: %s\n", strerror(errno) ); break; } else if ( 0 == bread ) { @@ -238,27 +258,28 @@ static int rcv_request(int sock, char *buf, size_t size, int timeout) { break; } total += bread; - buf[total] = 0; - if ( strstr( buf, "\r\n\r\n" ) ) { - res = 0; - break; - } - timeout = 200; + timeout = 5; } + buf[total] = 0; + if ( strstr( buf, "\r\n\r\n" ) ) + res = 0; return res; } static void *handle_conn( void *p ) { struct thread_data_t *td = p; - char buf[2048]; + char req[2048]; + DPRINT("-- new thread --\n"); DPRINT( "sock: %d\n", td->sock ); - if ( 0 == rcv_request(td->sock, buf, sizeof buf, 1000) ) { - DPRINT( "request:\n%s", buf); - respond( td, buf ); + while ( 0 == rcv_request(td->sock, req, sizeof req, 5000) ) { + DPRINT( "request:\n%s", req); + if ( 0 > respond( td->sock, req ) ) + break; } net_close( td->sock ); free( td ); + DPRINT("-- thread terminated --\n"); return NULL; } @@ -286,9 +307,6 @@ static int serve_http(void) { if ( NULL != (td = malloc( sizeof *td )) ) { int e; td->sock = as; - if ( 0 != tele_cpy( &td->tele, telemetry ) ) { - DPRINT( "No telemetry, serving dummy data\n" ); - } pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); if ( 0 != ( e = pthread_create( &tid, &attr, handle_conn, td ) ) ) {