--- /dev/null
+*.so
+*.o
+*.exe
+*.dll
+
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
\ No newline at end of file
#include "options.h"
// --- Static variables --- //
-static char * unspecified_funct = (char*)"???";
+static const char * unspecified_funct = "???";
// --- Function implementations --- //
* @param fmt - A format string
* @param ... - Arguments to be printed according to the format string
*/
-void Log(int level, char * funct, char * fmt, ...)
+void LogEx(int level, const char * funct, ...)
{
+ const char *fmt;
+ va_list va;
+ va_start(va, funct);
+ fmt = va_arg(va, const char*);
+
if (fmt == NULL) // sanity check
- Fatal("Log", "Format string is NULL");
+ FatalEx("Log", "Format string is NULL");
// Don't print the message unless we need to
- if (level > g_options.verbosity)
+ if (level > g_options.verbosity)
return;
if (funct == NULL)
funct = unspecified_funct;
// Make a human readable severity string
- char severity[BUFSIZ];
+ const char *severity;
switch (level)
{
case LOGERR:
- sprintf(severity, "ERROR");
+ severity = "ERROR";
break;
case LOGWARN:
- sprintf(severity, "WARNING");
+ severity = "WARNING";
break;
case LOGNOTE:
- sprintf(severity, "NOTICE");
+ severity = "NOTICE";
break;
case LOGINFO:
- sprintf(severity, "INFO");
+ severity = "INFO";
break;
default:
- sprintf(severity, "DEBUG");
+ severity = "DEBUG";
break;
}
fprintf(stderr, "%s [%d] : %s : %s - ", g_options.program, getpid(), severity, funct);
// Then pass additional arguments with the format string to vfprintf for printing
- va_list va;
- va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
/**
* Handle a Fatal error in the program by printing a message and exiting the program
- CALLING THIS FUNCTION WILL CAUSE THE PROGAM TO EXIT
+ * CALLING THIS FUNCTION WILL CAUSE THE PROGAM TO EXIT
* @param funct - Name of the calling function
* @param fmt - A format string
* @param ... - Arguments to be printed according to the format string
*/
-void Fatal(char * funct, char * fmt, ...)
+void FatalEx(const char * funct, ...)
{
+ const char *fmt;
+ va_list va;
+ va_start(va, funct);
+ fmt = va_arg(va, const char*);
if (fmt == NULL)
{
// Fatal error in the Fatal function.
// (This really shouldn't happen unless someone does something insanely stupid)
- Fatal("Fatal", "Format string is NULL");
+ FatalEx("Fatal", "Format string is NULL");
return; // Should never get here
}
fprintf(stderr, "%s [%d] : %s : FATAL - ", g_options.program, getpid(), funct);
- va_list va;
- va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
fprintf(stderr, "\n");
#include <stdbool.h>
#include <stdarg.h>
+//To get around a 'pedantic' C99 rule that you must have at least 1 variadic arg, combine fmt into that.
+#define Log(level, ...) LogEx(level, __func__, __VA_ARGS__)
+#define Fatal(...) FatalEx(__func__, __VA_ARGS__)
// An enum to make the severity of log messages human readable in code
enum {LOGERR=0, LOGWARN=1, LOGNOTE=2, LOGINFO=3,LOGDEBUG=4};
-extern void Log(int level, char * funct, char * fmt,...); // General function for printing log messages to stderr
-extern void Fatal(char * funct, char * fmt, ...); // Function that deals with a fatal error (prints a message, then exits the program).
+extern void LogEx(int level, const char * funct, ...); // General function for printing log messages to stderr
+extern void FatalEx(const char * funct, ...); // Function that deals with a fatal error (prints a message, then exits the program).
#endif //_LOG_H
{
g_options.program = argv[0]; // program name
g_options.verbosity = LOGDEBUG; // default log level
- Log(LOGDEBUG, "ParseArguments", "Called as %s with %d arguments.", g_options.program, argc);
+ Log(LOGDEBUG, "Called as %s with %d arguments.", g_options.program, argc);
}
/**
{
// At the moment just always exit.
// Call `exit` so that Cleanup will be called to... clean up.
- Log(LOGWARN, "SignalHandler", "Got signal %d (%s). Exiting.", signal, strsignal(signal));
+ Log(LOGWARN, "Got signal %d (%s). Exiting.", sig, strsignal(sig));
exit(sig);
}
*/
void Cleanup()
{
- Log(LOGDEBUG, "Cleanup", "Begin cleanup.");
- Log(LOGDEBUG, "Cleanup", "Finish cleanup.");
+ Log(LOGDEBUG, "Begin cleanup.");
+ Log(LOGDEBUG, "Finish cleanup.");
}
*/
int main(int argc, char ** argv)
{
+ ParseArguments(argc, argv, &g_options);
return 0;
}
--- /dev/null
+The application could be quite easily made to use FastCGI. Unlike normal CGI,
+with FastCGI (fcgi), the process is executed once, and continues to run. The
+process will receive responses from the browser in the response loop. Hence,
+sensor data can be read in another thread while the response loop runs.
+
+Setup:
+Compile fastcgi_test.c with: (the libfcgi-dev package must be installed)
+gcc fastcgi_test.c -lfcgi -o fastcgi_test
+
+Configure nginx to pass all requests to the address /cgi/ to the application:
+Edit /etc/nginx/sites-enabled/default by adding the contents of nginx_server_config.txt
+
+Restart nginx:
+/etc/init.d/nginx restart
+
+Run the application:
+spawn-fcgi -p9005 -n ./fastcgi_test
+
+You can see the results at:
+http://your.domain/cgi
\ No newline at end of file
--- /dev/null
+#include "fcgi_stdio.h" /* fcgi library; put it first*/
+#include <stdlib.h>
+
+/*
+ But the suggestion was: FunctionName, variable_name (local or member),
+ Structure, ENUMVALUE, Extern_FunctionName, g_global
+*/
+
+typedef struct Data Data;
+
+typedef void (*ModuleHandler) (Data *data, const char *params);
+
+static void SensorsHandler(Data *data, const char *params) {
+ printf("Sensors module!<br>");
+}
+
+/*
+ API Schema:
+ Sensors:
+ /cgi/sensors?get=x
+ *get=x is optional. Retrieves info for sensor with id x
+ Devices:
+ /cgi/devices?status=x&power=y&id=z
+ *status and power is optional
+ *status retrieves whether device with id x is operational
+ *power tells whether or not to power on/off the device with id z
+
+ Response format:
+ 200 OK if request was ok
+ 400 bad request for malformed request
+
+*/
+int main (int argc, char *argv[])
+{
+ Data *data = NULL;
+ int count = 0;
+
+ //FCGI Accept loop
+ while (FCGI_Accept() >= 0) {
+ ModuleHandler module_handler = NULL;
+ const char *module = getenv("DOCUMENT_URI_LOCAL");
+ const char *params = getenv("QUERY_STRING");
+
+ if (!strcmp("sensors", module)) {
+ module_handler = SensorsHandler; //Replace with pointer to sensors handler
+ } else if (!strcmp("admin"), module) {
+ module_handler = NULL; //Replace with pointer to admin handler
+ printf("Admin module selected!\n");
+ }
+
+ if (module_handler) {
+ printf("Content-type: text/html\r\n\r\n"); //Replace with actual type
+ module_handler(data, params);
+ } else {
+ printf("Status: 400 Bad Request\r\n"
+ "Content-type: text/html\r\n\r\n"
+ "<title>400 Bad Request</title>\n"
+ "Unknown module '%s' selected.<br>\n",
+ module);
+ }
+
+ //Debgging:
+ printf("Module: %s, Params: %s<br>\n", module, params);
+ printf("Request number %d, host <i>%s</i>\n",
+ count++, getenv("SERVER_HOSTNAME"));
+ }
+}
--- /dev/null
+ #Custom cgi
+ location ~ ^/cgi/([^?]*) {
+ fastcgi_pass 127.0.0.1:9005;
+ fastcgi_param GATEWAY_INTERFACE CGI/1.1;
+ fastcgi_param SERVER_HOSTNAME mctxsoft;
+ fastcgi_param SERVER_SOFTWARE nginx;
+
+ #Regex removed /cgi/ part, and any args
+ fastcgi_param DOCUMENT_URI_LOCAL $1;
+ fastcgi_param QUERY_STRING $query_string;
+
+ #Unused for now
+ fastcgi_param REQUEST_METHOD $request_method;
+ fastcgi_param CONTENT_TYPE $content_type;
+ fastcgi_param CONTENT_LENGTH $content_length;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script$
+ fastcgi_param SCRIPT_NAME $fastcgi_script_name;
+ fastcgi_param REQUEST_URI $request_uri;
+ fastcgi_param DOCUMENT_URI $document_uri;
+ fastcgi_param DOCUMENT_ROOT $document_root;
+ fastcgi_param SERVER_PROTOCOL $server_protocol;
+ fastcgi_param REMOTE_ADDR $remote_addr;
+ fastcgi_param REMOTE_PORT $remote_port;
+ fastcgi_param SERVER_ADDR $server_addr;
+ fastcgi_param SERVER_PORT $server_port;
+ fastcgi_param SERVER_NAME $server_name;
+ }