Multiple port support

This commit is contained in:
Nate Choe
2022-06-21 23:34:13 -05:00
parent dc044b22e3
commit 47cf044858
19 changed files with 333 additions and 136 deletions

View File

@@ -2,7 +2,7 @@ SRC = $(wildcard src/*.c)
OBJ = $(subst .c,.o,$(subst src,work,$(SRC)))
LIBS = gnutls
LDFLAGS = -pie -lrt -ldl $(shell pkg-config --libs $(LIBS))
CFLAGS := -O2 -pipe -Wall -Wpedantic -Wshadow -ansi -D_XOPEN_SOURCE=500
CFLAGS := -O2 -pipe -Wall -Wpedantic -Wshadow -ansi -D_XOPEN_SOURCE=500 -ggdb
CFLAGS += -Isrc/ -fpie -D_POSIX_C_SOURCE=200809L $(shell pkg-config --cflags $(LIBS))
INSTALLDIR := /usr/sbin
HEADERDIR := /usr/include/

View File

@@ -16,6 +16,10 @@ sitefiles also allow comments with #
* ```read [http path] [file path]``` - if the requested path matches ```[http path]```, return the contents of ```[file path]```. If [file path] is a directory, then the http path is appended to [file path] and that is read instead.
* ```linked``` - Run getResponse() from the library loaded from the library global variable
* ```throw [http path] [error code]``` - If the requested path matches ```[http path]```, send back the http error code ```[error code]```. For standardization purposes, these error codes are just the number.
* ```declare [transport] [port]``` - Declares that port ```[port]``` will be used with transport ```[transport]``` where ```[transport]``` is one of ```TCP```, ```TLS```
* ```key [key file] [port]``` - Sets the key file for port ```[port]``` to ```[key file]```
* ```cert [cert file] [port]``` - Sets the certificate file for port ```[port]``` to ```[cert file]```
* ```timeout [timeout] [port]``` - Sets the connection timeout for port ```[port]``` to ```[timeout]``` milliseconds
##### Other than set, commands should take in a regex as argument 1 and operate on a file specified in argument 2.
@@ -25,14 +29,8 @@ sitefiles also allow comments with #
* GET (defualt)
* POST
* ```host``` - The hostname to respond to. Case insensitive regex, default: .*
* ```port``` - The port to respond to, default: 80
# Part 4: Global variables
* ```port``` - the port to use. Note that this is a global variable, and so one instance of swebs cannot use multiple ports.
* ```transport``` - the type of connection to use. One of:
* TCP (default)
* TLS
* ```key``` - The filepath of the private key to use if transport == TLS
* ```cert``` - The filepath of the certificate to use if transport == TLS
* ```timeout``` - The amount of time to wait for data before closing the connection in ms. A timeout of 0 means to wait infinitely. (default: 2000)
* ```library``` - the path of a library that is linked in during runtime if ```DYNAMIC_LINKED_PAGES```is set.

7
site/https.html Normal file
View File

@@ -0,0 +1,7 @@
<!DOCTYPE html>
<html>
<body>
<p>You are a brave soul for trusting a self signed HTTPS
certificate. Don't do it again.</p>
</body>
</html>

View File

@@ -1,3 +1,3 @@
#!/bin/sh
../build/swebs -p swebs.pid -s sitefile -o logs -b 100 -j2
../build/swebs -p swebs.pid -s sitefile -o /dev/stdout -b 100 -j2

1
site/site/8001.html Normal file
View File

@@ -0,0 +1 @@
<p>Welcome to port 8001!</p>

View File

@@ -1,21 +1,49 @@
define port 8000
declare TCP 8000
declare TLS 8001
# We will use ports 8000 and 8001 with TCP and TLS respectively
key domain.key 8001
cert domain.crt 8001
# Port 8001 can have TLS, but it's self signed and very bad.
timeout 2000 8000
timeout 2000 8001
# Set these values for the ports
set port 8000
# The following pages will respond to port 8000
define transport TLS
define transport TCP
define key domain.key
define cert domain.crt
define timeout 2000
define library ./library.so
# Library calls should use ./library.so
set host localhost:8000
# The following pages will respond to the host localhost:8000
read / site/index.html
# The path / should be read from site/index.html
read /hello site/hello.html
# The path /hello should be read from site/hello.html
throw /blog/forbidden 403
# The path /blog/forbidden should throw error code 403
read /blog/.* site/blog/
#/blog/2021-1-25.html turns into site/blog//blog/2021-1-25.html
# /blog/2021-1-25.html turns into site/blog//blog/2021-1-25.html
linked /library
# The path /library should be dynamically loaded from the library (library.so)
set host 127.0.0.1:8000
# The following pages will respond to the host 127.0.0.1:8000
read / site/easteregg.html
# The path / should be read from site/easteregg.html
read /egg.png site/egg.png
# The path /egg.png should be read from site/egg.png
set host .*
# The following pages will respond to all hosts (regex)
read /alldomains site/alldomains.html
# The path /alldomains should be read from /site/alldomains.html
set port 8001
# The following pages will respond to port 8001
read / site/8001.html
# The path / should be read from site/8001.html

View File

@@ -27,7 +27,7 @@
#include <swebs/responses.h>
#include <swebs/connections.h>
int newConnection(Stream *stream, Connection *ret) {
int newConnection(Stream *stream, Connection *ret, int portind) {
struct timespec currentTime;
ret->stream = stream;
@@ -68,6 +68,8 @@ int newConnection(Stream *stream, Connection *ret) {
return 1;
}
memcpy(&ret->lastdata, &currentTime, sizeof(struct timespec));
ret->portind = portind;
return 0;
}
@@ -360,10 +362,11 @@ int updateConnection(Connection *conn, Sitefile *site) {
ssize_t received;
unsigned long i;
struct timespec currentTime;
const Port *port = site->ports + conn->portind;
if (clock_gettime(CLOCK_MONOTONIC, &currentTime) < 0)
return 1;
if (site->timeout > 0 &&
diff(&conn->lastdata, &currentTime) > site->timeout)
if (port->timeout > 0 &&
diff(&conn->lastdata, &currentTime) > port->timeout)
return 1;
received = recvStream(conn->stream, buff, sizeof(buff));
if (received < 0)

View File

@@ -20,6 +20,7 @@
#include <stdarg.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
@@ -41,11 +42,11 @@ typedef struct {
static Runner *runners;
static int processes;
static int mainfd;
static int *pending;
static Listener *listener;
static Sitefile *site;
static int mainfd; /* fd of the UNIX socket */
static struct sockaddr_un addr;
static ConnInfo *conninfo;
/* We want to be able to handle a signal at any time, so some global variables
* are needed. */
static const int signals[] = {
@@ -54,7 +55,6 @@ static const int signals[] = {
};
static void exitClean(int signal) {
freeListener(listener);
close(mainfd);
remove(addr.sun_path);
exit(EXIT_SUCCESS);
@@ -109,14 +109,16 @@ static void createProcess(int id) {
unsetsignal(SIGCHLD);
connfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (connfd < 0)
if (connfd < 0) {
createErrorLog("socket() failed, killing child", errno);
exit(EXIT_FAILURE);
}
if (connect(connfd, (struct sockaddr *) &addr, sizeof(addr))) {
createErrorLog("connect() failed, killing child", errno);
exit(EXIT_FAILURE);
}
close(mainfd);
runServer(connfd, site, listener, pending, id);
runServer(connfd, site, pending, id, conninfo);
createLog("child runServer() finished");
exit(EXIT_SUCCESS);
}
@@ -138,8 +140,24 @@ static void remakeChild(int signal) {
int main(int argc, char **argv) {
int i;
int pendingid;
int backlog;
int conninfoid;
Listener **listeners;
struct pollfd *pollfds;
setup(argc, argv, &site, &listener, &processes);
setup(argc, argv, &site, &processes, &backlog);
listeners = xmalloc(site->portcount * sizeof *listeners);
pollfds = xmalloc(site->portcount * sizeof *pollfds);
for (i = 0; i < site->portcount; ++i) {
listeners[i] = createListener(site->ports[i].num, backlog);
if (listeners[i] == NULL) {
fprintf(stderr, "Failed to listen on port %hu\n",
site->ports[i].num);
}
pollfds[i].fd = listenerfd(listeners[i]);
pollfds[i].events = POLLIN;
}
pendingid = smalloc(sizeof(int) * (processes - 1));
if (pendingid < 0) {
@@ -151,6 +169,18 @@ int main(int argc, char **argv) {
createErrorLog("saddr() failed", errno);
exit(EXIT_FAILURE);
}
conninfoid = smalloc(sizeof *conninfo);
if (conninfoid < 0) {
createErrorLog("smalloc() failed", errno);
exit(EXIT_FAILURE);
}
conninfo = saddr(conninfoid);
if (conninfo == NULL) {
createErrorLog("saddr() failed", errno);
exit(EXIT_FAILURE);
}
memset(pending, 0, sizeof(int) * (processes - 1));
mainfd = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -175,25 +205,29 @@ int main(int argc, char **argv) {
createLog("swebs started");
for (;;) {
int fd;
int lowestProc;
fd = acceptConnection(listener);
if (fd < 0) {
if (errno == ENOTSOCK || errno == EOPNOTSUPP ||
errno == EINVAL) {
createErrorLog("You've majorly screwed up. Good luck",
errno);
exit(EXIT_FAILURE);
}
continue;
if (poll(pollfds, site->portcount, -1) < 0) {
if (errno == EINTR)
continue;
createErrorLog("You've majorly screwed up. Good luck",
errno);
exit(EXIT_FAILURE);
}
createLog("Accepted stream");
lowestProc = 0;
for (i = 1; i < processes - 1; i++)
if (pending[i] < pending[lowestProc])
lowestProc = i;
sendFd(fd, runners[lowestProc].fd);
for (i = 0; i < site->portcount; ++i) {
if (pollfds[i].revents & POLLIN) {
int j, lowestproc, fd;
fd = acceptConnection(listeners[i]);
while (conninfo->valid) ;
lowestproc = 0;
for (j = 0; j < processes - 1; j++)
if (pending[j] < pending[lowestproc])
lowestproc = j;
conninfo->portind = i;
conninfo->valid = 1;
sendFd(fd, runners[lowestproc].fd);
}
}
}
}

View File

@@ -31,33 +31,42 @@
#include <swebs/sitefile.h>
#include <swebs/connections.h>
void runServer(int connfd, Sitefile *site, Listener *listener,
int *pending, int id) {
void runServer(int connfd, Sitefile *site, int *pending, int id,
ConnInfo *conninfo) {
int allocConns = 100;
struct pollfd *fds = malloc(sizeof(struct pollfd) * allocConns);
Connection *connections = malloc(sizeof(Connection) * allocConns);
int connCount = 1;
/* connections are 1 indexed because fds[0] is the notify fd. */
Context *context;
assert(fds != NULL);
assert(connections != NULL);
struct pollfd *fds;
Connection *connections;
int connCount;
Context **contexts;
int i;
connCount = 1;
fds = xmalloc(allocConns * sizeof *fds);
connections = xmalloc(allocConns * sizeof *connections);
fds[0].fd = connfd;
fds[0].events = POLLIN;
/* connections are 1 indexed because fds[0] is the notify fd. I hate
* that poll() forces us to do these hacks. */
switch (site->type) {
case TCP:
context = createContext(TCP);
break;
case TLS:
context = createContext(TLS, site->key, site->cert);
break;
default:
createLog("Socket type is somehow invalid");
return;
}
if (context == NULL) {
createErrorLog("Failed to create context", errno);
exit(EXIT_FAILURE);
contexts = xmalloc(site->portcount * sizeof *contexts);
for (i = 0; i < site->portcount; ++i) {
Port *port = site->ports + i;
switch (port->type) {
case TCP:
contexts[i] = createContext(TCP);
break;
case TLS:
contexts[i] = createContext(TLS, port->key, port->cert);
break;
default:
createLog("Socket type is somehow invalid");
return;
}
if (contexts[i] == NULL) {
createErrorLog("Failed to create context", errno);
exit(EXIT_FAILURE);
}
}
{
@@ -78,7 +87,6 @@ void runServer(int connfd, Sitefile *site, Listener *listener,
}
for (;;) {
int i;
poll(fds, connCount, -1);
{
char log[200];
@@ -105,17 +113,22 @@ remove:
if (fds[0].revents & POLLIN) {
Stream *newstream;
int newfd;
int portind;
newfd = recvFd(connfd);
if (newfd < 0) {
createLog("Message received that included an invalid fd");
continue;
}
while (conninfo->valid == 0) ;
portind = conninfo->portind;
conninfo->valid = 0;
createLog("Obtained file descriptor from child");
newstream = createStream(context, O_NONBLOCK, newfd);
newstream = createStream(contexts[portind], O_NONBLOCK, newfd);
if (newstream == NULL) {
createLog("Stream couldn't be created from file descriptor");
createLog(
"Stream couldn't be created from file descriptor");
close(newfd);
continue;
}
@@ -141,7 +154,7 @@ remove:
connections = newconns;
}
if (newConnection(newstream, connections + connCount)) {
if (newConnection(newstream, connections + connCount, portind)) {
createLog("Couldn't initialize connection from stream");
continue;
}

View File

@@ -58,15 +58,15 @@ static void printLongMessage(char *first, ...) {
va_end(ap);
}
void setup(int argc, char **argv,
Sitefile **site, Listener **listener, int *processes) {
void setup(int argc, char **argv, Sitefile **site, int *processes,
int *backlog) {
char *logout = "/var/log/swebs.log";
char *sitefile = NULL;
int backlog = 100;
char shouldDaemonize = 0;
char *pidfile = "/run/swebs.pid";
*processes = sysconf(_SC_NPROCESSORS_ONLN) + 1;
*backlog = 100;
for (;;) {
int c = getopt(argc, argv, "o:j:s:b:c:Bp:hl");
@@ -83,7 +83,7 @@ void setup(int argc, char **argv,
sitefile = optarg;
break;
case 'b':
backlog = atoi(optarg);
*backlog = atoi(optarg);
break;
case 'B':
shouldDaemonize = 1;
@@ -139,12 +139,6 @@ NULL
exit(EXIT_FAILURE);
}
*listener = createListener((*site)->port, backlog);
if (*listener == NULL) {
fprintf(stderr, "Failed to create socket\n");
exit(EXIT_FAILURE);
}
if (shouldDaemonize)
daemonize(pidfile);

View File

@@ -175,40 +175,46 @@ error:
}
Sitefile *parseSitefile(char *path) {
FILE *file = fopen(path, "r");
FILE *file;
RequestType respondto = GET;
const int cflags = REG_EXTENDED | REG_ICASE;
char *host = NULL;
int argc;
char **argv;
int allocatedLength = 50;
char gotPort = 0;
Sitefile *ret;
unsigned short currport;
currport = 80;
file = fopen(path, "r");
if (file == NULL)
return NULL;
ret = malloc(sizeof(Sitefile));
if (ret == NULL)
return NULL;
ret->type = TCP;
ret->key = NULL;
ret->cert = NULL;
ret->timeout = 2000;
ret = xmalloc(sizeof *ret);
ret->size = 0;
ret->content = malloc(allocatedLength * sizeof(SiteCommand));
ret->alloc = 50;
ret->content = xmalloc(ret->alloc * sizeof *ret->content);
ret->portcount = 0;
ret->portalloc = 5;
ret->ports = xmalloc(ret->portalloc * sizeof *ret->ports);
#if DYNAMIC_LINKED_PAGES
ret->getResponse = NULL;
#endif
if (ret->content == NULL) {
free(ret);
return NULL;
}
for (;;) {
ReturnCode status = getCommand(file, &argc, &argv);
switch (status) {
int i;
case FILE_END:
if (!gotPort)
goto nterror;
for (i = 0; i < ret->portcount; ++i) {
Port *port = ret->ports + i;
if (port->type == TLS &&
(port->key == NULL ||
port->cert == NULL)) {
fprintf(stderr,
"Port %hu declared as TLS without proper TLS files\n", port->num);
goto nterror;
}
}
fclose(file);
return ret;
case ERROR: case LINE_END:
@@ -225,7 +231,9 @@ Sitefile *parseSitefile(char *path) {
goto error;
}
else if (strcmp(argv[1], "host") == 0)
host = strdup(argv[2]);
host = xstrdup(argv[2]);
else if (strcmp(argv[1], "port") == 0)
currport = atoi(argv[2]);
else
goto error;
continue;
@@ -233,31 +241,12 @@ Sitefile *parseSitefile(char *path) {
else if (strcmp(argv[0], "define") == 0) {
if (argc < 3)
goto error;
if (strcmp(argv[1], "transport") == 0) {
if (strcmp(argv[2], "TCP") == 0)
ret->type = TCP;
else if (strcmp(argv[2], "TLS") == 0)
ret->type = TLS;
else
goto error;
}
else if (strcmp(argv[1], "port") == 0) {
ret->port = atoi(argv[2]);
gotPort = 1;
}
else if (strcmp(argv[1], "key") == 0)
ret->key = strdup(argv[2]);
else if (strcmp(argv[1], "cert") == 0)
ret->cert = strdup(argv[2]);
else if (strcmp(argv[1], "timeout") == 0)
ret->timeout = atoi(argv[2]);
else if (strcmp(argv[1], "library") == 0) {
#if DYNAMIC_LINKED_PAGES
ret->getResponse = loadGetResponse(argv[2]);
#else
fprintf(stderr,
"This version of swebs has no dynamic page support\n"
);
fputs(
"This version of swebs has no dynamic page support\n", stderr);
exit(EXIT_FAILURE);
#endif
}
@@ -265,11 +254,69 @@ Sitefile *parseSitefile(char *path) {
goto error;
continue;
}
if (ret->size >= allocatedLength) {
else if (strcmp(argv[0], "declare") == 0) {
Port newport;
int i;
if (argc < 3) {
fputs(
"Usage: declare [transport] [port]\n", stderr);
goto error;
}
newport.num = atoi(argv[2]);
for (i = 0; i < ret->portcount; ++i) {
if (ret->ports[i].num == newport.num) {
fprintf(stderr,
"Port %hu declared multiple times\n", newport.num);
goto error;
}
}
if (strcmp(argv[1], "TCP") == 0)
newport.type = TCP;
else if (strcmp(argv[1], "TLS") == 0)
newport.type = TLS;
else {
fprintf(stderr, "Invalid transport %s\n",
argv[1]);
goto error;
}
newport.timeout = 2000;
newport.key = newport.cert = NULL;
if (ret->portcount >= ret->portalloc) {
ret->portalloc *= 2;
ret->ports = xrealloc(ret->ports,
ret->portalloc * sizeof *ret->ports);
}
memcpy(ret->ports + ret->portcount, &newport,
sizeof newport);
++ret->portcount;
continue;
}
#define PORT_ATTRIBUTE(name, func) \
else if (strcmp(argv[0], #name) == 0) { \
int i; \
unsigned short port; \
if (argc < 3) { \
fputs("Usage: " #name " [" #name "] [port]\n", \
stderr); \
goto error; \
} \
port = atoi(argv[2]); \
for (i = 0; i < ret->portcount; ++i) \
if (ret->ports[i].num == port) \
ret->ports[i].name = func(argv[1]); \
continue; \
}
PORT_ATTRIBUTE(key, xstrdup)
PORT_ATTRIBUTE(cert, xstrdup)
PORT_ATTRIBUTE(timeout, atoi)
#undef PORT_ATTRIBUTE
if (ret->size >= ret->alloc) {
SiteCommand *newcontent;
allocatedLength *= 2;
newcontent = realloc(ret->content,
allocatedLength * sizeof(SiteCommand));
ret->alloc *= 2;
newcontent = realloc(ret->content, ret->alloc *
sizeof *newcontent);
if (newcontent == NULL)
goto error;
ret->content = newcontent;
@@ -282,7 +329,7 @@ Sitefile *parseSitefile(char *path) {
if (strcmp(argv[0], "read") == 0) {
if (argc < 3)
goto error;
ret->content[ret->size].arg = strdup(argv[2]);
ret->content[ret->size].arg = xstrdup(argv[2]);
if (ret->content[ret->size].arg == NULL)
goto error;
ret->content[ret->size].command = READ;
@@ -295,16 +342,26 @@ Sitefile *parseSitefile(char *path) {
goto error;
ret->content[ret->size].command = THROW;
}
else if (strcmp(argv[0], "linked") == 0)
else if (strcmp(argv[0], "linked") == 0) {
#if DYNAMIC_LINKED_PAGES
ret->content[ret->size].command = LINKED;
else
#else
fputs(
"This version of swebs doesn't have linked page support", stderr);
goto error;
#endif
}
else {
fprintf(stderr, "Unknown sitefile command %s", argv[0]);
goto error;
}
freeTokens(argc, argv);
ret->content[ret->size].respondto = respondto;
if (host == NULL)
regcomp(&ret->content[ret->size].host, ".*", cflags);
else
regcomp(&ret->content[ret->size].host, host, cflags);
ret->content[ret->size].port = currport;
ret->size++;
}
error:

View File

@@ -66,6 +66,10 @@ error:
return NULL;
}
int listenerfd(Listener *listener) {
return listener->fd;
}
Context *createContext(SocketType type, ...) {
Context *ret;
va_list ap;

View File

@@ -57,6 +57,8 @@ typedef struct Connection {
/* persistent */
size_t currLineAlloc;
size_t currLineLen;
int portind;
} Connection;
/*
* The 2 types of fields:
@@ -65,7 +67,7 @@ typedef struct Connection {
* request, path, body
* */
int newConnection(Stream *stream, Connection *ret);
int newConnection(Stream *stream, Connection *ret, int portind);
/* returns non-zero on error. */
void resetConnection(Connection *conn);
void freeConnection(Connection *conn);

View File

@@ -23,6 +23,14 @@
#include <swebs/sitefile.h>
#include <swebs/connections.h>
void runServer(int connfd, Sitefile *site, Listener *listener,
int *pending, int id);
typedef struct {
int valid;
int portind;
} ConnInfo;
void runServer(int connfd, Sitefile *site, int *pending, int id,
ConnInfo *info);
/* pending and info are shared memory. pending[id] is the amount of connections
* that are being processed by that process, and info contains info about the
* connection being sent through. */
#endif

View File

@@ -21,8 +21,8 @@
#include <swebs/sockets.h>
#include <swebs/sitefile.h>
void setup(int argc, char **argv,
Sitefile **site, Listener **listener, int *processes);
void setup(int argc, char **argv, Sitefile **site, int *processes,
int *backlog);
/* Setup parses args, utilizes them, and returns only what is needed in the
* main loop. */

View File

@@ -28,22 +28,33 @@ typedef enum {
LINKED
} Command;
typedef struct {
SocketType type;
unsigned short num;
int timeout;
char *key;
char *cert;
/* key and cert are possible unused */
} Port;
typedef struct {
RequestType respondto;
regex_t host;
Command command;
regex_t path;
char *arg;
unsigned short port;
} SiteCommand;
typedef struct {
int size;
size_t size;
size_t alloc;
SiteCommand *content;
SocketType type;
char *key;
char *cert;
int timeout;
unsigned short port;
size_t portcount;
size_t portalloc;
Port *ports;
#if DYNAMIC_LINKED_PAGES
int (*getResponse)(Request *, Response *);
#endif

View File

@@ -45,6 +45,7 @@ typedef struct {
int initTLS();
Listener *createListener(uint16_t port, int backlog);
int listenerfd(Listener *listener);
Context *createContext(SocketType type, ...);
/*
* extra arguments depend on type (similar to fcntl):

View File

@@ -28,6 +28,12 @@ void *saddr(int id);
void sfree(void *addr);
void sdestroy(int id);
void *xmalloc(size_t size);
void *xrealloc(void *ptr, size_t size);
char *xstrdup(char *str);
/* These functions should only be used during setup (reading sitefiles and such)
* and not real runtime. */
int createLog(char *msg);
int createErrorLog(char *msg, int err);
int istrcmp(char *s1, char *s2);

View File

@@ -57,6 +57,36 @@ void sdestroy(int id) {
shmctl(id, IPC_RMID, 0);
}
void *xmalloc(size_t size) {
void *ret;
ret = malloc(size);
if (ret == NULL) {
fputs("xmalloc() failed\n", stderr);
exit(EXIT_FAILURE);
}
return ret;
}
void *xrealloc(void *ptr, size_t size) {
void *ret;
ret = realloc(ptr, size);
if (ret == NULL) {
fputs("xrealloc() failed\n", stderr);
exit(EXIT_FAILURE);
}
return ret;
}
char *xstrdup(char *str) {
char *ret;
ret = strdup(str);
if (ret == NULL) {
fputs("xstrdup() failed\n", stderr);
exit(EXIT_FAILURE);
}
return ret;
}
int createLog(char *msg) {
time_t currenttime;
struct tm *timeinfo;