summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Linehan <patientulysses@gmail.com>2012-06-18 13:38:23 -0400
committerJason Linehan <patientulysses@gmail.com>2012-06-18 13:38:23 -0400
commitcc775383eda32741875d9d37e7cceb95da58e285 (patch)
tree6a98f743c7ee93fa7ea3773b33cb56159a1bbc58
parent313aa4bbcbcb1101ef16a3588b37bf625498eb71 (diff)
downloadcloth-cc775383eda32741875d9d37e7cceb95da58e285.tar.gz
cloth-cc775383eda32741875d9d37e7cceb95da58e285.tar.bz2
cloth-cc775383eda32741875d9d37e7cceb95da58e285.zip
Firms up log module, removes http_status.h
-rw-r--r--Makefile2
-rw-r--r--cloth.c43
-rw-r--r--http_status.h53
-rw-r--r--log.c224
-rw-r--r--log.h70
5 files changed, 189 insertions, 203 deletions
diff --git a/Makefile b/Makefile
index a06cb83..c981227 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ LDFLAGS=-pg
# gprof
#
-SOURCES=cloth.c textutils.c
+SOURCES=cloth.c log.c textutils.c
OBJECTS=$(SOURCES:.c=.o)
EXECUTABLE=cloth
diff --git a/cloth.c b/cloth.c
index 759bdbb..eabcba6 100644
--- a/cloth.c
+++ b/cloth.c
@@ -9,10 +9,11 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
+#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "textutils.h"
-#include "http_status.h"
+#include "log.h"
/*
* accept() makes use of the restrict keyword
@@ -30,9 +31,6 @@
/* Message printed on illegal argument usage. */
#define HELP_MESSAGE "usage: cloth <PORT> <WWW-DIRECTORY>\n"
-/* Type of message to be printed in the log. */
-/*enum log_genre { OOPS=42, WARN, INFO };*/
-
/*
@@ -69,12 +67,8 @@ struct ext_t supported_ext[]={
char www_path[BUFSIZE];
-
-
-
-
/******************************************************************************
- * HTTP
+ * HELPERS
* The main functions called by the child process when a request is made
* on the socket being listened to by the server.
******************************************************************************/
@@ -96,7 +90,10 @@ inline char *get_file_extension(char *buf, size_t buflen)
}
-struct sockaddr_in *copyaddr(struct sockaddr_in *addr)
+/**
+ * copyaddr -- allocate and return a copy of a sockaddr_in structure
+ */
+inline struct sockaddr_in *copyaddr(struct sockaddr_in *addr)
{
struct sockaddr_in *new;
@@ -109,6 +106,12 @@ struct sockaddr_in *copyaddr(struct sockaddr_in *addr)
return new;
}
+
+/******************************************************************************
+ * HTTP
+ * The main functions called by the child process when a request is made
+ * on the socket being listened to by the server.
+ ******************************************************************************/
/**
* web -- child web process that gets forked (so we can exit on error)
* @fd : socket file descriptor
@@ -116,7 +119,7 @@ struct sockaddr_in *copyaddr(struct sockaddr_in *addr)
*/
void web(int fd_socket, struct sockaddr_in *remote, int hit)
{
- struct session_t sess;
+ struct ses_t session;
static char request[BUFSIZE];
char *buf;
int fd_file;
@@ -128,7 +131,7 @@ void web(int fd_socket, struct sockaddr_in *remote, int hit)
**********************************************/
/* Read the request from the socket into the buffer */
if (ret = read(fd_socket, request, BUFSIZE), ret <= 0 || ret >= BUFSIZE)
- log(BAD_REQUEST, &sess, "");
+ log(BAD_REQUEST, &session, "");
/* Nul-terminate the buffer. */
request[ret] = '\0';
@@ -139,9 +142,9 @@ void web(int fd_socket, struct sockaddr_in *remote, int hit)
*buf = '*';
}
- session_info(&sess, fd_socket, remote, request);
+ sesinfo(&session, fd_socket, remote, request);
- log(ACCEPT, &sess, "");
+ log(ACCEPT, &session, "");
/**********************************************
@@ -149,7 +152,7 @@ void web(int fd_socket, struct sockaddr_in *remote, int hit)
**********************************************/
/* Only the GET operation is allowed */
if (strncmp(request, "GET ", 4) && strncmp(request, "get ", 4))
- log(BAD_METHOD, &sess, "Only GET supported");
+ log(BAD_METHOD, &session, "Only GET supported");
/* Truncate the request after the filename being requested */
for (buf=&request[4]; *buf; buf++) {
@@ -158,7 +161,7 @@ void web(int fd_socket, struct sockaddr_in *remote, int hit)
/* Catch any illegal relative pathnames (..) */
if (strstr(request, ".."))
- log(BAD_REQUEST, &sess, "Relative paths not supported");
+ log(BAD_REQUEST, &session, "Relative paths not supported");
/* In the absence of an explicit filename, default to index.html */
if (!strncmp(request, "GET /\0", 6) || !strncmp(request, "get /\0", 6))
@@ -166,13 +169,13 @@ void web(int fd_socket, struct sockaddr_in *remote, int hit)
/* Scan for filename extensions and check against valid ones. */
if (fstr = get_file_extension(request, strlen(request)), fstr == NULL)
- log(NO_METHOD, &sess, "file extension not supported");
+ log(NO_METHOD, &session, "file extension not supported");
/* Open the requested file */
if ((fd_file = open(&request[5], O_RDONLY)) == -1)
- log(ERROR, &sess, "failed to open file");
+ log(ERROR, &session, "failed to open file");
- log(RESPONSE, &sess, "");
+ log(RESPONSE, &session, "");
/**********************************************
@@ -196,7 +199,7 @@ void web(int fd_socket, struct sockaddr_in *remote, int hit)
free(remote);
#ifdef LINUX
- sleep(1); /* to allow socket to drain */
+ sleep(1); // allow socket to drain
#endif
exit(1);
}
diff --git a/http_status.h b/http_status.h
deleted file mode 100644
index 571a0f7..0000000
--- a/http_status.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef __HTTP_STATUS_H
-#define __HTTP_STATUS_H
-
-
-struct http_status {
- short code;
- short http;
- const char *figure;
-};
-
-
-#define OUCH 42
-#define WARN 43
-#define INFO 46
-
-
-#define HTTP_OK 200
-#define HTTP_ACCEPTED 202
-
-#define HTTP_BAD_REQUEST 400
-#define HTTP_NOT_FOUND 404
-#define HTTP_METHOD_FORBIDDEN 405
-#define HTTP_HEADER_OVERFLOW 431
-#define HTTP_SERVER_ERROR 500
-#define HTTP_NOT_IMPLEMENTED 501
-
-#define HTTP_FATAL_ERROR 555
-
-enum codes {
- RESPONSE,
- ACCEPT,
- BAD_REQUEST,
- NOT_FOUND,
- BAD_METHOD,
- OVERFLOW,
- ERROR,
- NO_METHOD,
- FATAL
-};
-
-static struct http_status STATUS[]={
- { INFO, HTTP_OK, "--->" }, /* RESPONSE */
- { INFO, HTTP_ACCEPTED, "<---" }, /* ACCEPT */
- { WARN, HTTP_BAD_REQUEST, "x---" }, /* BAD_REQUEST */
- { WARN, HTTP_NOT_FOUND, "?---" }, /* NOT_FOUND */
- { WARN, HTTP_METHOD_FORBIDDEN, "x---" }, /* BAD_METHOD */
- { WARN, HTTP_HEADER_OVERFLOW, "+---" }, /* OVERFLOW */
- { WARN, HTTP_SERVER_ERROR, "---x" }, /* ERROR */
- { WARN, HTTP_NOT_IMPLEMENTED, "---?" }, /* NO_METHOD */
- { OUCH, HTTP_FATAL_ERROR, "xxxx" }, /* FATAL */
-};
-
-#endif
diff --git a/log.c b/log.c
index a35dc57..44d613a 100644
--- a/log.c
+++ b/log.c
@@ -1,8 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
+#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -10,98 +12,36 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include "textutils.h"
-#include "http_status.h"
+#include "log.h"
+
/* Default path of the log file (relative to -d) */
#define LOG_PATH "cloth.log"
+#define INFO_PATH "cloth.info"
-/* strf format strings */
+/* strftime format strings */
#define COMMON_LOG_TIME "%d/%b/%Y:%H:%M:%S %z"
#define ISO_TIME "%Y-%m-%d %H:%M:%S"
-#define ISO_LEN 24
-
-/******************************************************************************
- * LOGS
- *
- * { code, file, hostname, verb, remote_addr, remote_port, time, message }
- *
- * code
- * ````
- * START - the server is starting up
- * STOP - the server is shutting down
- * INFO - standard entry which indicates an action
- * WARN - an action has failed
- * OUCH - an unrecoverable error has occured
- *
- * file
- * ````
- * The filename of the source being requested
- *
- * hostname
- * ````````
- * myserver.mydomain.org
- * 42.112.5.25.some.isp.net.
- *
- * The address or domain name specified by the remote host. Because
- * different names may resolve to the same address, this field will
- * specifically reflect the label that the *remote host* is using to
- * contact your server.
- *
- * verb
- * ````
- * The nature of the interaction between the local and remote hosts,
- * being one of the 9 HTTP methods ("verbs"). The 9 methods are HEAD,
- * GET, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, and PATCH.
- *
- * cloth only supports the GET routine, for simplicity.
- *
- * remote_addr
- * ```````````
- * IPv4 address of the remote client.
- *
- * remote_port
- * ```````````
- * Port number of the remote client.
- * time
- * ````
- * The time at which the request was processed by the server.
- * Time is formatted in ISO format: yyyy-mm-dd HH:mm:ss
- *
- * message
- * ```````
- * An optional plaintext message, e.g. explaining an error context or
- * specifying the user agent of the remote host.
- *
- ******************************************************************************/
/******************************************************************************
* SESSION INFORMATION
*
- * A session is identified in the log by a set of 6 values:
+ * A session collects the 7 values that are unique to each new connection
+ * over a socket:
*
* 0. socket - the outbound socket being communicated over
- * 1. host - hostname given by remote client (resolves to local ip)
- * 2. agent - the user-agent id of the remote client
- * 3. resource - the file requested by the remote client
- * 4. remote_addr - the address of the remote client
- * 5. remote_port - the port of the remote client
+ * 1. time - the current time as a formatted string
+ * 2. host - hostname given by remote client (resolves to local ip)
+ * 3. agent - the user-agent id of the remote client
+ * 4. resource - the file requested by the remote client
+ * 5. remote_addr - the address of the remote client
+ * 6. remote_port - the port of the remote client
+ *
+ * It also contains a 'buffer' member to accomodate the formatted string
+ * produced from the 7 values above, which will be an element in the log.
*
******************************************************************************/
-/*
- * Session structure
- */
-struct ses_t {
- int socket; // File descriptor of the socket
- char *host; // Hostname submitted by remote end
- char *agent; // Remote user-agent id
- char *resource; // Resource (file) being requested
- char *remote_addr; // Address of the remote host
- char time[ISO_LEN]; // Formatted time of processing
- unsigned short remote_port; // Port of the remote host
-};
-
-
/**
* sesinfo_http -- Insert parsed HTTP request into the session struct
* @session: the uninitialized session struct
@@ -111,9 +51,9 @@ struct ses_t {
*/
void sesinfo_http(struct ses_t *session, char *request)
{
- char *copy; // copy of HTTP request
- char *token; // tokenized substring of copy
- char *clean; // cleaned-up version of token
+ char *copy; // copy of HTTP request
+ char *token; // tokenized substring of copy
+ char *clean; // cleaned-up version of token
copy = bdup(request);
@@ -158,7 +98,25 @@ inline void sesinfo_addr(struct ses_t *session, struct sockaddr_in *remote)
*/
inline void sesinfo_time(struct ses_t *session, time_t time)
{
- strftime(session->time, LOGBUF, ISO_TIME, gmtime(&time));
+ strftime(session->time, ISO_LEN, ISO_TIME, gmtime(&time));
+}
+
+
+/**
+ * sesprep -- Write a formatted string containing session information
+ * @session: previously-initialized session struct
+ * @status : the status code
+ */
+inline void sesprep(struct ses_t *session, struct http_status *status)
+{
+ pumpf(&session->buffer, "%s: %s %s %s %s:%hu (%s)",
+ status->tag,
+ session->resource,
+ session->host,
+ status->figure,
+ session->remote_addr,
+ session->remote_port,
+ session->time);
}
@@ -171,75 +129,87 @@ inline void sesinfo_time(struct ses_t *session, time_t time)
*/
void sesinfo(struct ses_t *session, int socket, struct sockaddr_in *remote, char *request)
{
- sesinfo_http(session, request); // get resource, host, agent
- sesinfo_addr(session, remote); // get remote_addr, remote_port
- session->socket = socket; // get socket descriptor
+ sesinfo_http(session, request); // get resource, host, agent
+ sesinfo_addr(session, remote); // get remote_addr, remote_port
+ sesinfo_time(session, time(NULL)); // get formatted time
+ session->socket = socket; // get socket descriptor
}
+/******************************************************************************
+ * WRITE
+ * Functions to write to the log and to write over the open socket.
+ ******************************************************************************/
+/**
+ * write_log -- Write a char buffer to the designated LOG_PATH
+ * @buffer: string to be written to log file
+ */
+void write_log(const char *path, const char *buffer)
+{
+ int fd;
+ if ((fd = open(path, O_CREAT| O_WRONLY | O_APPEND, 0644)) >= 0) {
+ write(fd, buffer, strlen(buffer));
+ write(fd, "\n", 1);
+ close(fd);
+ }
+}
-
-
-char *new_entry(struct http_status *status, struct session_t *session)
+/**
+ * write_socket -- Write a buffer, including an HTTP error code, over a socket
+ * @socket: socket file descriptor
+ * @code : HTTP status code
+ * @buffer: message to be printed over socket
+ */
+void write_socket(int socket, int http_code, const char *message)
{
- char *timebuf;
char *buffer;
+ pumpf(&buffer, "cloth says: %hd %s\r", http_code, message);
- timebuf = malloc(LOGBUF * sizeof(char));
- time_info(timebuf, time(NULL));
+ /* Check that socket is a valid file descriptor */
+ if (fcntl(socket, F_GETFD) == EBADF)
+ log(WARN, NULL, "Socket write failure");
+ else
+ write(socket, buffer, strlen(buffer));
- pumpf(&buffer, "%s %s %s %s:%hu (%s)",
- session->resource,
- session->host,
- status->figure,
- session->remote_addr,
- session->remote_port,
- timebuf);
-
- free(timebuf);
-
- return buffer;
+ free(buffer);
}
-void log(int code, struct session_t *session, char *msg)
+/******************************************************************************
+ * LOG
+ * Entry point for outside callers seeking to write to the log.
+ ******************************************************************************/
+/**
+ * log -- write a message to the log file and/or over a socket
+ * @code: the cloth status code
+ * @session: an initialized session struct
+ * @message: an additional explanatory message
+ */
+void log(int code, struct ses_t *session, char *message)
{
- char *entry;
- char *buf;
- int fd;
+ char *buffer;
- if (session != NULL)
- entry = new_entry(&STATUS[code], session);
+ if (session) {
+ sesprep(session, &STATUS[code]);
+ pumpf(&buffer, "%s", session->buffer);
+ } else
+ pumpf(&buffer, "%s: %s (%d)", STATUS[code].tag, message, errno);
+
+ write_log(LOG_PATH, buffer); // All codes get written to the log
switch (STATUS[code].code)
{
case INFO:
- pumpf(&buf, "INFO: %s %s", entry, msg);
+ free(buffer);
break;
case OUCH:
- pumpf(&buf, "OUCH: %s (%d)", msg, errno);
+ exit(3);
break;
case WARN:
- pumpf(&buf, "cloth says: %hd %s\r", STATUS[code].code, msg);
- write(session->socket, buf, strlen(buf));
- pumpf(&buf, "WARN: %s (%hd)", entry, STATUS[code].http);
+ write_socket(session->socket, STATUS[code].code, message);
+ exit(3);
break;
}
-
- /* Write the log buffer to the log file */
- if ((fd = open(LOG_PATH, O_CREAT| O_WRONLY | O_APPEND, 0644)) >= 0) {
- write(fd, buf, strlen(buf));
- write(fd, "\n", 1);
- close(fd);
- }
-
- if (session != NULL)
- free(entry);
-
- free(buf);
-
- if (STATUS[code].code == OUCH || STATUS[code].code == WARN)
- exit(3);
}
diff --git a/log.h b/log.h
index cdf8953..0e0e6bf 100644
--- a/log.h
+++ b/log.h
@@ -1,7 +1,73 @@
#ifndef __HTTP_LOG_H
#define __HTTP_LOG_H
-struct ses_t _session_fref;
+/* Collects multiple representations of a status. */
+struct http_status {
+ char *tag;
+ short code;
+ short http;
+ const char *figure;
+};
+
+
+/* cloth internal status code classes */
+#define OUCH 42 // unrecoverable error
+#define WARN 43 // failure
+#define INFO 46 // normal operation
+
+
+/* HTTP status codes */
+#define HTTP_OK 200
+#define HTTP_ACCEPTED 202
+#define HTTP_BAD_REQUEST 400
+#define HTTP_NOT_FOUND 404
+#define HTTP_METHOD_FORBIDDEN 405
+#define HTTP_HEADER_OVERFLOW 431
+#define HTTP_SERVER_ERROR 500
+#define HTTP_NOT_IMPLEMENTED 501
+#define HTTP_FATAL_ERROR 555
+
+
+/* cloth status codes */
+enum codes { RESPONSE, ACCEPT, BAD_REQUEST, NOT_FOUND, BAD_METHOD, OVERFLOW,
+ ERROR, NO_METHOD, FATAL };
+
+
+/* status codes are indices into the global STATUS vector */
+static struct http_status STATUS[]={
+ { "INFO", INFO, HTTP_OK, "--->" }, // RESPONSE
+ { "INFO", INFO, HTTP_ACCEPTED, "<---" }, // ACCEPT
+ { "WARN", WARN, HTTP_BAD_REQUEST, "x---" }, // BAD_REQUEST
+ { "WARN", WARN, HTTP_NOT_FOUND, "?---" }, // NOT_FOUND
+ { "WARN", WARN, HTTP_METHOD_FORBIDDEN, "x---" }, // BAD_METHOD
+ { "WARN", WARN, HTTP_HEADER_OVERFLOW, "+---" }, // OVERFLOW
+ { "WARN", WARN, HTTP_SERVER_ERROR, "---x" }, // ERROR
+ { "WARN", WARN, HTTP_NOT_IMPLEMENTED, "---?" }, // NO_METHOD
+ { "OUCH", OUCH, HTTP_FATAL_ERROR, "xxxx" }, // FATAL
+};
+
+
+#define ISO_LEN 24
+
+
+/* Session structure */
+struct ses_t {
+ int socket; // File descriptor of the socket
+ char time[ISO_LEN]; // Formatted time of processing
+ char *host; // Hostname submitted by remote end
+ char *agent; // Remote user-agent id
+ char *resource; // Resource (file) being requested
+ char *remote_addr; // Address of the remote host
+ unsigned short remote_port; // Port of the remote host
+ char *buffer; // The formatted output string
+};
+
+
+/* Function prototypes */
+void log(int code, struct ses_t *session, char *message);
+void sesinfo(struct ses_t *, int, struct sockaddr_in *, char *);
+
+
+#endif
-void log(int code, struct ses_t *session, char *msg);