summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..9b5c666
--- /dev/null
+++ b/main.c
@@ -0,0 +1,150 @@
+/*
+ * 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 <errno.h>
+#include <luajit.h>
+#include <mosquitto.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "logging.h"
+#include "server.h"
+
+static volatile sig_atomic_t g_shutdown;
+
+static void OnSignal(int num) {
+ (void)num;
+ g_shutdown = 1;
+}
+
+static bool HandleRequest(void* user, int fd, const char* method,
+ const char* target, const void* body,
+ size_t body_size) {
+ const char* reply = NULL;
+ if (strcmp(method, "POST")) {
+ reply =
+ "HTTP/1.1 405 Method Not Allowed\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n";
+ } else if (!body_size) {
+ reply =
+ "HTTP/1.1 400 Bad Request\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n";
+ } else {
+ reply =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n";
+ }
+ // TODO(mburakov): Change to iterative writing.
+ size_t length = strlen(reply);
+ ssize_t result = write(fd, reply, length);
+ if (result != (ssize_t)length) {
+ Log("Failed to write complete reply (%s)", strerror(errno));
+ return 0;
+ }
+ return 1;
+}
+
+int main(int argc, char* argv[]) {
+ if (argc < 3) Terminate("Usage: %s <host> <port>", argv[0]);
+ int port = atoi(argv[2]);
+ if (0 >= port || port >= 65536)
+ Terminate("Invalid mosquitto port \"%s\"", argv[2]);
+ int epfd = epoll_create(1);
+ if (epfd == -1) Terminate("Failed to create epoll (%s)", strerror(errno));
+ int result = EXIT_FAILURE;
+ struct Server* server = ServerCreate(epfd, HandleRequest, NULL);
+ if (!server) {
+ Log("Failed to create server");
+ goto rollback_epoll_create;
+ }
+ int mosq_errno = mosquitto_lib_init();
+ if (mosq_errno != MOSQ_ERR_SUCCESS) {
+ Log("Failed to initialize mosquitto lib (%s)",
+ mosquitto_strerror(mosq_errno));
+ goto rollback_server_create;
+ }
+ struct mosquitto* mosq = mosquitto_new(NULL, true, NULL);
+ if (!mosq) {
+ Log("Failed to create mosquitto (%s)", strerror(errno));
+ goto rollback_mosquitto_lib_init;
+ }
+ mosq_errno = mosquitto_connect(mosq, argv[1], port, 60);
+ if (mosq_errno != MOSQ_ERR_SUCCESS) {
+ Log("Failed to connect mosquitto (%s)", mosquitto_strerror(mosq_errno));
+ goto rollback_mosquitto_new;
+ }
+ int mosq_sock = mosquitto_socket(mosq);
+ if (mosq_sock == -1) {
+ Log("Failed to get mosquitto socket");
+ goto rollback_mosquitto_connect;
+ }
+ struct epoll_event ev = {.events = EPOLLIN, .data.fd = mosq_sock};
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, mosq_sock, &ev)) {
+ Log("Failed to add mosquitto to epoll (%s)", strerror(errno));
+ goto rollback_mosquitto_connect;
+ }
+ static const struct sigaction sa = {.sa_handler = OnSignal};
+ if (sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL)) {
+ Log("Failed to set up signal handlers (%s)", strerror(errno));
+ goto rollback_mosquitto_connect;
+ }
+ while (!g_shutdown) {
+ switch (epoll_wait(epfd, &ev, 1, 1000)) {
+ case -1:
+ Log("Failed to wait epoll (%s)", strerror(errno));
+ if (errno != EINTR) goto rollback_mosquitto_connect;
+ continue;
+ case 0:
+ mosq_errno = mosquitto_loop_misc(mosq);
+ if (mosq_errno != MOSQ_ERR_SUCCESS) {
+ Log("Failed to loop mosquitto (%s)", mosquitto_strerror(mosq_errno));
+ goto rollback_mosquitto_connect;
+ }
+ continue;
+ default:
+ break;
+ }
+ if (ev.data.fd == mosq_sock) {
+ mosq_errno = mosquitto_loop_read(mosq, 1);
+ if (mosq_errno != MOSQ_ERR_SUCCESS) {
+ Log("Failed to read mosquitto (%s)", mosquitto_strerror(mosq_errno));
+ goto rollback_mosquitto_connect;
+ }
+ continue;
+ }
+ if (!ServerMaybeHandle(server, ev.data.fd))
+ Terminate("Stray socket in epoll");
+ }
+ result = EXIT_SUCCESS;
+rollback_mosquitto_connect:
+ mosquitto_disconnect(mosq);
+rollback_mosquitto_new:
+ mosquitto_destroy(mosq);
+rollback_mosquitto_lib_init:
+ mosquitto_lib_cleanup();
+rollback_server_create:
+ ServerDestroy(server);
+rollback_epoll_create:
+ close(epfd);
+ return result;
+}