Merge branch 'master' of https://github.com/szmoore/MCTX3420.git
authorJeremy Tan <[email protected]>
Thu, 15 Aug 2013 00:29:58 +0000 (08:29 +0800)
committerJeremy Tan <[email protected]>
Thu, 15 Aug 2013 00:29:58 +0000 (08:29 +0800)
irc/log
rpi/Makefile
rpi/log.c
rpi/log.h
rpi/main.c [new file with mode: 0644]
rpi/network.c [deleted file]
rpi/network.h [deleted file]
rpi/options.h
rpi/webserver.c [deleted file]

diff --git a/irc/log b/irc/log
index 8c7c90e..103a54c 100644 (file)
--- a/irc/log
+++ b/irc/log
 20:49 -!- jtanx [[email protected]] has quit ["ChatZilla 0.9.89 [Firefox 22.0/20130618035212]"]
 20:56 -!- jtanx [[email protected]] has joined #mctxuwa_softdev
 22:40 -!- jtanx [[email protected]] has quit ["ChatZilla 0.9.89 [Firefox 22.0/20130618035212]"]
+--- Day changed Wed Aug 14 2013
+07:58 -!- jtanx [[email protected]] has joined #mctxuwa_softdev
+09:13 < jtanx> I've done a version using fastcgi, which was surprisingly quite easy to set up
+09:13 < jtanx> see here: https://github.com/jtanx/MCTX3420/tree/master/testing/fastcgi-approach
+10:41 < sam_moore> That looks interesting, I'd prefer that to the PHP/database solution
+10:42 < sam_moore> My concern is: You have to query the web server to start the process, even though it keeps running
+10:42 < sam_moore> Also, I know "write a custom HTTP server" sounds scary, but it does actually work
+10:43 < jtanx> nah
+10:43 < jtanx> fastcgi
+10:43 < jtanx> the process is started once and always runs
+10:43 < jtanx> so you have a request loop
+10:44 < jtanx> wait
+10:44 < jtanx> how do you envision it working?
+10:45 < sam_moore> Oh, right, I see how the fastcgi approach would work, it's basically the same idea; you have something responding to HTTP queries in one thread, something dealing with sensors/actuators in seperate threads
+10:45 < jtanx> yeah
+10:46 < jtanx> except that you don't have to worry about maintaining your own webserver
+10:46 < sam_moore> Cool
+10:46 < sam_moore> I do think that the HTTP server isn't that hard, and it's mostly working
+10:46 < sam_moore> But we can probably switch to fastcgi
+10:48 < sam_moore> I mean, we still have to parse a query string right?
+10:48 < jtanx> well yes
+10:48 < jtanx> if your request was
+10:48 < jtanx> http://blah/cgi/?key=value&anotherkey=value2
+10:48 < jtanx> you'd get back key=value&anotherkey=value2
+10:48 < jtanx> as query string
+10:50 < jtanx> try it out here: http://124.169.120.181:8080/cgi
+10:51 < jtanx> (hopefully that forwards ok)
+10:51 < sam_moore> Yep, that's cool
+10:51 < sam_moore> The HTTP server I wrote basically does that
+10:51 < sam_moore> But if it really bothers you, I'm fine with switching to fastcgi :P
+10:52 < jtanx> well whatever works
+10:52 < jtanx> but I thought it might be more maintainable if you used something that already exists :P
+10:52 < sam_moore> Yeah, but thinking about it, what maintainence does the HTTP server require?
+10:53 < sam_moore> Oh well, it's a good idea
+10:53 < jtanx> for this situation not much
+10:57 < sam_moore> We can pretty easily start with a structure that would allow us to switch, but I'd lean towards keeping the custom HTTP server
+10:58 < sam_moore> Have you done multithreading in C before?
+10:58 < jtanx> in windows yes
+10:58 < jtanx> on linux not really
+10:58 < sam_moore> Ah, I've only done it on linux
+10:58 < jtanx> i did a bit in operating systems
+10:59 < jtanx> but kinda forgot
+10:59 < sam_moore> It shouldn't be too hard for our purposes
+11:00 < jtanx> that thing with running a custom webserver is that if anyone wants to reuse this in the future, i doubt they'd really like the idea of that
+11:01 < jtanx> say they had some new fangled thing that requires php
+11:01 < jtanx> which isn't going to work 
+11:01 < jtanx> but with a standard webserver like apache or nginx, it's really easy to just install an extra addon
+11:02 < sam_moore> I suppose... what would they need the new fangled php thing for?
+11:03 < jtanx> well that's the thing - for now I don't know, but it could be required
+11:03 < sam_moore> Yeah, good point
+11:03 < sam_moore> Ok, another reason to use an existing web server, is we might require some advanced features if we want to be serious about the safety stuff
+11:04 < sam_moore> For example, it would be a fair amount of work to add SSL to make the custom thing do https
+11:04 < jtanx> oh yeah
+11:04 < jtanx> that too
+11:04 < sam_moore> Also we might want some authentication on it
+11:04 < jtanx> nginx/apache are highly customisable
+11:05 < sam_moore> I've never used nginx, what are it'
+11:05 < sam_moore> s advantages over apache2?
+11:05 < jtanx> nginx
+11:05 < jtanx> yup
+11:05 < jtanx> its really good
+11:05 < sam_moore> Haha
+11:05 < jtanx> a lot of sites use it because it's fast
+11:05 < sam_moore> Fast is good
+11:05 < jtanx> faster than apache
+11:05 < sam_moore> Sold
+11:05 < sam_moore> Well, we only need one user as well
+11:05 < sam_moore> In fact, we deliberately do not want to have multiple clients able to use the thing at the same time
+11:05 < jtanx> haha true
+11:07 < sam_moore> Ok, so I think you've convinced me to use fastcgi
+11:07 < sam_moore> Most of the custom HTTP server was reused code, so I didn't waste too much time on it
+11:07 < jtanx> haha ok
+11:07 < jtanx> have you written one before?
+11:09 < sam_moore> Not specifically a HTTP server, but I've written a project for posix systems with a fair bit of networking
+11:09 < sam_moore> git.ucc.asn.au/?p=matches/swarm.git
+11:10 < jtanx> nice
+11:10 < sam_moore> It allows you to run a shell, eg: bash accross multiple machines at once
+11:11 < sam_moore> Not as useful as I thought it might be, but it was fun
+11:12 < jtanx> heh
+11:12 < jtanx> what did you end up using it for?
+11:13 < sam_moore> I was setting up a programming competition where you have AIs play against each other
+11:13 < sam_moore> I wanted to make a round robin
+11:13 < sam_moore> So I had a bash script setup to do that, but then I got impatient, because it would have to run the games in order
+11:14 < jtanx> oO
+11:14 < sam_moore> Well it turned out no one entered the competition, so I probably didn't need to go overboard
+11:14 < sam_moore> But maybe I can use it for something else
+11:15 < sam_moore> For the threading I'm thinking of using pthreads
+11:16 < sam_moore> The alternative is OpenMP, but it's more suited to numerical computation, rather than having seperate things talking to each other
+11:16 < jtanx> okay
+11:17 < sam_moore> My goal for this week was to have the framework started, so we just have some really basic threads running and then we can start implementing them
+11:17 < jtanx> yeah that would be good
+11:18 < sam_moore> If you want to do some work with the fastcgi part so that we'll be able to parse the query strings, that would probably be a good start
+11:18 < sam_moore> We don't have the exact details of pretty much anything yet
+11:18 < sam_moore> Maybe talk to James/Rowan about how the GUI is going to query the server
+11:19 < sam_moore> Also, did you see my suggested naming convention?
+11:19 < jtanx> no
+11:20 < sam_moore> I don't really mind, although I'd prefer not to have hungarian notation
+11:20 < sam_moore> As long as it'
+11:20 < sam_moore> s consistent
+11:21 < sam_moore> But the suggestion was: FunctionName, variable_name (local or member), Structure, ENUMVALUE, Extern_FunctionName, g_global
+11:21 < jtanx> okay I'll try to keep to that
+11:22 < sam_moore> Cool, I should probably go do something else
+12:33 < jtanx> i gotta go
+12:33 -!- jtanx [[email protected]] has quit ["ChatZilla 0.9.89 [Firefox 22.0/20130618035212]"]
+15:39 -!- jtanx [[email protected]] has joined #mctxuwa_softdev
+16:22 -!- justin_kruger [[email protected]] has joined #mctxuwa_softdev
+16:23 -!- justin_kruger [[email protected]] has quit [EOF From client]
+16:43 -!- jtanx_ [[email protected]] has joined #mctxuwa_softdev
+16:56 < jtanx_> a beagleboard
+16:56 < jtanx_> hmm
+16:58 -!- jtanx [[email protected]] has quit [Ping timeout]
+16:58 -!- jtanx_ is now known as jtanx
+17:03 < jtanx> is it the beaglebone black?
+17:03 < jtanx> sounds interesting
+17:04 < sam_moore> They didn't specify
+17:04 < sam_moore> Oh right, I accidentally cut out his message
+17:04 < sam_moore> tl;dr "Beagle Board"
+17:04 < jtanx> the beagle board is around $125 though
+17:04 < sam_moore> Probably the Beaglebone black
+17:04 < sam_moore> Oh really
+17:04 < sam_moore> Heh
+17:04 < jtanx> yeah
+17:05 < jtanx> the beaglebone black is $45
+17:05 < jtanx> but just looking the A/D converter on the black has a max voltage of 1.8v
+17:05 < sam_moore> That's probably what they meant, since they said it is "not much more expensive"
+17:05 < sam_moore> That should be fine; the sensors team says things are in mV
+17:05 < jtanx> okay
+17:05 < jtanx> that's good
+17:05 < sam_moore> Really though... electronics should be asking the sensors team stuff like this
+17:06 < jtanx> heh yeah
+17:06 < sam_moore> They should probably have asked us if it was feasable for software
+17:06 < sam_moore> Maybe they had someone who knew it would be, but still
+17:06 < sam_moore> It looks like it is anyway, so crisis averted
+17:07 < jtanx> just with the sensors, I think that the diferences need to be amplified so it covers the full range of the A/D converter
+17:07 < sam_moore> Yes, the sensors guy knows that
+17:07 < jtanx> yeah so if its only 1.8v there's less range than 0-5v
+17:08 < jtanx> is that compensated enough by having a 12 bit a/d converter vs a 10 bit (i think arduino is 10 bit) converter
+17:10 < sam_moore> I think so; you get ~4x more resolution from the 12 bit ADC and lose ~3x from the lower range
+17:10 < sam_moore> Also there's no set requirement yet on what the resolution should be
+17:11 < jtanx> true
+17:11 < jtanx> well in any case the bb black sounds quite nice
+17:11 < sam_moore> Yep, it'll probably be good to use
+17:14 < sam_moore> I'm much happier now that we actually have regular verbal communication with the other teams
+18:23 < sam_moore> I'm looking into getting doxygen working for this
+18:59 < jtanx> for the documentation?
+18:59 < jtanx> seems good, but never used it before myself
+19:01 < jtanx> looks a lot like javadoc
+21:26 -!- jtanx [[email protected]] has quit ["ChatZilla 0.9.89 [Firefox 22.0/20130618035212]"]
+21:34 -!- jtanx [[email protected]] has joined #mctxuwa_softdev
+22:54 -!- jtanx [[email protected]] has quit ["ChatZilla 0.9.89 [Firefox 22.0/20130618035212]"]
index 24310f3..a7f9f7b 100644 (file)
@@ -1,11 +1,11 @@
-# Makefile for web2io testing stuff
+# Makefile for rpi side server
 CXX = gcc
 FLAGS = -std=c99 -Wall -Werror -pedantic -g
 LIB = 
