Merge branch 'master' of https://github.com/szmoore/MCTX3420.git
authorJeremy Tan <[email protected]>
Mon, 2 Sep 2013 00:45:52 +0000 (08:45 +0800)
committerJeremy Tan <[email protected]>
Mon, 2 Sep 2013 00:45:52 +0000 (08:45 +0800)
1  2 
server/Makefile
server/fastcgi.c
server/fastcgi.h

diff --combined server/Makefile
@@@ -2,11 -2,16 +2,16 @@@
  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
  
+ all : $(BIN) stream
+ stream : stream.c
+       $(CXX) -o stream stream.c -I/usr/include/opencv -I/usr/include/opencv2/highgui -L/usr/lib -lopencv_highgui -lopencv_core -lopencv_ml -lopencv_imgproc 
  
  $(BIN) : $(OBJ)
        $(CXX) $(FLAGS) -o $(BIN) $(OBJ) $(LIB)
diff --combined server/fastcgi.c
  
  #include "common.h"
  #include "sensor.h"
 -#include "log.h"
 +#include "control.h"
  #include "options.h"
  
 -#define LOGIN_TIMEOUT 180
 +#define CONTROL_TIMEOUT 180
  
  struct FCGIContext {
 -      /**The time of last valid logged-in user access*/
 -      time_t login_timestamp;
 -      char login_key[41];
 -      char login_ip[16];
 +      /**The time of last valid user access possessing the control key*/
 +      time_t control_timestamp;
 +      char control_key[41];
 +      char control_ip[16];
        /**The name of the current module**/
        const char *current_module;
        /**For debugging purposes?**/
  };
  
  /**
 - * 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 a 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_BeginControl(FCGIContext *context, bool force) {
        time_t now = time(NULL);
 -      if (force || !*(context->login_key) || 
 -         (now - context->login_timestamp > LOGIN_TIMEOUT)) 
 -      {
 +      bool expired = now - context->control_timestamp > CONTROL_TIMEOUT;
 +      
 +      if (force || !*(context->control_key) || expired) {
                SHA_CTX sha1ctx;
                unsigned char sha1[20];
                int i = rand();
                SHA1_Update(&sha1ctx, &i, sizeof(i));
                SHA1_Final(sha1, &sha1ctx);
  
 -              context->login_timestamp = now;
 +              context->control_timestamp = now;
                for (i = 0; i < 20; i++)
 -                      sprintf(context->login_key + i * 2, "%02x", sha1[i]);
 -              snprintf(context->login_ip, 16, "%s", getenv("REMOTE_ADDR"));
 +                      sprintf(context->control_key + i * 2, "%02x", sha1[i]);
 +              snprintf(context->control_ip, 16, "%s", getenv("REMOTE_ADDR"));
                FCGI_BeginJSON(context, STATUS_OK);
 -              FCGI_JSONPair("key", context->login_key);
 -              FCGI_EndJSON();
 +              FCGI_JSONPair("key", context->control_key);
 +              FCGI_EndJSON();         
        } else {
                char buf[128];
                strftime(buf, 128, "%H:%M:%S %d-%m-%Y",
 -                      localtime(&(context->login_timestamp))); 
 +                      localtime(&(context->control_timestamp))); 
                FCGI_BeginJSON(context, STATUS_UNAUTHORIZED);
 -              FCGI_JSONPair("description", "Already logged in");
 -              FCGI_JSONPair("user", context->login_ip); 
 -              FCGI_JSONPair("time", 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_JSONPair("description", "Another user already has control");
 +              FCGI_JSONPair("current_user", context->control_ip); 
 +              FCGI_JSONPair("when", buf);
                FCGI_EndJSON();
        }
  }
  
  /**
   * Given an FCGIContext, determines if the current user (as specified by
 - * the key) is authorized or not. If validated, the context login_timestamp is
 + * the key) has control or not. If validated, the context control_timestamp is
   * updated.
   * @param context The context to work in
 - * @param key The login key to be validated.
 + * @param key The control key to be validated.
   * @return TRUE if authorized, FALSE if not.
   */
 -bool FCGI_Authorized(FCGIContext *context, const char *key) {
 +bool FCGI_HasControl(FCGIContext *context, const char *key) {
        time_t now = time(NULL);
 -      int result = (now - context->login_timestamp) <= LOGIN_TIMEOUT &&
 -                               !strcmp(context->login_key, key);
 +      int result = (now - context->control_timestamp) <= CONTROL_TIMEOUT &&
 +                               key != NULL && !strcmp(context->control_key, key);
        if (result) {
 -              context->login_timestamp = now; //Update the login_timestamp
 +              context->control_timestamp = now; //Update the control_timestamp
        }
        return result;
  }
  
 +
 +/**
 + * Revokes the current control key, if present.
 + * @param context The context to work in
 + */
 +void FCGI_EndControl(FCGIContext *context) {
 +      *(context->control_key) = 0;
 +      FCGI_BeginJSON(context, STATUS_OK);
 +      FCGI_EndJSON();
 +      return;
 +}
 +
  /**
   * Extracts a key/value pair from a request string.
   * Note that the input is modified by this function.
@@@ -246,27 -255,18 +246,27 @@@ void FCGI_EndJSON(
  }
  
  /**
 - * To be used when the input parameters are invalid.
 - * Sends a response with HTTP status 400 Bad request, along with
 - * JSON data for debugging.
 + * To be used when the input parameters are invalid. The return data will
 + * have a status of STATUS_ERROR, along with other debugging information.
   * @param context The context to work in
 - * @param params The parameters that the module handler received.
   */
  void FCGI_RejectJSON(FCGIContext *context)
  {
 -      printf("Status: 400 Bad Request\r\n");
 -      
 -      FCGI_BeginJSON(context, STATUS_ERROR);
 -      FCGI_JSONPair("description", "Invalid request");
 +      FCGI_RejectJSONEx(context, STATUS_ERROR, "Invalid request");
 +}
 +
 +/**
 + * To be used when the input parameters are rejected. The return data
 + * will also have debugging information provided.
 + * @param context The context to work in
 + * @param status The status the return data should have.
 + * @param description A short description of why the input was rejected.
 + * @param params The parameters that the module handler received.
 + */
 +void FCGI_RejectJSONEx(FCGIContext *context, StatusCodes status, const char *description)
 +{
 +      FCGI_BeginJSON(context, status);
 +      FCGI_JSONPair("description", description);
        FCGI_JSONLong("responsenumber", context->response_number);
        FCGI_JSONPair("params", getenv("QUERY_STRING"));
        FCGI_JSONPair("host", getenv("SERVER_HOSTNAME"));
        FCGI_EndJSON();
  }
  
  /**
   * Main FCGI request loop that receives/responds to client requests.
   * @param data Reserved.
@@@ -312,19 -313,20 +313,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 --combined server/fastcgi.h
@@@ -6,19 -6,17 +6,19 @@@
  #ifndef _FASTCGI_H
  #define _FASTCGI_H
   
 -/**Status codes that fcgi module handlers can return**/
 +/**(HTTP) Status codes that fcgi module handlers can return**/
  typedef enum StatusCodes {
 -      STATUS_OK = 0,
 -      STATUS_ERROR = -1,
 -      STATUS_UNAUTHORIZED = -2
 +      STATUS_OK = 200,
 +      STATUS_ERROR = 400,
 +      STATUS_UNAUTHORIZED = 401
  } StatusCodes;
  
  typedef struct FCGIContext FCGIContext;
 -typedef void (*ModuleHandler) (FCGIContext *data, char *params);
 +typedef void (*ModuleHandler) (FCGIContext *context, char *params);
  
 -extern bool FCGI_Authorized(FCGIContext *context, const char *key);
 +extern void FCGI_BeginControl(FCGIContext *context, bool force);
 +extern void FCGI_EndControl(FCGIContext *context);
 +extern bool FCGI_HasControl(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);
  extern void FCGI_JSONPair(const char *key, const char *value);
@@@ -29,8 -27,8 +29,9 @@@ extern void FCGI_JSONKey(const char *ke
  extern void FCGI_JSONValue(const char *format, ...);
  extern void FCGI_EndJSON();
  extern void FCGI_RejectJSON(FCGIContext *context);
 +extern void FCGI_RejectJSONEx(FCGIContext *context, StatusCodes status, const char *description);
  extern void * FCGI_RequestLoop (void *data);
+ #define FCGI_PrintRaw FCGI_JSONValue // Functionality is identical
  
  #endif
  

UCC git Repository :: git.ucc.asn.au