diff options
Diffstat (limited to 'chatty.h')
-rw-r--r-- | chatty.h | 220 |
1 files changed, 50 insertions, 170 deletions
@@ -1,7 +1,8 @@ -#ifndef CHATTY_IMPL +#ifndef CHATTY_H #include <assert.h> #include <locale.h> +#include <stdarg.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> @@ -11,6 +12,7 @@ #include <sys/mman.h> #include <sys/socket.h> #include <time.h> +#include <unistd.h> #include <wchar.h> typedef uint8_t u8; @@ -28,13 +30,54 @@ typedef enum { // port for chatty #define PORT 9983 +// max number of bytes that can be logged at once +#define LOGMESSAGE_MAX 2048 +#define LOG_FMT "%H:%M:%S " +#define LOG_LEN 10 #define Kilobytes(Value) ((Value) * 1024) #define Megabytes(Value) (Kilobytes(Value) * 1024) #define Gigabytes(Value) (Megabytes((u64)Value) * 1024) #define Terabytes(Value) (Gigabytes((u64)Value) * 1024) #define PAGESIZE 4096 +#define local_persist static +#define global_variable +#define internal static +global_variable s32 logfd; + +u32 +wstrlen(u32* str) +{ + u32 i = 0; + while (str[i] != 0) + i++; + return i; +} + +void +loggingf(char* format, ...) +{ + char buf[LOGMESSAGE_MAX]; + va_list args; + va_start(args, format); + + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + + int n = 0; + while (*(buf + n) != 0) n++; + + u64 t = time(0); + u8 timestamp[LOG_LEN]; + struct tm* ltime = localtime((time_t*)&t); + strftime((char*)timestamp, LOG_LEN, LOG_FMT, ltime); + write(logfd, timestamp, LOG_LEN - 1); + + write(logfd, buf, n); +} + +// Arena Allocator struct Arena { void* addr; u64 size; @@ -46,25 +89,20 @@ struct Arena { #define PushStruct(arena, type) PushArray((arena), (type), 1) #define PushStructZero(arena, type) PushArrayZero((arena), (type), 1) -Arena* -ArenaAlloc(u64 size) +// Returns arena in case of success, or 0 if it failed to alllocate the memory +void +ArenaAlloc(Arena* arena, u64 size) { - Arena* arena = (Arena*)malloc(sizeof(Arena)); - - arena->addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (arena->addr == MAP_FAILED) - return NULL; + arena->addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(arena->addr != MAP_FAILED); arena->pos = 0; arena->size = size; - - return arena; } void ArenaRelease(Arena* arena) { munmap(arena->addr, arena->size); - free(arena); } void* @@ -73,167 +111,9 @@ ArenaPush(Arena* arena, u64 size) u8* mem; mem = (u8*)arena->addr + arena->pos; arena->pos += size; + assert(arena->pos <= arena->size); return mem; } -/// Protocol -// - every message has format Header + Message -// TODO: authentication -// TODO: encryption - -/// Protocol Header -// - 2 bytes for version -// - 1 byte for message type -// - 16 bytes for checksum -// -// Text Message -// - 12 bytes for the author -// - 8 bytes for the timestamp -// - 2 bytes for the text length -// - x*4 bytes for the text -// -// History Message -// This message is for requesting messages sent after a timestamp. -// - 8 bytes for the timestamp - -/// Naming convention -// Messages end with the Message suffix (eg. TextMessag, HistoryMessage) -// A function that is coupled to a type works like -// <noun><type> eg. (printTextMessage, formatTimestamp) - -#define PROTOCOL_VERSION 0 - -typedef struct { - u16 version; - u8 type; -} HeaderMessage; - -enum { HEADER_TYPE_TEXT = 0, - HEADER_TYPE_HISTORY, - HEADER_TYPE_PRESENCE }; -#define HEADER_TEXTMESSAGE {.version = PROTOCOL_VERSION, .type = HEADER_TYPE_TEXT}; -#define HEADER_HISTORYMESSAGE {.version = PROTOCOL_VERSION, .type = HEADER_TYPE_HISTORY}; -#define HEADER_PRESENCEMESSAGE {.version = PROTOCOL_VERSION, .type = HEADER_TYPE_PRESENCE}; - -// Size of author string including null terminator -#define AUTHOR_LEN 13 -// Size of formatted timestamp string including null terminator -#define TIMESTAMP_LEN 9 - -typedef struct { - u8 checksum[16]; - u8 author[AUTHOR_LEN]; - u64 timestamp; - u16 len; // including null terminator - u32* text; // placeholder for indexing - // TODO: 0-length field? -} TextMessage; - -// Size of TextMessage without text pointer, used when receiving the message over a stream -#define TEXTMESSAGE_TEXT_SIZE(m) (m.len * sizeof(*m.text)) -#define TEXTMESSAGE_SIZE (sizeof(TextMessage) - sizeof(u32*)) - -typedef struct { - u64 timestamp; -} HistoryMessage; - -typedef struct { - u8 author[AUTHOR_LEN]; - u8 type; -} PresenceMessage; -enum { PRESENCE_TYPE_CONNECTED = 0, - PRESENCE_TYPE_DISCONNECTED }; - -// Returns string for type byte in HeaderMessage -u8* -headerTypeString(u8 type) -{ - switch (type) { - case HEADER_TYPE_TEXT: return (u8*)"TextMessage"; - case HEADER_TYPE_HISTORY: return (u8*)"HistoryMessage"; - case HEADER_TYPE_PRESENCE: return (u8*)"PresenceMessage"; - default: return (u8*)"Unknown"; - } -} - -u8* -presenceTypeString(u8 type) -{ - switch (type) { - case PRESENCE_TYPE_CONNECTED: return (u8*)"connected"; - case PRESENCE_TYPE_DISCONNECTED: return (u8*)"disconnected"; - default: return (u8*)"Unknown"; - } -} - -// from Tsoding video on minicel (https://youtu.be/HCAgvKQDJng?t=4546) -// sv(https://github.com/tsoding/sv) -#define PH_FMT "header: v%d %s(%d)" -#define PH_ARG(header) header.version, headerTypeString(header.type), header.type - -void -formatTimestamp(u8 tmsp[TIMESTAMP_LEN], u64 t) -{ - struct tm* ltime; - ltime = localtime((time_t*)&t); - strftime((char*)tmsp, TIMESTAMP_LEN, "%H:%M:%S", ltime); -} - -void -printTextMessage(TextMessage* message, u8 wide) -{ - u8 timestamp[TIMESTAMP_LEN] = {0}; - formatTimestamp(timestamp, message->timestamp); - - assert(setlocale(LC_ALL, "") != NULL); - - if (wide) - wprintf(L"TextMessage: %s [%s] %ls\n", timestamp, message->author, (wchar_t*)&message->text); - else { - u8 str[message->len]; - wcstombs((char*)str, (wchar_t*)&message->text, message->len * sizeof(*message->text)); - printf("TextMessage: %s [%s] (%d)%s\n", timestamp, message->author, message->len, str); - } -} - -// Receive a message from fd and store it to the msgsArena, -// if dest is not NULL point it to the new message created on msgsArena -// Returns the number of bytes received -u32 -recvTextMessage(Arena* msgsArena, u32 fd, TextMessage** dest) -{ - s32 nrecv = 0; - - TextMessage* message = ArenaPush(msgsArena, TEXTMESSAGE_SIZE); - if (dest != NULL) - *dest = message; - - // Receive everything but the text so we can know the text's size and act accordingly - nrecv = recv(fd, message, TEXTMESSAGE_SIZE, 0); - assert(nrecv != -1); - assert(nrecv == TEXTMESSAGE_SIZE); - - nrecv = 0; - - // Allocate memory for text and receive in that memory - u32 text_size = message->len * sizeof(*message->text); - ArenaPush(msgsArena, text_size); - - nrecv = recv(fd, (u8*)&message->text, text_size, 0); - assert(nrecv != -1); - assert(nrecv == message->len * sizeof(*message->text)); - - return TEXTMESSAGE_SIZE + nrecv; -} - -u32 -wstrlen(u32* str) -{ - u32 i = 0; - while (str[i] != 0) - i++; - return i; -} - #endif #define CHATTY_H |