-OBJ = network.o log.o webserver.o
+OBJ = log.o main.o
 RM = rm -f
 
-BIN = webserver
+BIN = server
 
 $(BIN) : $(OBJ)
        $(CXX) $(FLAGS) -o $(BIN) $(OBJ)
index 3a8c55c..bd41936 100644 (file)
--- a/rpi/log.c
+++ b/rpi/log.c
@@ -1,16 +1,43 @@
+/**
+ * @file log.c
+ * @purpose Implement logging and error handling functions
+ */
+
+
+#include <unistd.h>
+
+// --- Custom headers --- //
 #include "log.h"
 #include "options.h"
-#include <unistd.h>
 
-static int last_len = 0;
+// --- Static variables --- //
+static char * unspecified_funct = (char*)"???";
+
+// --- Function implementations --- //
 
-void log_print(int level, char * funct, char * fmt, ...)
+/**
+ * @funct Log
+ * @purpose Print a message to stderr
+ * @param level - Specify how severe the message is.
+       If level is higher (less urgent) than the program's verbosity (see options.h) no message will be printed
+ * @param funct - String indicating the function name from which this function was called.
+       If this is NULL, Log will show the unspecified_funct string instead
+ * @param fmt - A format string
+ * @param ... - Arguments to be printed according to the format string
+ */
+void Log(int level, char * funct, char * fmt, ...)
 {
-       if (level > options.verbosity)
+       if (fmt == NULL) // sanity check
+               Fatal("Log", "Format string is NULL");
+
+       // Don't print the message unless we need to
+       if (level > g_options.verbosity) 
                return;
 
-       
+       if (funct == NULL)
+               funct = unspecified_funct;
 
+       // Make a human readable severity string
        char severity[BUFSIZ];
        switch (level)
        {
@@ -31,30 +58,43 @@ void log_print(int level, char * funct, char * fmt, ...)
                        break;
        }
 
-       if (funct != NULL)
-               last_len = fprintf(stderr, "%s [%d] : %s : %s - ", options.program, getpid(), severity, funct);
-       else
-       {
-               for (int i = 0; i < last_len; ++i);
-                       fprintf(stderr, " ");
-       }
+       // Print: Program name, PID, severity string, function name first
+       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);
+
+       // End log messages with a newline
        fprintf(stderr, "\n");
 }
 
