Code reorganization

This commit is contained in:
Nate Choe
2022-03-30 17:39:55 -05:00
parent 266a087655
commit 26c0eaca15
7 changed files with 241 additions and 160 deletions

View File

@@ -18,200 +18,75 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <pwd.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <swebs/util.h>
#include <swebs/setup.h>
#include <swebs/runner.h>
#include <swebs/sockets.h>
#include <swebs/sitefile.h>
static void daemonize(char *pidfile) {
pid_t pid;
FILE *pidout;
pid = fork();
switch (pid) {
case -1:
exit(EXIT_FAILURE);
case 0:
break;
default:
pidout = fopen(pidfile, "w");
fprintf(pidout, "%d\n", pid);
fclose(pidout);
exit(EXIT_SUCCESS);
}
if (setsid() < 0)
exit(EXIT_FAILURE);
}
static void printLongMessage(char *first, ...) {
va_list ap;
va_start(ap, first);
puts(first);
for (;;) {
char *nextarg = va_arg(ap, char *);
if (nextarg == NULL)
break;
puts(nextarg);
}
va_end(ap);
}
int main(int argc, char **argv) {
char *logout = "/var/log/swebs.log";
char *sitefile = NULL;
int processes = sysconf(_SC_NPROCESSORS_ONLN) + 1;
int backlog = 100;
char shouldDaemonize = 0;
char *pidfile = "/run/swebs.pid";
Sitefile *site;
Listener *listener;
int processes;
int *pending, (*notify)[2];
int *pending, pendingid, (*notify)[2];
pthread_t *threads;
int i;
for (;;) {
int c = getopt(argc, argv, "o:j:s:b:c:Bp:hl");
if (c == -1)
break;
switch (c) {
case 'o':
logout = optarg;
break;
case 'j':
processes = atoi(optarg);
break;
case 's':
sitefile = optarg;
break;
case 'b':
backlog = atoi(optarg);
break;
case 'B':
shouldDaemonize = 1;
break;
case 'p':
pidfile = optarg;
break;
case 'l':
printLongMessage(
"swebs Copyright (C) 2022 Nate Choe",
"This is free software, and you are welcome to redistribute under certain",
"conditions, but comes with ABSOLUTELY NO WARRANTY. For more details see the",
"GNU General Public License Version 3\n",
"This program dynamically links with:",
" gnutls (gnutls.org)\n",
setup(argc, argv, &site, &listener, &processes);
"For any complaints, email me at natechoe9@gmail.com",
"I'm a programmer not a lawyer, so there's a good chance I accidentally",
"violated the LGPL.",
NULL
);
exit(EXIT_SUCCESS);
case 'h':
printLongMessage(
"Usage: swebs [options]",
" -o [out] Set the log file (default: /var/log/swebs.log)",
" -j [cores] Use that many cores (default: $(nproc)+1)",
" -s [site file] Use that site file (required)",
" -b [backlog] Set the socket backlog (default: 100)",
" -B Run swebs in the background and daemonize",
" -p [pidfile] Specify PID file if daemonizing",
" (defualt: /run/swebs.pid)",
" -l Show some legal details",
" -h Show this help message",
NULL
);
exit(EXIT_SUCCESS);
case '?':
fprintf(stderr, "-h for help\n");
exit(EXIT_FAILURE);
}
}
if (sitefile == NULL) {
fprintf(stderr, "No sitefile configured\n");
pendingid = smalloc(sizeof(int) * (processes - 1));
if (pendingid < 0) {
createLog("smalloc() failed");
exit(EXIT_FAILURE);
}
site = parseSitefile(sitefile);
if (site == NULL) {
fprintf(stderr, "Invalid sitefile %s\n", sitefile);
pending = saddr(pendingid);;
if (pending == NULL) {
createLog("saddr() failed");
exit(EXIT_FAILURE);
}
memset(pending, 0, sizeof(int) * (processes - 1));
switch (site->type) {
case TCP: default:
listener = createListener(TCP, site->port, backlog);
break;
case TLS:
initTLS();
listener = createListener(TLS, site->port, backlog,
site->key, site->cert);
break;
}
if (listener == NULL) {
fprintf(stderr, "Failed to create socket\n");
exit(EXIT_FAILURE);
}
if (shouldDaemonize)
daemonize(pidfile);
if (initLogging(logout)) {
fprintf(stderr, "Couldn't open logs file %s\n", logout);
exit(EXIT_FAILURE);
}
{
struct passwd *swebs, *root;
swebs = getpwnam("swebs");
if (swebs == NULL)
createLog("Couldn't find swebs user");
else
if (seteuid(swebs->pw_uid))
createLog("seteuid() failed");
root = getpwnam("root");
if (root == NULL) {
createLog("Couldn't find root user, quitting");
exit(EXIT_FAILURE);
}
if (geteuid() == root->pw_uid) {
createLog("swebs should not be run as root");
exit(EXIT_FAILURE);
}
}
signal(SIGPIPE, SIG_IGN);
pending = calloc(processes - 1, sizeof(int));
notify = malloc(sizeof(int[2]) * (processes - 1));
threads = malloc(sizeof(pthread_t) * (processes - 1));
if (threads == NULL)
if (notify == NULL) {
createLog("malloc() failed");
exit(EXIT_FAILURE);
}
threads = malloc(sizeof(pthread_t) * (processes - 1));
if (threads == NULL) {
createLog("malloc() failed");
exit(EXIT_FAILURE);
}
for (i = 0; i < processes - 1; i++) {
RunnerArgs *args = malloc(sizeof(RunnerArgs));
if (args == NULL)
if (args == NULL) {
createLog("malloc() failed");
exit(EXIT_FAILURE);
if (pipe(notify[i]))
}
if (pipe(notify[i])) {
createLog("pipe() failed");
exit(EXIT_FAILURE);
}
args->site = site;
args->pending = pending;
args->pendingid = pendingid;
args->notify = notify[i][0];
args->id = i;
pthread_create(threads + i, NULL,
(void*(*)(void*)) runServer, args);
}
signal(SIGPIPE, SIG_IGN);
createLog("swebs started");
for (;;) {
@@ -228,7 +103,7 @@ NULL
if (pending[i] < pending[lowestThread])
lowestThread = i;
if (write(notify[lowestThread][1], &stream, sizeof(&stream))
< sizeof(&stream))
< sizeof(&stream))
continue;
}

View File

@@ -30,7 +30,7 @@
void *runServer(RunnerArgs *args) {
Sitefile *site = args->site;
int *pending = args->pending;
int *pending = saddr(args->pendingid);
int notify = args->notify;
int id = args->id;
@@ -62,7 +62,7 @@ void *runServer(RunnerArgs *args) {
remove:
freeConnection(connections + i);
connCount--;
memcpy(fds + i, fds + connCount,
memcpy(fds + i, fds + connCount - 1,
sizeof(struct pollfd));
memcpy(connections + i, fds + connCount,
sizeof(struct pollfd));

166
src/setup.c Normal file
View File

@@ -0,0 +1,166 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <pwd.h>
#include <unistd.h>
#include <swebs/util.h>
#include <swebs/setup.h>
static void daemonize(char *pidfile) {
pid_t pid;
FILE *pidout;
pid = fork();
switch (pid) {
case -1:
exit(EXIT_FAILURE);
case 0:
break;
default:
pidout = fopen(pidfile, "w");
fprintf(pidout, "%d\n", pid);
fclose(pidout);
exit(EXIT_SUCCESS);
}
if (setsid() < 0)
exit(EXIT_FAILURE);
}
static void printLongMessage(char *first, ...) {
va_list ap;
va_start(ap, first);
puts(first);
for (;;) {
char *nextarg = va_arg(ap, char *);
if (nextarg == NULL)
break;
puts(nextarg);
}
va_end(ap);
}
void setup(int argc, char **argv,
Sitefile **site, Listener **listener, int *processes) {
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;
for (;;) {
int c = getopt(argc, argv, "o:j:s:b:c:Bp:hl");
if (c == -1)
break;
switch (c) {
case 'o':
logout = optarg;
break;
case 'j':
*processes = atoi(optarg);
break;
case 's':
sitefile = optarg;
break;
case 'b':
backlog = atoi(optarg);
break;
case 'B':
shouldDaemonize = 1;
break;
case 'p':
pidfile = optarg;
break;
case 'l':
printLongMessage(
"swebs Copyright (C) 2022 Nate Choe",
"This is free software, and you are welcome to redistribute under certain",
"conditions, but comes with ABSOLUTELY NO WARRANTY. For more details see the",
"GNU General Public License Version 3\n",
"This program dynamically links with:",
" gnutls (gnutls.org)\n",
"For any complaints, email me at natechoe9@gmail.com",
"I'm a programmer not a lawyer, so there's a good chance I accidentally",
"violated the LGPL.",
NULL
);
exit(EXIT_SUCCESS);
case 'h':
printLongMessage(
"Usage: swebs [options]",
" -o [out] Set the log file (default: /var/log/swebs.log)",
" -j [cores] Use that many cores (default: $(nproc)+1)",
" -s [site file] Use that site file (required)",
" -b [backlog] Set the socket backlog (default: 100)",
" -B Run swebs in the background and daemonize",
" -p [pidfile] Specify PID file if daemonizing",
" (defualt: /run/swebs.pid)",
" -l Show some legal details",
" -h Show this help message",
NULL
);
exit(EXIT_SUCCESS);
case '?':
fprintf(stderr, "-h for help\n");
exit(EXIT_FAILURE);
}
}
if (sitefile == NULL) {
fprintf(stderr, "No sitefile configured\n");
exit(EXIT_FAILURE);
}
*site = parseSitefile(sitefile);
if (site == NULL) {
fprintf(stderr, "Invalid sitefile %s\n", sitefile);
exit(EXIT_FAILURE);
}
switch ((*site)->type) {
case TCP: default:
*listener = createListener(TCP, (*site)->port, backlog);
break;
case TLS:
initTLS();
*listener = createListener(TLS, (*site)->port, backlog,
(*site)->key, (*site)->cert);
break;
}
if (listener == NULL) {
fprintf(stderr, "Failed to create socket\n");
exit(EXIT_FAILURE);
}
if (shouldDaemonize)
daemonize(pidfile);
if (initLogging(logout)) {
fprintf(stderr, "Couldn't open logs file %s\n", logout);
exit(EXIT_FAILURE);
}
{
struct passwd *swebs, *root;
swebs = getpwnam("swebs");
if (swebs == NULL)
createLog("Couldn't find swebs user");
else
if (seteuid(swebs->pw_uid))
createLog("seteuid() failed");
root = getpwnam("root");
if (root == NULL) {
createLog("Couldn't find root user, quitting");
exit(EXIT_FAILURE);
}
if (geteuid() == root->pw_uid) {
createLog("swebs should not be run as root");
exit(EXIT_FAILURE);
}
}
}

View File

@@ -24,7 +24,8 @@
typedef struct {
Sitefile *site;
int *pending;
int pendingid;
/* int *pending */
/*
* pending[thread id] = the number of connections being handled by that
* thread
@@ -32,7 +33,7 @@ typedef struct {
int notify;
/*
* When this runner should accept a connection, notify will contain an
* int ready to be read.
* int ready to be read. notify is an fd
* */
int id;
} RunnerArgs;

12
src/swebs/setup.h Normal file
View File

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

View File

@@ -21,6 +21,13 @@
#include <swebs/types.h>
int initLogging(char *path);
int smalloc(size_t size);
/* returns an id passed to saddr, or -1 on error */
void *saddr(int id);
void sfree(void *addr);
void sdestroy(int id);
int createLog(char *msg);
int istrcmp(char *s1, char *s2);
/* case insensitive strcmp */

View File

@@ -20,6 +20,9 @@
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <swebs/util.h>
#include <swebs/types.h>
@@ -30,6 +33,23 @@ int initLogging(char *path) {
return logs == NULL;
}
int smalloc(size_t size) {
return shmget(IPC_PRIVATE, size,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
}
void *saddr(int id) {
return shmat(id, NULL, 0);
}
void sfree(void *addr) {
shmdt(addr);
}
void sdestroy(int id) {
shmctl(id, IPC_RMID, 0);
}
int createLog(char *msg) {
time_t currenttime;
struct tm *timeinfo;