summaryrefslogtreecommitdiff
path: root/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'server.c')
-rw-r--r--server.c237
1 files changed, 0 insertions, 237 deletions
diff --git a/server.c b/server.c
deleted file mode 100644
index 7f647aa..0000000
--- a/server.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2021 Mikhail Burakov. This file is part of MQhTTp.
- *
- * MQhTTp is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * MQhTTp is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with MQhTTp. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "server.h"
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <search.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include "logging.h"
-#include "uhttp.h"
-
-struct Client {
- int fd;
- struct Uhttp* uhttp;
-};
-
-struct Server {
- int epfd;
- ServerHandler handler;
- void* user;
- int fd;
- void* clients;
-};
-
-static int CompareClients(const void* a, const void* b) {
- int fda = ((const struct Client*)a)->fd;
- int fdb = ((const struct Client*)b)->fd;
- return (fda > fdb) - (fda < fdb);
-}
-
-static void FreeClient(void* nodep) {
- struct Client* client = nodep;
- if (client->uhttp) UhttpDestroy(client->uhttp);
- close(client->fd);
- free(client);
-}
-
-static in_port_t GetPort() {
- static const in_port_t kDefaultPort = 8080;
- const char* http_port = getenv("HTTP_PORT");
- if (!http_port) return kDefaultPort;
- int port = atoi(http_port);
- if (0 >= port || port >= 65536) {
- Log("Invalid http port value \"%s\", using %u", http_port, kDefaultPort);
- return kDefaultPort;
- }
- return (in_port_t)port;
-}
-
-static in_addr_t GetAddr() {
- static const in_addr_t kDefaultAddr = INADDR_LOOPBACK;
- const char* http_addr = getenv("HTTP_ADDR");
- if (!http_addr) return kDefaultAddr;
- in_addr_t addr = inet_addr(http_addr);
- if (addr == INADDR_NONE) {
- Log("Invalid http addr value \"%s\", using loopback", http_addr);
- return kDefaultAddr;
- }
- return ntohl(addr);
-}
-
-static int MakeServerSocket() {
- int sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock == -1) {
- Log("Failed to create socket (%s)", strerror(errno));
- return -1;
- }
- int one = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
- Log("Failed to reuse address (%s)", strerror(errno));
- goto rollback_socket;
- }
- struct sockaddr_in addr = {.sin_family = AF_INET,
- .sin_port = htons(GetPort()),
- .sin_addr.s_addr = htonl(GetAddr())};
- if (bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
- Log("Failed to bind socket (%s)", strerror(errno));
- goto rollback_socket;
- }
- if (listen(sock, SOMAXCONN)) {
- Log("Failed to listen socket (%s)", strerror(errno));
- goto rollback_socket;
- }
- return sock;
-rollback_socket:
- close(sock);
- return -1;
-}
-
-static void AcceptClient(struct Server* server) {
- struct Client* client = calloc(1, sizeof(struct Client));
- if (!client) {
- Log("Failed to allocate client (%s)", strerror(errno));
- return;
- }
- client->fd = accept(server->fd, NULL, NULL);
- if (client->fd == -1) {
- Log("Failed to accept client (%s)", strerror(errno));
- goto rollback_calloc;
- }
- struct epoll_event ev = {.events = EPOLLIN, .data.fd = client->fd};
- if (epoll_ctl(server->epfd, EPOLL_CTL_ADD, client->fd, &ev)) {
- Log("Failed to add client to epoll (%s)", strerror(errno));
- goto rollback_accept;
- }
- struct Client** it = tsearch(client, &server->clients, CompareClients);
- if (!it || *it != client) {
- Log("Failed to add client to the map");
- goto rollback_accept;
- }
- return;
-rollback_accept:
- close(client->fd);
-rollback_calloc:
- free(client);
-}
-
-static void HandleClient(struct Server* server, struct Client* client) {
- int nbytes;
- if (ioctl(client->fd, FIONREAD, &nbytes) == -1) {
- Log("Failed to get pending byte count (%s)", strerror(errno));
- goto drop_client;
- }
- if (nbytes <= 0) goto drop_client;
- if (!client->uhttp) {
- client->uhttp = UhttpCreate();
- if (!client->uhttp) {
- Log("Failed to create uhttp");
- goto drop_client;
- }
- }
- void* buffer = UhttpAllocate(client->uhttp, (size_t)nbytes);
- if (!buffer) {
- Log("Failed to allocate uhttp buffer");
- goto drop_client;
- }
- ssize_t result = read(client->fd, buffer, (size_t)nbytes);
- switch (result) {
- case -1:
- Log("Failed to read client (%s)", strerror(errno));
- __attribute__((fallthrough));
- case 0:
- goto drop_client;
- default:
- break;
- }
- switch (UhttpConsume(client->uhttp, (size_t)result)) {
- case kUhttpResultTerminate:
- Terminate("Heap corruption possible");
- case kUhttpResultFailure:
- Log("Failed to parse request");
- goto drop_client;
- case kUhttpResultWantMore:
- return;
- case kUhttpResultFinished:
- break;
- }
- if (!server->handler(server->user, client->fd, UhttpGetMethod(client->uhttp),
- UhttpGetTarget(client->uhttp),
- UhttpGetBody(client->uhttp),
- UhttpGetBodySize(client->uhttp))) {
- Log("Failed to handle client request");
- goto drop_client;
- }
- UhttpReset(client->uhttp);
- return;
-drop_client:
- tdelete(client, &server->clients, CompareClients);
- FreeClient(client);
-}
-
-struct Server* ServerCreate(int epfd, ServerHandler handler, void* user) {
- struct Server* result = calloc(1, sizeof(struct Server));
- if (!result) {
- Log("Failed to allocate server (%s)", strerror(errno));
- return NULL;
- }
- result->epfd = epfd;
- result->handler = handler;
- result->user = user;
- result->fd = MakeServerSocket();
- if (result->fd == -1) {
- Log("Failed to create server socket");
- goto rollback_calloc;
- }
- struct epoll_event ev = {.events = EPOLLIN, .data.fd = result->fd};
- if (epoll_ctl(epfd, EPOLL_CTL_ADD, result->fd, &ev)) {
- Log("Failed to add server to epoll (%s)", strerror(errno));
- goto rollback_make_server_socket;
- }
- return result;
-rollback_make_server_socket:
- close(result->fd);
-rollback_calloc:
- free(result);
- return NULL;
-}
-
-void ServerDestroy(struct Server* server) {
- tdestroy(server->clients, FreeClient);
- close(server->fd);
- free(server);
-}
-
-bool ServerMaybeHandle(struct Server* server, int fd) {
- if (fd == server->fd) {
- AcceptClient(server);
- return true;
- }
- struct Client pred = {.fd = fd};
- struct Client** it = tfind(&pred, &server->clients, CompareClients);
- if (!it) return false;
- HandleClient(server, *it);
- return true;
-}