summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c83
1 files changed, 53 insertions, 30 deletions
diff --git a/main.c b/main.c
index 5f8776a..e94230b 100644
--- a/main.c
+++ b/main.c
@@ -42,6 +42,9 @@ struct Message {
struct Context {
struct mosquitto* mosq;
void* messages;
+ char* buffer;
+ size_t size;
+ size_t alloc;
};
static volatile sig_atomic_t g_shutdown;
@@ -56,6 +59,12 @@ static int CompareMessages(const void* a, const void* b) {
((const struct Message*)b)->topic);
}
+static void FreeMessage(void* nodep) {
+ struct Message* message = nodep;
+ free(message->topic);
+ free(message->payload);
+}
+
static bool Flush(int fd, const char* status, const char* type,
const void* body, size_t body_size) {
char buffer[256];
@@ -85,36 +94,54 @@ static bool Flush(int fd, const char* status, const char* type,
return true;
}
+static bool BufferAppend(struct Context* context, const char* data,
+ size_t size) {
+ size_t alloc = context->size + size;
+ if (context->alloc < alloc) {
+ char* buffer = realloc(context->buffer, alloc);
+ if (!buffer) {
+ Log("Failed to reallocate buffer (%s)", strerror(errno));
+ return false;
+ }
+ context->buffer = buffer;
+ context->alloc = alloc;
+ }
+ memcpy(context->buffer + context->size, data, size);
+ context->size += size;
+ return true;
+}
+
static void CollectMatchingMessages(const void* nodep, VISIT which,
void* closure) {
struct {
+ struct Context* context;
const char* topic;
size_t topic_len;
- char* buffer;
- size_t buffer_size;
}* arg = closure;
const struct Message* const* it = nodep;
if (which == preorder || which == endorder ||
strncmp((*it)->topic, arg->topic, arg->topic_len))
return;
- size_t topic_len = strlen((*it)->topic);
- static const char kSep[] = {'<', 'b', 'r', '>'};
- size_t buffer_size = arg->buffer_size + topic_len + sizeof(kSep);
- char* buffer = realloc(arg->buffer, buffer_size);
- if (!buffer) {
- Log("Failed to realloc buffer (%s)", strerror(errno));
- return;
- }
- memcpy(buffer + arg->buffer_size, (*it)->topic, topic_len);
- memcpy(buffer + arg->buffer_size + topic_len, kSep, sizeof(kSep));
- arg->buffer = buffer;
- arg->buffer_size = buffer_size;
+ static const char kPre[] = "<a href=\"/";
+ BufferAppend(arg->context, kPre, strlen(kPre));
+ BufferAppend(arg->context, (*it)->topic, strlen((*it)->topic));
+ static const char kInt[] = "\">/";
+ BufferAppend(arg->context, kInt, strlen(kInt));
+ BufferAppend(arg->context, (*it)->topic, strlen((*it)->topic));
+ static const char kPost[] = "<br>";
+ BufferAppend(arg->context, kPost, strlen(kPost));
}
static bool HandleGetRequest(struct Context* context, int fd,
const char* target) {
if (!strcmp(target, "/favicon.ico"))
return Flush(fd, "404 Not Found", NULL, NULL, 0);
+ struct Message pred = {.topic = UNCONST(target + 1)};
+ struct Message** it = tfind(&pred, &context->messages, CompareMessages);
+ if (it) {
+ return Flush(fd, "200 OK", "application/json", (*it)->payload,
+ (*it)->payloadlen);
+ }
static const char kHeader[] =
"<!DOCTYPE html>"
"<html>"
@@ -126,22 +153,15 @@ static bool HandleGetRequest(struct Context* context, int fd,
"</body>"
"</html>";
struct {
+ struct Context* context;
const char* topic;
size_t topic_len;
- char* buffer;
- size_t buffer_size;
- } arg = {.topic = target + 1,
- .topic_len = strlen(target) - 1,
- .buffer = strdup(kHeader),
- .buffer_size = sizeof(kHeader) - 1};
+ } arg = {context, target + 1, strlen(target) - 1};
+ context->size = 0;
+ if (!BufferAppend(context, kHeader, sizeof(kHeader) - 1)) return false;
twalk_r(context->messages, CollectMatchingMessages, &arg);
- size_t buffer_size = arg.buffer_size + sizeof(kFooter) - 1;
- char* buffer = realloc(arg.buffer, buffer_size);
- memcpy(buffer + arg.buffer_size, kFooter, sizeof(kFooter) - 1);
- bool result =
- Flush(fd, "200 OK", "text/html; charset=utf-8", buffer, buffer_size);
- free(arg.buffer);
- return result;
+ if (!BufferAppend(context, kFooter, sizeof(kFooter) - 1)) return false;
+ return Flush(fd, "200 OK", "text/html", context->buffer, context->size);
}
static bool HandleRequest(void* user, int fd, const char* method,
@@ -157,8 +177,8 @@ static bool HandleRequest(void* user, int fd, const char* method,
(int)body_size, body, 0, false);
if (mosq_errno == MOSQ_ERR_SUCCESS) return Flush(fd, "200 OK", NULL, NULL, 0);
const char* error = mosquitto_strerror(mosq_errno);
- return Flush(fd, "500 Internal Server Error", "text/plain; charset=utf-8",
- error, strlen(error));
+ return Flush(fd, "500 Internal Server Error", "text/plain", error,
+ strlen(error));
}
static void StoreMessagePayload(void** messages,
@@ -225,7 +245,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 Context context = {.mosq = NULL, .messages = NULL};
+ struct Context context;
+ memset(&context, 0, sizeof(struct Context));
struct Server* server = ServerCreate(epfd, HandleRequest, &context);
if (!server) {
Log("Failed to create server");
@@ -305,6 +326,8 @@ rollback_mosquitto_lib_init:
rollback_server_create:
ServerDestroy(server);
rollback_epoll_create:
+ tdestroy(context.messages, FreeMessage);
+ free(context.buffer);
close(epfd);
return result;
}