Code reorganization
This commit is contained in:
187
src/main.c
187
src/main.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
166
src/setup.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
12
src/swebs/setup.h
Normal 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
|
||||
@@ -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 */
|
||||
|
||||
20
src/util.c
20
src/util.c
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user