* Improved Makefile logic.
*.o
*.so
-shmget
+telehttpd
-.PHONY: all clean
-all: shmget telemetry.so
+SELF := $(lastword $(MAKEFILE_LIST))
SDK_HEADERS=\
- sdk/include/*.h \
- sdk/include/common/*.h \
- sdk/include/amtrucks/*.h \
- sdk/include/eurotrucks2/*.h
+ sdk/include/*.h \
+ sdk/include/common/*.h \
+ sdk/include/amtrucks/*.h \
+ sdk/include/eurotrucks2/*.h
SDK_INCLUDES=\
- -Isdk/include \
- -Isdk/include/common/ \
- -Isdk/include/amtrucks/ \
- -Isdk/include/eurotrucks2
+ -Isdk/include \
+ -Isdk/include/common/ \
+ -Isdk/include/amtrucks/ \
+ -Isdk/include/eurotrucks2
-CFLAGS=-Wall -std=gnu99 -DDEBUG -I.
+CFLAGS=-Wall -Wextra -std=gnu99 -DDEBUG -I.
UNAME:= $(shell uname -s)
ifeq ($(UNAME),Darwin)
-LIB_NAME_OPTION=-install_name
+ LIB_NAME_OPTION=-install_name
else
-LIB_NAME_OPTION=-soname
+ LIB_NAME_OPTION=-soname
endif
+.PHONY: all clean
+
+all: telehttpd telemetry.so
+
telemetry.so: telemetry.cpp $(SDK_HEADERS)
g++ -o $@ -fPIC -Wall --shared -Wl,$(LIB_NAME_OPTION),$@ $(SDK_INCLUDES) telemetry.cpp
-shmget: shmget.o net.o fserv.o ntime.o
- $(CC) $(LDFLAGS) -o $@ -pthread $^
+telehttpd: telehttpd.o shmget.o net.o fserv.o ntime.o
+ $(CC) $(LDFLAGS) -o $@ -pthread $^
+
+%.o: %.c $(SELF)
+ $(CC) -c $(CFLAGS) -o $*.o $*.c
clean:
- @rm -f -- *.so *.o shmget
+ @rm -f -- *.so *.o telehttpd
+#include <stdio.h>
+#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
-#include <stdio.h>
-
#include <errno.h>
-#include <poll.h>
-
-#include <pthread.h>
#include <unistd.h>
-#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
-#include "fserv.h"
-#include "net.h"
+#include "shmget.h"
#include "log.h"
-#include "telemetry.h"
struct telemetry_state_t *telemetry;
-static volatile int force_quit;
-
-static void handle_signal(int sig) {
- fprintf (stderr, "SIGNAL: %d\n", sig);
- switch (sig){
- case SIGTERM:
- case SIGINT:
- force_quit = 1;
- break;
- }
-}
-
-enum respond_code {
- r_index,
- r_json,
- r_none
-};
-
-static void respond(int fd, const char *req, int code) {
- char buf[4096];
- char origin[256] = "http://localhost";
- char host[256] = "localhost";
- const char *s;
- switch (code) {
- case r_json:
- case r_index:
- s = strstr(req, "Origin:");
- if (s){
- s += 8; //strlen("Origin: ");
- const char *e = strstr(s, "\r\n");
- strncpy(origin, s, e-s);
- }
- s = strstr(req, "Host:");
- if (s){
- s += 6;//strlen("Host: ");
- const char *e = strstr(s, "\r\n");
- strncpy(host, s, e-s);
- }
-
- write(fd, buf, sprintf (buf, "HTTP/1.1 200 OK\r\n"));
- write(fd, buf, sprintf (buf, "Host: %s\r\n", host));
- if (r_json == code){
- write(fd, buf, sprintf (buf, "Access-Control-Allow-Origin: %s\r\n", origin));
- write(fd, buf, sprintf (buf, "Content-type: text/json\r\n"));
- write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
- write(fd, buf, sprintf (buf, "{ \"fc_avg\": %3.2f, \"speed\": %3.2f, \"cc\": %3.2f }",
- 100.0 * telemetry->fc_avg , telemetry -> speed * 3.6, telemetry -> cc * 3.6));
- } else {
- struct file_info_t fi;
- if (0 == fserv_open_server("index.html", &fi)){
- write(fd, buf, sprintf (buf, "Content-type: text/html\r\n"));
- write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
- fserv_sendfile(fd, &fi);
- fserv_close(&fi);
- } else {
- write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
- write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
- write(fd, buf, sprintf (buf, "Tough luck"));
- }
- }
- break;
- case r_none:
- write(fd, buf, sprintf (buf, "HTTP/1.1 404 Not Found\r\n"));
- write(fd, buf, sprintf (buf, "Host: localhost\r\n"));
- write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
- write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
- write(fd, buf, sprintf (buf, "Fuck you 404!"));
- break;
- default:
- write(fd, buf, sprintf (buf, "HTTP/1.1 500 Internal Server Error\r\n"));
- write(fd, buf, sprintf (buf, "Host: localhost\r\n"));
- write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
- write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
- write(fd, buf, sprintf (buf, "Fuck you 500!"));
- break;
- }
-}
-
-static int receive(int fd, int timeout) {
- struct pollfd pe;
- int res;
- pe.fd = fd;
- char buf[2048];
- int bread, total;
-
- total = 0;
- *buf = 0;
- do {
- pe.events = POLLIN;
- pe.revents = 0;
- res = poll(&pe, 1, timeout);
- if ( 0 < res && pe.revents == POLLIN ) {
- errno = 0;
- bread = read(fd, buf + total, sizeof buf - total);
- if ( 0 > bread ) {
- switch (errno) {
- case EAGAIN:
- //case EWOULDBLOCK:
- case EINTR:
- break;
- default:
- res = -1;
- break;
- }
- }
- else if ( 0 == bread && 0 == errno ) {
- res = -1;
- }
- else {
- total += bread;
- buf[total] = 0;
- if ( strstr(buf, "\r\n\r\n" ) ) {
- fprintf (stderr, "%s", buf);
- if (0 == strncmp(buf, "GET /json HTTP", 10))
- respond(fd, buf, r_json);
- else if (0 == strncmp(buf, "GET / HTTP", 10))
- respond(fd, buf, r_index);
- else
- respond(fd, NULL, r_none);
- *buf = 0;
- res = 0;
- }
- }
- }
- timeout = 200;
- } while ( 1 == res && pe.revents == POLLIN && !force_quit );
- return res;
-}
-
-static void *handle_conn( void *p ) {
- int sock = *(int*)p;
- int err;
-
- DPRINT( "sock: %d\n", sock );
- do {
- err = receive(sock, 1000);
- } while ( 0 < err && !force_quit );
- net_close( sock );
- return p;
-}
-
-static int shmgetter(void) {
- int ret;
+int init_shm(void) {
int shmid;
- int as, ss;
- pthread_t tid;
- pthread_attr_t attr;
shmid = shmget(SHM_KEY, sizeof *telemetry, 0);
if ( 0 > shmid ) {
EPRINT( "shmget failed\n" );
- ret = -1;
- goto err_shmget;
+ return -1;
}
-
telemetry = shmat(shmid, NULL, SHM_RDONLY);
if ((void *)-1 == telemetry) {
EPRINT( "shmget failed\n" );
- ret = -2;
- goto err_shmat;
- }
-
- ss = net_open_server( 8837, "*" );
- if ( ss < 0 ) {
- EPRINT( "net_open_server failed!\n" );
- ret = -3;
- goto err_open_server;
- }
-
- while ( !force_quit ) {
- if ( (as = net_accept( ss )) > 0 ) {
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&tid, &attr, handle_conn, &as);
- usleep (100);
- }
+ shmdt(telemetry);
+ return -2;
}
-
-err_open_server:
-err_shmat:
- shmdt(telemetry);
-err_shmget:
- return ret;
-}
-
-int main(int argc, char *argv[]) {
- int res;
-
- //install signal handlers
- signal(SIGTERM, handle_signal);
- signal(SIGINT, handle_signal);
- res = shmgetter();
- puts("");
- return res;
+ return 0;
}
--- /dev/null
+#ifndef SHMGET_H_
+#define SHMGET_H_
+
+#include "telemetry.h"
+
+extern struct telemetry_state_t *telemetry;
+
+extern int init_shm(void);
+
+#endif /* SHMGET_H_ */
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <poll.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include "fserv.h"
+#include "net.h"
+#include "log.h"
+#include "shmget.h"
+
+static volatile int force_quit;
+
+static void handle_signal(int sig) {
+ fprintf (stderr, "SIGNAL: %d\n", sig);
+ switch (sig){
+ case SIGTERM:
+ case SIGINT:
+ force_quit = 1;
+ break;
+ }
+}
+
+enum respond_code {
+ r_index,
+ r_json,
+ r_none
+};
+
+static void respond(int fd, const char *req, int code) {
+ char buf[4096];
+ char origin[256] = "http://localhost";
+ char host[256] = "localhost";
+ const char *s;
+ switch (code) {
+ case r_json:
+ case r_index:
+ s = strstr(req, "Origin:");
+ if (s){
+ s += 8; //strlen("Origin: ");
+ const char *e = strstr(s, "\r\n");
+ strncpy(origin, s, e-s);
+ }
+ s = strstr(req, "Host:");
+ if (s){
+ s += 6;//strlen("Host: ");
+ const char *e = strstr(s, "\r\n");
+ strncpy(host, s, e-s);
+ }
+
+ write(fd, buf, sprintf (buf, "HTTP/1.1 200 OK\r\n"));
+ write(fd, buf, sprintf (buf, "Host: %s\r\n", host));
+ if (r_json == code){
+ write(fd, buf, sprintf (buf, "Access-Control-Allow-Origin: %s\r\n", origin));
+ write(fd, buf, sprintf (buf, "Content-type: text/json\r\n"));
+ write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
+ write(fd, buf, sprintf (buf, "{ \"fc_avg\": %3.2f, \"speed\": %3.2f, \"cc\": %3.2f }",
+ 100.0 * telemetry->fc_avg , telemetry -> speed * 3.6, telemetry -> cc * 3.6));
+ } else {
+ struct file_info_t fi;
+ if (0 == fserv_open_server("index.html", &fi)){
+ write(fd, buf, sprintf (buf, "Content-type: text/html\r\n"));
+ write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
+ fserv_sendfile(fd, &fi);
+ fserv_close(&fi);
+ } else {
+ write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
+ write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
+ write(fd, buf, sprintf (buf, "Tough luck"));
+ }
+ }
+ break;
+ case r_none:
+ write(fd, buf, sprintf (buf, "HTTP/1.1 404 Not Found\r\n"));
+ write(fd, buf, sprintf (buf, "Host: localhost\r\n"));
+ write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
+ write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
+ write(fd, buf, sprintf (buf, "Fuck you 404!"));
+ break;
+ default:
+ write(fd, buf, sprintf (buf, "HTTP/1.1 500 Internal Server Error\r\n"));
+ write(fd, buf, sprintf (buf, "Host: localhost\r\n"));
+ write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
+ write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
+ write(fd, buf, sprintf (buf, "Fuck you 500!"));
+ break;
+ }
+}
+
+static int receive(int fd, int timeout) {
+ struct pollfd pe;
+ int res;
+ pe.fd = fd;
+ char buf[2048];
+ int bread, total;
+
+ total = 0;
+ *buf = 0;
+ do {
+ pe.events = POLLIN;
+ pe.revents = 0;
+ res = poll(&pe, 1, timeout);
+ if ( 0 < res && pe.revents == POLLIN ) {
+ errno = 0;
+ bread = read(fd, buf + total, sizeof buf - total);
+ if ( 0 > bread ) {
+ switch (errno) {
+ case EAGAIN:
+ //case EWOULDBLOCK:
+ case EINTR:
+ break;
+ default:
+ res = -1;
+ break;
+ }
+ }
+ else if ( 0 == bread && 0 == errno ) {
+ res = -1;
+ }
+ else {
+ total += bread;
+ buf[total] = 0;
+ if ( strstr(buf, "\r\n\r\n" ) ) {
+ fprintf (stderr, "%s", buf);
+ if (0 == strncmp(buf, "GET /json HTTP", 10))
+ respond(fd, buf, r_json);
+ else if (0 == strncmp(buf, "GET / HTTP", 10))
+ respond(fd, buf, r_index);
+ else
+ respond(fd, NULL, r_none);
+ *buf = 0;
+ res = 0;
+ }
+ }
+ }
+ timeout = 200;
+ } while ( 1 == res && pe.revents == POLLIN && !force_quit );
+ return res;
+}
+
+static void *handle_conn( void *p ) {
+ int sock = *(int*)p;
+ int err;
+
+ DPRINT( "sock: %d\n", sock );
+ do {
+ err = receive(sock, 1000);
+ } while ( 0 < err && !force_quit );
+ net_close( sock );
+ return p;
+}
+
+static int serve_http(void) {
+ int as, ss;
+ pthread_t tid;
+ pthread_attr_t attr;
+
+ ss = net_open_server( 8837, "*" );
+ if ( ss < 0 ) {
+ EPRINT( "net_open_server failed!\n" );
+ return -1;
+ }
+
+ while ( !force_quit ) {
+ if ( (as = net_accept( ss )) > 0 ) {
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&tid, &attr, handle_conn, &as);
+ usleep (100);
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ signal(SIGTERM, handle_signal);
+ signal(SIGINT, handle_signal);
+
+ if ( 0 != init_shm() )
+ exit( EXIT_FAILURE);
+
+ if ( 0 != serve_http() )
+ exit( EXIT_FAILURE);
+
+ exit( EXIT_SUCCESS );
+ (void)argc; (void)argv;
+}