Multiple port support
This commit is contained in:
2
Makefile
2
Makefile
@@ -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/
|
||||
|
||||
@@ -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
7
site/https.html
Normal 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>
|
||||
@@ -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
1
site/site/8001.html
Normal file
@@ -0,0 +1 @@
|
||||
<p>Welcome to port 8001!</p>
|
||||
@@ -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
|
||||
|
||||
@@ -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, ¤tTime, 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, ¤tTime) < 0)
|
||||
return 1;
|
||||
if (site->timeout > 0 &&
|
||||
diff(&conn->lastdata, ¤tTime) > site->timeout)
|
||||
if (port->timeout > 0 &&
|
||||
diff(&conn->lastdata, ¤tTime) > port->timeout)
|
||||
return 1;
|
||||
received = recvStream(conn->stream, buff, sizeof(buff));
|
||||
if (received < 0)
|
||||
|
||||
80
src/main.c
80
src/main.c
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
67
src/runner.c
67
src/runner.c
@@ -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;
|
||||
}
|
||||
|
||||
14
src/setup.c
14
src/setup.c
@@ -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);
|
||||
|
||||
|
||||
149
src/sitefile.c
149
src/sitefile.c
@@ -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:
|
||||
|
||||
@@ -66,6 +66,10 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int listenerfd(Listener *listener) {
|
||||
return listener->fd;
|
||||
}
|
||||
|
||||
Context *createContext(SocketType type, ...) {
|
||||
Context *ret;
|
||||
va_list ap;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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);
|
||||
|
||||
30
src/util.c
30
src/util.c
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user