#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
+#include <sys/stat.h>
#include "net.h"
#include "log.h"
struct thread_data_t {
int sock;
- struct telemetry_state_t tele;
};
struct {
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) );
}
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 {
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"
"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"
"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) {
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 ) {
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;
}
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 ) ) ) {