-void error(char * funct, char * fmt, ...)
+/**
+ * @funct Fatal
+ * @purpose Handle a Fatal error in the program by printing a message and exiting the program
+       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, ...)
 {
-       if (funct != NULL)
-               last_len = fprintf(stderr, "%s [%d] : Fatal error in %s - ", options.program, getpid(), funct);
-       else
+       
+       if (fmt == NULL)
        {
-               for (int i = 0; i < last_len; ++i)
-                       fprintf(stderr, " ");
-               fprintf(stderr, "Fatal - ");
+               // Fatal error in the Fatal function.
+               // (This really shouldn't happen unless someone does something insanely stupid)
+               Fatal("Fatal", "Format string is NULL");
+               return; // Should never get here
        }
+
+       if (funct == NULL)
+               funct = unspecified_funct;
+
+       fprintf(stderr, "%s [%d] : %s : FATAL - ", g_options.program, getpid(), funct);
+
        va_list va;
        va_start(va, fmt);
        vfprintf(stderr, fmt, va);
index 75e2780..99d54d0 100644 (file)
--- a/rpi/log.h
+++ b/rpi/log.h
@@ -1,16 +1,22 @@
+/**
+ * @file log.h
+ * @purpose Declaration of functions for printing log messages and/or terminating program after a fatal error
+ */
+
 #ifndef _LOG_H
 #define _LOG_H
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdbool.h>
-
 #include <stdarg.h>
 
