diff options
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 84 |
1 files changed, 58 insertions, 26 deletions
@@ -19,14 +19,26 @@ #include <luajit.h> #include <mosquitto.h> #include <signal.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/epoll.h> +#include <sys/uio.h> #include <unistd.h> #include "logging.h" #include "server.h" +#define UNCONST(op) ((void*)(uintptr_t)(op)) +#define STRIOVEC(op) \ + { .iov_base = UNCONST(op), .iov_len = sizeof(op) - 1 } +#define FLUSHARG(op) \ + { STRIOVEC(op), {.iov_base = NULL, .iov_len = 0}, } + +struct Context { + struct mosquitto* mosq; +}; + static volatile sig_atomic_t g_shutdown; static void OnSignal(int num) { @@ -34,34 +46,53 @@ static void OnSignal(int num) { g_shutdown = 1; } +static bool Flush(int fd, const struct iovec iov[2]) { + // TODO(mburakov): Change to iterative writing. + ssize_t result = writev(fd, iov, 2); + if (result != (ssize_t)(iov[0].iov_len + iov[1].iov_len)) { + Log("Failed to write complete reply (%s)", strerror(errno)); + return false; + } + return true; +} + static bool HandleRequest(void* user, int fd, const char* method, const char* target, const void* body, size_t body_size) { - const char* reply = NULL; + struct Context* context = user; if (strcmp(method, "POST")) { - reply = + static const struct iovec kStatus405[2] = FLUSHARG( "HTTP/1.1 405 Method Not Allowed\r\n" "Content-Length: 0\r\n" - "\r\n"; - } else if (!body_size) { - reply = + "\r\n"); + return Flush(fd, kStatus405); + } + if (!body_size || !target[1]) { + static const struct iovec kStatus400[2] = FLUSHARG( "HTTP/1.1 400 Bad Request\r\n" "Content-Length: 0\r\n" - "\r\n"; - } else { - reply = + "\r\n"); + return Flush(fd, kStatus400); + } + int mosq_errno = mosquitto_publish(context->mosq, NULL, target + 1, + (int)body_size, body, 0, false); + if (mosq_errno == MOSQ_ERR_SUCCESS) { + static const struct iovec kStatus200[2] = FLUSHARG( "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; + "\r\n"); + return Flush(fd, kStatus200); } - return 1; + char buffer[64]; + const char* error = mosquitto_strerror(mosq_errno); + snprintf(buffer, sizeof(buffer), + "HTTP/1.1 500 Internal Server Error\r\n" + "Content-Length: %zu\r\n\r\n", + strlen(error)); + const struct iovec iov[2] = { + {.iov_base = buffer, .iov_len = strlen(buffer)}, + {.iov_base = UNCONST(error), .iov_len = strlen(error)}}; + return Flush(fd, iov); } int main(int argc, char* argv[]) { @@ -72,7 +103,8 @@ int main(int argc, char* argv[]) { 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); + struct Context context; + struct Server* server = ServerCreate(epfd, HandleRequest, &context); if (!server) { Log("Failed to create server"); goto rollback_epoll_create; @@ -83,17 +115,17 @@ int main(int argc, char* argv[]) { mosquitto_strerror(mosq_errno)); goto rollback_server_create; } - struct mosquitto* mosq = mosquitto_new(NULL, true, NULL); - if (!mosq) { + context.mosq = mosquitto_new(NULL, true, NULL); + if (!context.mosq) { Log("Failed to create mosquitto (%s)", strerror(errno)); goto rollback_mosquitto_lib_init; } - mosq_errno = mosquitto_connect(mosq, argv[1], port, 60); + mosq_errno = mosquitto_connect(context.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); + int mosq_sock = mosquitto_socket(context.mosq); if (mosq_sock == -1) { Log("Failed to get mosquitto socket"); goto rollback_mosquitto_connect; @@ -115,7 +147,7 @@ int main(int argc, char* argv[]) { if (errno != EINTR) goto rollback_mosquitto_connect; continue; case 0: - mosq_errno = mosquitto_loop_misc(mosq); + mosq_errno = mosquitto_loop_misc(context.mosq); if (mosq_errno != MOSQ_ERR_SUCCESS) { Log("Failed to loop mosquitto (%s)", mosquitto_strerror(mosq_errno)); goto rollback_mosquitto_connect; @@ -125,7 +157,7 @@ int main(int argc, char* argv[]) { break; } if (ev.data.fd == mosq_sock) { - mosq_errno = mosquitto_loop_read(mosq, 1); + mosq_errno = mosquitto_loop_read(context.mosq, 1); if (mosq_errno != MOSQ_ERR_SUCCESS) { Log("Failed to read mosquitto (%s)", mosquitto_strerror(mosq_errno)); goto rollback_mosquitto_connect; @@ -137,9 +169,9 @@ int main(int argc, char* argv[]) { } result = EXIT_SUCCESS; rollback_mosquitto_connect: - mosquitto_disconnect(mosq); + mosquitto_disconnect(context.mosq); rollback_mosquitto_new: - mosquitto_destroy(mosq); + mosquitto_destroy(context.mosq); rollback_mosquitto_lib_init: mosquitto_lib_cleanup(); rollback_server_create: |
