From 0a7664de84e25474991ead0d76dc9aea58e61aba Mon Sep 17 00:00:00 2001 From: Jeremy Tan Date: Thu, 29 Aug 2013 16:13:30 +0800 Subject: [PATCH] (Restructure) Move controls to separate file. This should be where actuators stuff goes. --- nginx-configs/sites-enabled/mctxconfig | 4 +- server/Makefile | 2 +- server/control.c | 50 ++++++++++++++ server/control.h | 7 ++ server/fastcgi.c | 93 ++++++++++++-------------- server/fastcgi.h | 4 +- 6 files changed, 104 insertions(+), 56 deletions(-) create mode 100644 server/control.c create mode 100644 server/control.h diff --git a/nginx-configs/sites-enabled/mctxconfig b/nginx-configs/sites-enabled/mctxconfig index dfdf2b9..4da2b84 100644 --- a/nginx-configs/sites-enabled/mctxconfig +++ b/nginx-configs/sites-enabled/mctxconfig @@ -73,12 +73,12 @@ server { #MCTX API location /api { #Login area - location ^~ /api/login { + location ^~ /api/control { auth_basic "Restricted Access"; auth_basic_user_file /usr/share/nginx/access/.htpasswd; fastcgi_pass 127.0.0.1:9005; - fastcgi_param DOCUMENT_URI_LOCAL login; + fastcgi_param DOCUMENT_URI_LOCAL control; include fastcgi_params; } location ~ ^/api/?([^?]*) { diff --git a/server/Makefile b/server/Makefile index ef834a1..0858d7d 100644 --- a/server/Makefile +++ b/server/Makefile @@ -2,7 +2,7 @@ CXX = gcc FLAGS = -std=c99 -Wall -Werror -pedantic -g LIB = -lpthread -lfcgi -lssl -lcrypto -OBJ = log.o sensor.o fastcgi.o thread.o main.o +OBJ = log.o control.o sensor.o fastcgi.o thread.o main.o RM = rm -f BIN = server diff --git a/server/control.c b/server/control.c new file mode 100644 index 0000000..7f5ea34 --- /dev/null +++ b/server/control.c @@ -0,0 +1,50 @@ +#include "common.h" +#include "control.h" + +/** + * System control handler. This covers control over all aspects of the system. + * E.g: Actuators, system commands (start/stop experiment/recording) etc + * @param context The context to work in + * @param params The input parameters + */ +void Control_Handler(FCGIContext *context, char *params) { + const char *key, *value, *loginkey = NULL, *action = NULL; + bool force = false; + + while ((params = FCGI_KeyPair(params, &key, &value))) { + if (!strcmp(key, "action")) + action = value; + else if (!strcmp(key, "key")) + loginkey = value; + else if (!strcmp(key, "force")) + force = !force; + else if (!strcmp(key, "id")) { + + } + else if (!strcmp(key, "value")) { + + } + } + + if (!strcmp(action, "start")) { + FCGI_Authorize(context, force); + } else if (!strcmp(action, "stop")) { //Don't require control key to stop... + //EMERGENCY STOP!! + FCGI_BeginJSON(context, STATUS_OK); + FCGI_JSONPair("description", "stopped!"); //Not really + FCGI_EndJSON(); + } else { + if (!FCGI_Authorized(context, loginkey)) { + FCGI_BeginJSON(context, STATUS_UNAUTHORIZED); + FCGI_JSONPair("description", "Invalid key specified."); + FCGI_EndJSON(); + return; + } else if (!strcmp(action, "end")) { + FCGI_AuthorizeEnd(context); + } else if (!strcmp(action, "set")) { + FCGI_BeginJSON(context, STATUS_OK); + FCGI_JSONPair("description", "actuated!"); + FCGI_EndJSON(); + } + } +} diff --git a/server/control.h b/server/control.h new file mode 100644 index 0000000..af61066 --- /dev/null +++ b/server/control.h @@ -0,0 +1,7 @@ +#ifndef _CONTROL_H +#define _CONTROL_H + +extern void Control_Handler(FCGIContext *context, char *params); + + +#endif diff --git a/server/fastcgi.c b/server/fastcgi.c index 49bf197..6eff2df 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -12,7 +12,7 @@ #include "common.h" #include "sensor.h" -#include "log.h" +#include "control.h" #include "options.h" #define LOGIN_TIMEOUT 180 @@ -29,32 +29,30 @@ struct FCGIContext { }; /** - * Handles user logins. - * @param context The context to work in - * @param params User specified parameters - */ -static void LoginHandler(FCGIContext *context, char *params) { - const char *key, *value; - bool force = 0, end = 0; - - while ((params = FCGI_KeyPair(params, &key, &value))) { - if (!strcmp(key, "force")) - force = !force; - else if (!strcmp(key, "end")) - end = !end; - } - - if (end) { - *(context->login_key) = 0; - FCGI_BeginJSON(context, STATUS_OK); - FCGI_EndJSON(); - return; - } + * Identifies current version info. Useful for testing that the API is running. + * TODO - Consider adding info about available sensors and actuators (eg capabilities)? + */ +static void IdentifyHandler(FCGIContext *context, char *params) { + FCGI_BeginJSON(context, STATUS_OK); + FCGI_JSONPair("description", "MCTX3420 Server API (2013)"); + FCGI_JSONPair("build_date", __DATE__ " " __TIME__); + FCGI_EndJSON(); +} +/** + * Gives the user an authorization key that determines who has control over + * the system at any one time. The key can be forcibly generated, revoking + * any previous control keys. To be used in conjunction with HTTP + * basic authentication. + * This function will generate a JSON response that indicates success/failure. + * @param context The context to work in + * @param force Whether to force key generation or not. + */ +void FCGI_Authorize(FCGIContext *context, bool force) { time_t now = time(NULL); - if (force || !*(context->login_key) || - (now - context->login_timestamp > LOGIN_TIMEOUT)) - { + bool expired = now - context->login_timestamp > LOGIN_TIMEOUT; + + if (force || !*(context->login_key) || expired) { SHA_CTX sha1ctx; unsigned char sha1[20]; int i = rand(); @@ -70,36 +68,28 @@ static void LoginHandler(FCGIContext *context, char *params) { snprintf(context->login_ip, 16, "%s", getenv("REMOTE_ADDR")); FCGI_BeginJSON(context, STATUS_OK); FCGI_JSONPair("key", context->login_key); - FCGI_EndJSON(); + FCGI_EndJSON(); } else { char buf[128]; strftime(buf, 128, "%H:%M:%S %d-%m-%Y", localtime(&(context->login_timestamp))); FCGI_BeginJSON(context, STATUS_UNAUTHORIZED); FCGI_JSONPair("description", "Already logged in"); - FCGI_JSONPair("user", context->login_ip); - FCGI_JSONPair("time", buf); + FCGI_JSONPair("current_user", context->login_ip); + FCGI_JSONPair("when", buf); FCGI_EndJSON(); } } -/*TODO: Remove and replace with the actual actuator code*/ -static void ActuatorHandler(FCGIContext *context, char *params) { - const char *key, *value, *loginkey = NULL; - while ((params = FCGI_KeyPair(params, &key, &value))) { - if (!strcmp(key, "key")) { - loginkey = value; - } - } - if (!loginkey || !FCGI_Authorized(context, loginkey)) { - FCGI_BeginJSON(context, STATUS_UNAUTHORIZED); - FCGI_JSONPair("description", "Invalid key specified."); - FCGI_EndJSON(); - } else { - FCGI_BeginJSON(context, STATUS_OK); - FCGI_JSONPair("description", "Logged in!"); - FCGI_EndJSON(); - } +/** + * Revokes the current authorization key, if present. + * @param context The context to work in + */ +void FCGI_AuthorizeEnd(FCGIContext *context) { + *(context->login_key) = 0; + FCGI_BeginJSON(context, STATUS_OK); + FCGI_EndJSON(); + return; } /** @@ -113,7 +103,7 @@ static void ActuatorHandler(FCGIContext *context, char *params) { bool FCGI_Authorized(FCGIContext *context, const char *key) { time_t now = time(NULL); int result = (now - context->login_timestamp) <= LOGIN_TIMEOUT && - !strcmp(context->login_key, key); + key != NULL && !strcmp(context->login_key, key); if (result) { context->login_timestamp = now; //Update the login_timestamp } @@ -312,20 +302,19 @@ void * FCGI_RequestLoop (void *data) if (lastchar > 0 && module[lastchar] == '/') module[lastchar] = 0; - - if (!strcmp("login", module)) { - module_handler = LoginHandler; + if (!*module || !strcmp("identify", module)) { + module_handler = IdentifyHandler; + } else if (!strcmp("control", module)) { + module_handler = Control_Handler; } else if (!strcmp("sensors", module)) { module_handler = Sensor_Handler; - } else if (!strcmp("actuators", module)) { - module_handler = ActuatorHandler; } context.current_module = module; if (module_handler) { module_handler(&context, params); } else { - strncat(module, " [unknown]", BUFSIZ); + strncat(module, " (unhandled)", BUFSIZ); FCGI_RejectJSON(&context); } context.response_number++; diff --git a/server/fastcgi.h b/server/fastcgi.h index 3030b75..8e4dc4c 100644 --- a/server/fastcgi.h +++ b/server/fastcgi.h @@ -14,8 +14,10 @@ typedef enum StatusCodes { } StatusCodes; typedef struct FCGIContext FCGIContext; -typedef void (*ModuleHandler) (FCGIContext *data, char *params); +typedef void (*ModuleHandler) (FCGIContext *context, char *params); +extern void FCGI_Authorize(FCGIContext *context, bool force); +extern void FCGI_AuthorizeEnd(FCGIContext *context); extern bool FCGI_Authorized(FCGIContext *context, const char *key); extern char *FCGI_KeyPair(char *in, const char **key, const char **value); extern void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code); -- 2.20.1