+
+// 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_print(int level, char * funct, char * fmt,...);
-extern void error(char * funct, char * fmt, ...);
+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).
 
 #endif //_LOG_H
 
diff --git a/rpi/main.c b/rpi/main.c
new file mode 100644 (file)
index 0000000..bb3b5ac
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * @file main.c
+ * @purpose Entry point to the program, starts threads, handles cleanup on program exit
+ */
+
+#define _POSIX_C_SOURCE 200809L // For strsignal to work
+
+// --- Standard headers --- //
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h> // for signal handling
+#include <string.h> // string functions
+
+// --- Custom headers --- //
+#include "log.h"
+#include "options.h"
+
+// --- Variable definitions --- //
+Options g_options; // options passed to program through command line arguments
+
+// --- Function definitions --- //
+
+/**
+ * @funct ParseArguments
+ * @purpose Parse command line arguments, set up an options variable
+ * @param argc - Num args
+ * @param argv - Array of args
+ * @param opts - Pointer to options.  &g_options
+ */
+void ParseArguments(int argc, char ** argv, Options * opts)
+{
+       opts->program = argv[0]; // program name
+       opts->verbosity = LOGDEBUG; // default log level
+       Log(LOGDEBUG, "ParseArguments", "Called as %s with %d arguments.", opts->program, argc);
+}
+
+/**
+ * @funct SignalHandler
+ * @purpose Handle signals
+ * @param sig - The signal
+ */
+void SignalHandler(int sig)
+{
+       // 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.", sig, strsignal(sig));
+       exit(sig);
+}
+
+/**
+ * @funct Cleanup
+ * @purpose Called when program exits
+ */
+void Cleanup()
+{
+       Log(LOGDEBUG, "Cleanup", "Begin cleanup.");
+       Log(LOGDEBUG, "Cleanup", "Finish cleanup.");
+
+}
+
+/**
+ * @funct main
+ * @purpose Main entry point; start worker threads, setup signal handling, wait for threads to exit, exit
+ * @param argc - Num args
+ * @param argv - Args
+ * @returns 0 on success, error code on failure
+ */
+int main(int argc, char ** argv)
+{
+       return 0;
+}
+
+
diff --git a/rpi/network.c b/rpi/network.c
deleted file mode 100644 (file)
index 1a1b862..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "network.h"
-#include <assert.h>
-#include <errno.h>
-#include <sys/select.h>
-#include "log.h"
-
-#define h_addr h_addr_list[0]
-
-
-
-
-
-int Network_get_port(int sfd)
-{
-       static struct sockaddr_in sin;
-       static socklen_t len = sizeof(struct sockaddr_in);
-
-       if (getsockname(sfd, (struct sockaddr *)&sin, &len) != 0)
-                error("Network_port", "getsockname : %s", strerror(errno));
-       return ntohs(sin.sin_port);
-}
-
-int Network_server_bind(int port, int * bound)
-{
-       int sfd = socket(PF_INET, SOCK_STREAM, 0);
-       if (sfd < 0)
-       {
-               error("Network_server", "Creating socket on port %d : %s", port, strerror(errno));
-       }
-
-       struct   sockaddr_in name;
-
-       name.sin_family = AF_INET;
-       name.sin_addr.s_addr = htonl(INADDR_ANY);
-       name.sin_port = htons(port);
-
-       if (bind( sfd, (struct sockaddr *) &name, sizeof(name) ) < 0)
-       {
-               error("Network_server", "Binding socket on port %d : %s", port, strerror(errno));
-       }
-
-       if (bound != NULL)
-               *bound = Network_get_port(sfd);
-       return sfd;     
-}
-
-int Network_server_listen(int sfd, char * addr)
-{
-       int port = Network_get_port(sfd);
-       if (listen(sfd, 1) < 0)
-       {
-               error("Network_server", "Listening on port %d : %s", port, strerror(errno));
-       }
-       
-       int psd;
-       if (addr == NULL)
-               psd = accept(sfd, 0, 0);
-       else
-       {
-               struct  sockaddr_in client;
-               struct  hostent *hp;
-
-               client.sin_family = AF_INET;
-               hp = gethostbyname(addr);
-               bcopy ( hp->h_addr, &(client.sin_addr.s_addr), hp->h_length);
-               client.sin_port = htons(port);
-               socklen_t len = sizeof(client);
-
-               psd = accept(sfd, (struct sockaddr*)&client, &len);
-       }
-       //close(sfd); // don't close the bind socket here; we might want to reuse the port
-       assert(psd >= 0);
-       return psd;
-}
-
-int Network_server(char * addr, int port)
-{
-       int bind = Network_server_bind(port, &port);
-       int sfd = Network_server_listen(bind, addr);
-       close(bind); // won't be able to reuse the port (it goes into TIME_WAIT)
-       return sfd;
-}
-
-int Network_client(const char * addr, int port, int timeout)
-{
-       int sfd = socket(PF_INET, SOCK_STREAM, 0);
-
-       //log_print(2, "Network_client", "Created socket");
-       long arg = fcntl(sfd, F_GETFL, NULL);
-       arg |= O_NONBLOCK;
-       fcntl(sfd, F_SETFL, arg);
-
-       if (sfd < 0)
-       {
-               error("Network_client", "Creating socket for address %s:%d : %s", addr, port, strerror(errno));
-       }
-       struct  sockaddr_in server;
-       struct  hostent *hp;
-
-
-       server.sin_family = AF_INET;
-       hp = gethostbyname(addr);
-       if (hp == NULL)
-       {
-               error("Network_client", "Can't get host by name %s", addr);
-       }
-       bcopy ( hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
-       server.sin_port = htons(port);
-
-
-       int res = connect(sfd, (struct sockaddr *) &server, sizeof(server));
-       
-
-       if (res < 0 && errno == EINPROGRESS)
-       {
-               
-               fd_set writeSet;
-               FD_ZERO(&writeSet);
-               FD_SET(sfd, &writeSet);
-
-               struct timeval tv;
-               tv.tv_sec = timeout;
-               tv.tv_usec = 0;
-
-               struct timeval * tp;
-               tp = (timeout < 0) ? NULL : &tv;
-               
-               int err = select(sfd+1, NULL, &writeSet, NULL, tp);
-               
-               if (err == 0)
-               {
-                       error("Network_client", "Timed out trying to connect to %s:%d after %d seconds", addr, port, timeout);
-               }
-               else if (err < 0)
-               {
-                       error("Network_client", "Connecting to %s:%d - Error in select(2) call : %s", addr, port, strerror(errno));
-               }
-               else if (FD_ISSET(sfd, &writeSet))
-               {
-                       int so_error;
-                       socklen_t len = sizeof so_error;
-                       getsockopt(sfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
-                       if (so_error != 0)
-                       {
-                               error("Network_client", "Connecting to %s:%d : %s", addr, port, strerror(so_error));
-                       }
-               }
-               else
-               {
-                       error("Network_client", "select(2) returned %d but the socket is not writable!?", err);
-               }
-       }
-       else
-       {
-               error("Network_client", "Connecting to %s:%d : %s", addr, port, strerror(errno));
-       }
-
-       arg = fcntl(sfd, F_GETFL, NULL);
-       arg &= (~O_NONBLOCK);
-       fcntl(sfd, F_SETFL, arg);
-       
-       
-       
-       return sfd;
-}
-
-void Network_close(int sfd)
-{
-       if (shutdown(sfd, 2) != 0)
-       {
-               error("Network_close", "Closing socket : %s", strerror(errno));
-       }
-       close(sfd);
-}
diff --git a/rpi/network.h b/rpi/network.h
deleted file mode 100644 (file)
index 07c9459..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _NETWORK_H
-#define _NETWORK_H
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <strings.h>
-#include <stdarg.h>
-
-extern int Network_get_port(int socket); // get port used by socket
-extern int Network_server(char * addr, int port);
-extern int Network_client(const char * addr, int port, int timeout);
-
-extern int Network_server_bind(int port, int * bound);
-extern int Network_server_listen(int sfd, char * addr);
-
-extern void Network_close(int sfd);
-
-#endif //_NETWORK_H
-
-//EOF
index 2a6d323..66cad6c 100644 (file)
@@ -3,18 +3,16 @@
  * @purpose Declaration of structure to handle options passed to program
  */
 
-#include <stdint.h>
+#ifndef _OPTIONS_H
+#define _OPTIONS_H
 
 typedef struct
 {
        const char * program; //name of program
-       uint8_t verbosity; // verbosity level
-       int port; // port to use for webserver
-       int bound_sfd; // socket webserver has bound to
-       int sfd; // socket connected to client
-       
-} Options;
+       int verbosity; // verbosity level
 
+} Options;
 
+extern Options g_options; // global options structure
 
-extern Options options;
+#endif //_OPTIONS_H
diff --git a/rpi/webserver.c b/rpi/webserver.c
deleted file mode 100644 (file)
index 6ff4f46..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/**
- * @file webserver.c
- * @purpose Test implementing a minimalistic webserver
- * 
- */
-
-#define _POSIX_C_SOURCE 200809L // needed for some POSIX stuff to work
-
-// --- Standard headers --- //
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h> // string helper functions
-#include <ctype.h> // character types
-#include <signal.h> // for signal handling
-
-// --- Custom headers --- //
-#include "log.h" // C functions to handle logging
-#include "options.h" // Options structure
-#include "network.h" // C functions to handle low level networking
-
-// --- Variable definitions --- //
-Options options; // declared in "options.h"
-
-// --- Function definitions --- //
-
-/**
- * @funct ParseArguments
- * @purpose Parse Arguments and setup the global options variable
- * @param argc - Num args
- * @param argv - Array of args
- */
-void ParseArguments(int argc, char ** argv)
-{
-       options.program = argv[0];
-       options.verbosity = LOGDEBUG;
-       if (argc > 1)
-               options.port = atoi(argv[1]); // Allow us change the port for testing (I keep getting "address in use" errors)
-       else
-               options.port = 8080; // Using 8080 instead of 80 for now because to use 80 you have to run the program as root
-       options.sfd = -1;
-       options.bound_sfd = -1;
-       log_print(LOGDEBUG, "ParseArguments", "Called as %s with %d arguments.", options.program, argc);
-}
-
-/**
- * @funct SignalHandler
- * @purpose Handle signals
- * @param sig - The signal
- */
-void SignalHandler(int sig)
-{
-       // At the moment just always exit.
-       // Call `exit` so that Cleanup will be called to... clean up.
-       log_print(LOGWARN, "SignalHandler", "Got signal %d (%s). Exiting.", sig, strsignal(sig));
-       exit(sig);
-}
-
-/**
- * @funct Cleanup
- * @purpose Called when program exits
- */
-void Cleanup()
-{
-       log_print(LOGDEBUG, "Cleanup", "Begin cleanup.");
-       if (options.sfd >= 0)
-       {
-               Network_close(options.sfd); // close socket
-               options.sfd = -1;
-       }
-       if (options.bound_sfd >= 0)
-       {
-               Network_close(options.bound_sfd); // unbind
-               options.bound_sfd = -1;
-       }
-       log_print(LOGDEBUG, "Cleanup", "Unbound from port %d successfully", options.port);
-       log_print(LOGDEBUG, "Cleanup", "Done.");
-
-}
-
-
-/**
- * @funct Get
- * @purpose Respond to a GET request
- * @param request - The request string
- * @param sfd - Socket to respond through
- */
-void Get(char * request, int sfd)
-{
-       log_print(LOGDEBUG, "Get", "Got GET request: \"%s\"", request);
-
-       int i = 0;
-       while (!isspace(request[++i]) && request[i] != '\0'); //NOTE: Don't need to check first character
-       request[i] = '\0';
-
-       char response[BUFSIZ];
-       // TODO: Magical low level interfacing stuff!
-
-       int len = sprintf(response, "HTTP/1.1 200 OK\nContent-type: text/html\n\n");
-       write(sfd, response, len);
-       len = 0;
-
-       if (strcmp("/sensor", request) == 0) // dummy test
-       {
-               len = sprintf(response, "SENSOR OFFLINE\n");
-       }
-       else
-       {
-               FILE * f = fopen(request+1, "r");
-               if (f == NULL)
-               {
-                       log_print(LOGWARN, "Get", "File \"%s\" doesn't exist", request+1);
-                       len = sprintf(response, "You requested \"%s\" using GET\n", request);
-               }
-               else
-               {
-                       while (fgets(response, sizeof(response), f) != NULL)
-                       {
-                               write(sfd, response, strlen(response));
-                       }
-               }
-       }
-       if (len > 0)
-               write(sfd, response, len);
-}
-
-/**
- * @funct Post
- * @purpose Respond to a POST request
- * @param request - The request string
- * @param sfd - Socket to respond through
- */
-void Post(char * request, int sfd)
-{
-       log_print(LOGDEBUG, "Post", "Got POST request: \"%s\"", request);
-       int i = 0;
-       while (!isspace(request[++i]) && request[i] != '\0'); //NOTE: Don't need to check first character
-       request[i] = '\0';
-
-       char response[BUFSIZ];
-       int len = sprintf(response, "HTTP/1.1 200 OK\nContent-type: text/html\n\n");
-       write(sfd, response, len);
-       len = 0;
-
-       // TODO: Magical low level interfacing stuff!
-
-
-       if (strcmp("/actuator", request) == 0) // dummy test
-       {
-               len = sprintf(response, "ACTUATOR OFFLINE\n");
-       }
-       else
-       {       
-               len = sprintf(response, "You requested \"%s\" using POST\n", request);
-       }
-       if (len > 0)
-               write(sfd, response, len);
-
-}
-
-/**
- * @funct main
- * @purpose Main program
- * @param argc - Num arguments
- * @param argv - Argument string array
- * @returns error code (0 for no error)
- */
-
-int main(int argc, char ** argv)
-{
-       // Parse Arguments
-       ParseArguments(argc, argv);
-       // Set Cleanup to be called on program exit
-       atexit(Cleanup);
-
-       // Setup signal handlers
-       int signals_to_handle[] = {SIGTERM, SIGINT, SIGHUP, SIGPIPE};
-       for (int i = 0; i < sizeof(signals_to_handle)/sizeof(int); ++i)
-       {
-               int s = signals_to_handle[i];
-               if (signal(s, SignalHandler) == SIG_ERR)
-                       error("main", "Setting signal handler for %d (%s): %s", s, strsignal(s), strerror(errno));
-       }
-
-       // Bind to the port
-       options.bound_sfd = Network_server_bind(options.port, &(options.port));
-       log_print(LOGDEBUG, "main", "Bound to port %d succesfully", options.port);
-
-       while (true)
-       {
-                       // Listen for a client
-                       options.sfd = Network_server_listen(options.bound_sfd, NULL);
-                       
-                       log_print(LOGDEBUG, "main", "Connected to client");
-       
-                       char buffer[BUFSIZ]; //NOTE: Won't be able to respond to requests longer than BUFSIZ
-                       // read a request
-                       int len = read(options.sfd, buffer, sizeof(buffer));
-                       log_print(LOGDEBUG, "main", "Read %d characters. Buffer is \"%s\"", len, buffer);
-
-                       // Parse request
-                       for (int i = 0; i < sizeof(buffer) && buffer[i] != '\0'; ++i)
-                       {
-                               // Look for "GET" or "POST" followed by a whitespace
-                               if (isspace(buffer[i])) // whitespace
-                               {
-                                       while (isspace(buffer[++i]) && buffer[i] != '\0'); // Skip whitespace
-                                       char * req = buffer+i; // set request string
-                               
-                                       buffer[i-1] = '\0'; // terminate request type
-                                       while (buffer[++i] != '\n' && buffer[i] != '\0'); // find next newline
-                                       buffer[i-1] = '\0';
-                                       
-                                       if (strcmp("GET", buffer) == 0) // Compare with "GET"
-                                       {
-                                               Get(req, options.sfd);
-                                       }
-                                       else if (strcmp("POST", buffer) == 0) // Compare with "POST"
-                                       {
-                                               Post(req, options.sfd);
-                                       }
-                                       else // Unknown request
-                                       {
-                                               log_print(LOGWARN, "main", "Unrecognised request type \"%s\" (request \"%s\")", buffer, req);
-                                               char response[] = "Error: Unrecognised request\n";
-                                               write(options.sfd, response, sizeof(response));
-                                       }
-                                       break;
-                               }
-                       }
-
-                       // Close connection
-                       Network_close(options.sfd);
-                       options.sfd = -1;
-                       log_print(LOGDEBUG, "main", "Closed connection to client");
-       }
-
-
-       
-       
-       return 0;
-}
-
-

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