forked from Telodendria/Telodendria
Bind to socket; HTTP server event thread; signal handling.
This commit is contained in:
parent
46cd0edaf8
commit
e94212b080
6 changed files with 291 additions and 26 deletions
134
src/HttpServer.c
Normal file
134
src/HttpServer.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Jordan Bancino <@jordan:bancino.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <HttpServer.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct HttpServer
|
||||
{
|
||||
int sd;
|
||||
unsigned int nThreads;
|
||||
HttpHandler *requestHandler;
|
||||
void *handlerArgs;
|
||||
|
||||
pthread_t socketThread;
|
||||
|
||||
volatile unsigned int stop:1;
|
||||
volatile unsigned int isRunning:1;
|
||||
};
|
||||
|
||||
HttpServer *
|
||||
HttpServerCreate(int socketDesc, unsigned int nThreads, HttpHandler * requestHandler, void *handlerArgs)
|
||||
{
|
||||
HttpServer *server = malloc(sizeof(HttpServer));
|
||||
|
||||
if (!server)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
server->sd = socketDesc;
|
||||
server->nThreads = nThreads;
|
||||
server->requestHandler = requestHandler;
|
||||
server->handlerArgs = handlerArgs;
|
||||
server->stop = 0;
|
||||
server->isRunning = 0;
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void
|
||||
HttpServerFree(HttpServer * server)
|
||||
{
|
||||
free(server);
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static void *
|
||||
HttpServerEventThread(void *args)
|
||||
{
|
||||
HttpServer *server = (HttpServer *) args;
|
||||
|
||||
server->isRunning = 1;
|
||||
server->stop = 0;
|
||||
|
||||
while (!server->stop)
|
||||
{
|
||||
printf("In server event thread\n");
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
server->isRunning = 0;
|
||||
|
||||
printf("Event thread dying!\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
HttpServerStart(HttpServer * server)
|
||||
{
|
||||
if (!server)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (server->isRunning)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pthread_create(&server->socketThread, NULL, HttpServerEventThread, server) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
HttpServerJoin(HttpServer * server)
|
||||
{
|
||||
if (!server)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_join(server->socketThread, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
HttpServerStop(HttpServer * server)
|
||||
{
|
||||
if (!server)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
server->stop = 1;
|
||||
}
|
|
@ -26,15 +26,35 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <TelodendriaConfig.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <TelodendriaConfig.h>
|
||||
#include <Log.h>
|
||||
#include <HashMap.h>
|
||||
#include <Config.h>
|
||||
#include <HttpServer.h>
|
||||
|
||||
HttpServer *httpServer = NULL;
|
||||
|
||||
static void
|
||||
TelodendriaHttpHandler(HttpRequest * req, HttpResponse * res, void *args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
TelodendriaSignalHandler(int signalNo)
|
||||
{
|
||||
(void) signalNo;
|
||||
HttpServerStop(httpServer);
|
||||
}
|
||||
|
||||
typedef enum ArgFlag
|
||||
{
|
||||
|
@ -73,6 +93,31 @@ TelodendriaPrintUsage(LogConfig * lc)
|
|||
Log(lc, LOG_MESSAGE, " -h Print this usage, then exit.");
|
||||
}
|
||||
|
||||
static int
|
||||
TelodendriaBindSocket(unsigned short port)
|
||||
{
|
||||
struct sockaddr_in remote = {0};
|
||||
int s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (s < 0)
|
||||
{
|
||||
/* Unable to create the socket */
|
||||
return -1;
|
||||
}
|
||||
|
||||
remote.sin_family = AF_INET;
|
||||
remote.sin_port = port;
|
||||
remote.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if (bind(s, (struct sockaddr *) & remote, sizeof(remote)) < 0)
|
||||
{
|
||||
/* Unable to bind the socket */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
@ -96,6 +141,12 @@ main(int argc, char **argv)
|
|||
struct passwd *userInfo;
|
||||
struct group *groupInfo;
|
||||
|
||||
/* Networking */
|
||||
int httpSocket = -1;
|
||||
|
||||
/* Signal handling */
|
||||
struct sigaction sigAction;
|
||||
|
||||
lc = LogConfigCreate();
|
||||
|
||||
if (!lc)
|
||||
|
@ -239,7 +290,7 @@ main(int argc, char **argv)
|
|||
|
||||
Log(lc, LOG_DEBUG, "Configuration:");
|
||||
LogConfigIndent(lc);
|
||||
Log(lc, LOG_DEBUG, "Listen On: %s:%d", tConfig->listenHost, tConfig->listenPort);
|
||||
Log(lc, LOG_DEBUG, "Listen On: %d", tConfig->listenPort);
|
||||
Log(lc, LOG_DEBUG, "Server Name: %s", tConfig->serverName);
|
||||
Log(lc, LOG_DEBUG, "Chroot: %s", tConfig->chroot);
|
||||
Log(lc, LOG_DEBUG, "Run As: %s:%s", tConfig->uid, tConfig->gid);
|
||||
|
@ -248,8 +299,6 @@ main(int argc, char **argv)
|
|||
Log(lc, LOG_DEBUG, "Flags: %x", tConfig->flags);
|
||||
LogConfigUnindent(lc);
|
||||
|
||||
Log(lc, LOG_TASK, "Setting permissions...");
|
||||
|
||||
if (chdir(tConfig->chroot) != 0)
|
||||
{
|
||||
Log(lc, LOG_ERROR, "Unable to change into data directory: %s.", strerror(errno));
|
||||
|
@ -277,6 +326,15 @@ main(int argc, char **argv)
|
|||
Log(lc, LOG_DEBUG, "Found user/group information using getpwnam() and getgrnam().");
|
||||
}
|
||||
|
||||
/* Bind the socket before possibly dropping permissions */
|
||||
httpSocket = TelodendriaBindSocket(tConfig->listenPort);
|
||||
if (httpSocket < 0)
|
||||
{
|
||||
Log(lc, LOG_ERROR, "Unable to bind to port %d: %s", strerror(errno));
|
||||
exit = EXIT_FAILURE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (getuid() == 0)
|
||||
{
|
||||
#ifndef __OpenBSD__
|
||||
|
@ -325,7 +383,50 @@ main(int argc, char **argv)
|
|||
tConfig->uid = NULL;
|
||||
tConfig->gid = NULL;
|
||||
|
||||
Log(lc, LOG_TASK, "Starting server...");
|
||||
|
||||
httpServer = HttpServerCreate(httpSocket, tConfig->threads, TelodendriaHttpHandler, NULL);
|
||||
if (!httpServer)
|
||||
{
|
||||
Log(lc, LOG_ERROR, "Unable to create HTTP server.");
|
||||
exit = EXIT_FAILURE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!HttpServerStart(httpServer))
|
||||
{
|
||||
Log(lc, LOG_ERROR, "Unable to start HTTP server.");
|
||||
exit = EXIT_FAILURE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
Log(lc, LOG_MESSAGE, "Ready.");
|
||||
|
||||
sigAction.sa_handler = TelodendriaSignalHandler;
|
||||
sigfillset(&sigAction.sa_mask);
|
||||
sigAction.sa_flags = SA_RESTART;
|
||||
|
||||
if (sigaction(SIGINT, &sigAction, NULL) < 0)
|
||||
{
|
||||
Log(lc, LOG_ERROR, "Unable to install signal handler.");
|
||||
exit = EXIT_FAILURE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Block this thread until the server is terminated by a signal
|
||||
* handler */
|
||||
HttpServerJoin(httpServer);
|
||||
|
||||
finish:
|
||||
Log(lc, LOG_TASK, "Shutting down...");
|
||||
if (httpSocket > 0)
|
||||
{
|
||||
close(httpSocket);
|
||||
}
|
||||
if (httpServer)
|
||||
{
|
||||
HttpServerFree(httpServer);
|
||||
}
|
||||
Log(lc, LOG_DEBUG, "Exiting with code '%d'.", exit);
|
||||
TelodendriaConfigFree(tConfig);
|
||||
LogConfigFree(lc);
|
||||
|
|
|
@ -95,17 +95,15 @@ TelodendriaConfigParse(HashMap * config, LogConfig * lc)
|
|||
|
||||
if (!directive)
|
||||
{
|
||||
Log(lc, LOG_WARNING, "No 'listen' directive specified; using defaults, which may change.");
|
||||
tConfig->listenHost = UtilStringDuplicate("localhost");
|
||||
Log(lc, LOG_WARNING, "No 'listen' directive specified; using default value, which may change.");
|
||||
tConfig->listenPort = 8008;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_NO_CHILDREN("listen");
|
||||
ASSERT_VALUES("listen", 2);
|
||||
COPY_VALUE(tConfig->listenHost, 0);
|
||||
ASSERT_VALUES("listen", 1);
|
||||
|
||||
tConfig->listenPort = (unsigned short) atoi(ArrayGet(value, 1));
|
||||
tConfig->listenPort = (unsigned short) atoi(ArrayGet(value, 0));
|
||||
if (!tConfig->listenPort)
|
||||
{
|
||||
Log(lc, LOG_ERROR, "Expected numeric value for listen port, got '%s'.", ArrayGet(value, 1));
|
||||
|
@ -316,7 +314,6 @@ TelodendriaConfigFree(TelodendriaConfig * tConfig)
|
|||
return;
|
||||
}
|
||||
|
||||
free(tConfig->listenHost);
|
||||
free(tConfig->serverName);
|
||||
free(tConfig->chroot);
|
||||
free(tConfig->uid);
|
||||
|
|
|
@ -99,18 +99,6 @@ typedef enum HttpStatus
|
|||
HTTP_NETWORK_AUTH_REQUIRED = 511
|
||||
} HttpStatus;
|
||||
|
||||
struct HttpRequest
|
||||
{
|
||||
HttpRequestMethod method;
|
||||
HashMap *headers;
|
||||
};
|
||||
|
||||
struct HttpResponse
|
||||
{
|
||||
HttpStatus status;
|
||||
HashMap *headers;
|
||||
};
|
||||
|
||||
extern char *
|
||||
HttpGetStatusString(const HttpStatus httpStatus);
|
||||
|
||||
|
@ -120,6 +108,4 @@ extern HttpRequestMethod
|
|||
typedef struct HttpRequest HttpRequest;
|
||||
typedef struct HttpResponse HttpResponse;
|
||||
|
||||
typedef void (*HttpHandler) (HttpRequest *, HttpResponse *);
|
||||
|
||||
#endif
|
||||
|
|
48
src/include/HttpServer.h
Normal file
48
src/include/HttpServer.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Jordan Bancino <@jordan:bancino.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef TELODENDRIA_HTTPSERVER_H
|
||||
#define TELODENDRIA_HTTPSERVER_H
|
||||
|
||||
#include <Http.h>
|
||||
|
||||
typedef struct HttpServer HttpServer;
|
||||
|
||||
typedef void (HttpHandler) (HttpRequest *, HttpResponse *, void *);
|
||||
|
||||
extern HttpServer *
|
||||
HttpServerCreate(int, unsigned int, HttpHandler *, void *);
|
||||
|
||||
extern void
|
||||
HttpServerFree(HttpServer *);
|
||||
|
||||
extern int
|
||||
HttpServerStart(HttpServer *);
|
||||
|
||||
extern void
|
||||
HttpServerJoin(HttpServer *);
|
||||
|
||||
extern void
|
||||
HttpServerStop(HttpServer *);
|
||||
|
||||
#endif
|
|
@ -52,14 +52,13 @@ typedef enum TelodendriaConfigFlag
|
|||
*/
|
||||
typedef struct TelodendriaConfig
|
||||
{
|
||||
char *listenHost;
|
||||
unsigned short listenPort;
|
||||
char *serverName;
|
||||
char *chroot;
|
||||
char *uid;
|
||||
char *gid;
|
||||
char *dataDir;
|
||||
|
||||
unsigned short listenPort;
|
||||
unsigned int flags;
|
||||
unsigned int threads;
|
||||
|
||||
|
|
Loading…
Reference in a new issue