aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaymaekers Luca <raymaekers.luca@gmail.com>2024-10-19 15:31:51 +0200
committerRaymaekers Luca <raymaekers.luca@gmail.com>2024-10-19 15:31:51 +0200
commitff0aae89238f4d60267def24476e8b9f4cb596cf (patch)
treed8a646d04c0e2617bf279b387e5d11960906d340
parent104dabefd62952f2d892a2dcdfb5700d9379ac00 (diff)
add serialization to file code
-rw-r--r--client.c36
-rw-r--r--common.c59
-rw-r--r--common.h28
-rw-r--r--config.h19
-rw-r--r--server.c6
5 files changed, 113 insertions, 35 deletions
diff --git a/client.c b/client.c
index c70e9d0..9a22d90 100644
--- a/client.c
+++ b/client.c
@@ -9,6 +9,7 @@
#define TB_IMPL
#include "termbox2.h"
// clang-format on
+#include "common.h"
#include "config.h"
#include <arpa/inet.h>
@@ -32,10 +33,9 @@ int prompt_offs_y = 3;
static int serverfd;
// Input message to be send
struct message input = {
- .buf = {0},
.author = USERNAME,
.timestamp = {0},
- .buf_len = 0,
+ .len = 0,
};
// All messages sent and received in order
struct message *messages;
@@ -76,7 +76,7 @@ void screen_welcome()
if (lines_available - nmessages < 0)
skip = nmessages - lines_available;
for (msg_y = skip; msg_y < nmessages; msg_y++) {
- tb_printf(0, msg_y - skip, 0, 0, "%s [%s]: %s", messages[msg_y].timestamp, messages[msg_y].author, messages[msg_y].buf);
+ tb_printf(0, msg_y - skip, 0, 0, "%s [%s]: %s", messages[msg_y].timestamp, messages[msg_y].author, messages[msg_y].text);
}
}
@@ -84,10 +84,10 @@ void screen_welcome()
void add_message(struct message msg)
{
int i;
- for (i = 0; (messages[nmessages].buf[i] = msg.buf[i]); i++)
+ for (i = 0; (messages[nmessages].text[i] = msg.text[i]); i++)
;
- messages[nmessages].buf[i] = 0;
- messages[nmessages].buf_len = i;
+ messages[nmessages].text[i] = 0;
+ messages[nmessages].len = i;
for (i = 0; (messages[nmessages].timestamp[i] = msg.timestamp[i]); i++)
;
messages[nmessages].timestamp[i] = 0;
@@ -174,11 +174,11 @@ int main(void)
tb_print(global.cursor_x, global.cursor_y, 0, 0, " ");
}
tb_set_cursor(curs_offs_x, global.cursor_y);
- input.buf_len = 0;
+ input.len = 0;
break;
// send message
case TB_KEY_CTRL_M:
- if (input.buf_len <= 0)
+ if (input.len <= 0)
break;
while (global.cursor_x > curs_offs_x) {
global.cursor_x--;
@@ -187,7 +187,7 @@ int main(void)
tb_set_cursor(curs_offs_x, global.cursor_y);
// zero terminate
- input.buf[input.buf_len] = 0;
+ input.text[input.len] = 0;
// print new message
time(&now);
@@ -200,7 +200,7 @@ int main(void)
err_exit("Error while sending message.");
// reset buffer
- input.buf_len = 0;
+ input.len = 0;
// update the screen
// NOTE: kind of wasteful cause we should only display new message
@@ -211,28 +211,28 @@ int main(void)
// remove word
case TB_KEY_CTRL_W:
// Delete consecutive space
- while (input.buf[input.buf_len - 1] == ' ' && global.cursor_x > curs_offs_x) {
+ while (input.text[input.len - 1] == ' ' && global.cursor_x > curs_offs_x) {
global.cursor_x--;
- input.buf_len--;
+ input.len--;
tb_print(global.cursor_x, global.cursor_y, 0, 0, " ");
}
// Delete until next non-space
- while (input.buf[input.buf_len - 1] != ' ' && global.cursor_x > curs_offs_x) {
+ while (input.text[input.len - 1] != ' ' && global.cursor_x > curs_offs_x) {
global.cursor_x--;
- input.buf_len--;
+ input.len--;
tb_print(global.cursor_x, global.cursor_y, 0, 0, " ");
}
- input.buf[input.buf_len] = 0;
+ input.text[input.len] = 0;
break;
}
- // append pressed character to input.buf
+ // append pressed character to input.text
// TODO: wrap instead
- if (ev.ch > 0 && input.buf_len < MSG_MAX && input.buf_len < global.width - 3 - 1) {
+ if (ev.ch > 0 && input.len < MSG_MAX && input.len < global.width - 3 - 1) {
tb_printf(global.cursor_x, global.cursor_y, 0, 0, "%c", ev.ch);
global.cursor_x++;
- input.buf[input.buf_len++] = ev.ch;
+ input.text[input.len++] = ev.ch;
}
} else if (fds[FD_SERVER].revents & POLLIN) {
diff --git a/common.c b/common.c
index b177987..d72ead3 100644
--- a/common.c
+++ b/common.c
@@ -1,9 +1,12 @@
+#include "common.h"
#include "config.h"
+
#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
#include <strings.h>
#include <unistd.h>
-// wrapper for write
void writef(char *format, ...)
{
va_list args;
@@ -18,3 +21,57 @@ void writef(char *format, ...)
n++;
write(0, buf, n);
}
+
+u16 str_len(char *str)
+{
+ u16 i = 0;
+ while (str[i])
+ i++;
+ return i;
+}
+
+void str_cpy(char *to, char *from)
+{
+ while ((*to++ = *from++))
+ ;
+}
+
+u8 save_message(struct message *msg, FILE *f)
+{
+ u8 err = 0;
+ u16 len;
+ if (msg->text == NULL) {
+ len = 0;
+ msg->text = ""; // TODO: Error empty message should not be allowed.
+ } else {
+ len = str_len(msg->text);
+ }
+
+ if (len == 0)
+ err = 1;
+
+ fwrite(&msg->timestamp, sizeof(*msg->timestamp) * MSG_TIMESTAMP_LEN, 1, f);
+ fwrite(&msg->author, sizeof(*msg->author) * MSG_AUTHOR_LEN, 1, f);
+ fwrite(&len, sizeof(len), 1, f);
+ fputs(msg->text, f);
+
+ return err;
+}
+
+u8 load_message(struct message *msg, FILE *f)
+{
+ fread(msg, sizeof(*msg->timestamp) * MSG_TIMESTAMP_LEN + sizeof(*msg->author) * MSG_AUTHOR_LEN, 1, f);
+ u16 len;
+ fread(&len, sizeof(len), 1, f);
+ if (len == 0) {
+ // TODO: Error: empty message should not be allowed
+ // empty message
+ msg->text = "";
+ return 1;
+ }
+ char txt[len];
+ fgets(txt, len, f);
+ msg->text = txt;
+
+ return 0;
+}
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..f737e2f
--- /dev/null
+++ b/common.h
@@ -0,0 +1,28 @@
+#include <stdint.h>
+#include <stdio.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+
+// To serialize the text that could be arbitrary length the lenght is encoded after the author
+// string and before the text.
+struct message {
+ char timestamp[9]; // HH:MM:SS
+ char author[12];
+ u16 len;
+ char *text;
+};
+
+// printf without buffering using write syscall, works when using sockets
+void writef(char *format, ...);
+
+u16 str_len(char *str);
+void str_cpy(char *to, char *from);
+
+// save the message msg to file in binary format, returns zero on success, returns 1 if the msg.text
+// was empty which should not be allowed.
+u8 save_message(struct message *msg, FILE *f);
+// load the message msg from file f, returns zero on success, returns 1 if the msg.text
+// was empty which should not be allowed.
+u8 load_message(struct message *msg, FILE *f);
diff --git a/config.h b/config.h
index 039367d..626ccad 100644
--- a/config.h
+++ b/config.h
@@ -1,20 +1,11 @@
-#include <stdarg.h>
-#include <stdio.h>
-#include <unistd.h>
-
#define PORT 9983
// max size for a message sent
#define BUF_MAX 255
// max length of messages
#define MSG_MAX 256
+// max length of author field
+#define MSG_AUTHOR_LEN 12
+// max length of timestamp field
+#define MSG_TIMESTAMP_LEN 9
// current user's name
-#define USERNAME "unrtdqttr"
-
-void writef(char* format, ...);
-
-struct message {
- char buf[MSG_MAX];
- int buf_len;
- char timestamp[9]; // HH:MM:SS
- char author[12];
-};
+#define USERNAME "Jef Koek"
diff --git a/server.c b/server.c
index 63784d1..675bfb7 100644
--- a/server.c
+++ b/server.c
@@ -15,12 +15,14 @@
// - max y for new messages and make them scroll
// - check resize event
// - asynchronously receive/send a message
+// - fix receiving messages with arbitrary text length
// TODO: send message to all other clients
// - implement different rooms
// - implement history
// - implement tls
+#include "common.h"
#include "config.h"
#include <arpa/inet.h>
#include <errno.h>
@@ -33,6 +35,8 @@
#define MAX_CONNECTIONS 5
#define FD_MAX MAX_CONNECTIONS + 1
+static const char *filename = "history.dat";
+
enum { FD_SERVER = 0 };
int serverfd;
@@ -156,7 +160,6 @@ int main(void)
printf("Retransmitted message to client %d.\n", j);
}
-
// // TODO: check if bytes are correct
// FILE *f = fopen("srv_recv.bin", "wb");
// fwrite(&msg_recv, sizeof(struct message), 1, f);
@@ -164,7 +167,6 @@ int main(void)
//
// printf("written %lu bytes to srv_recv.bin\n", sizeof(msg_recv));
// return 0;
-
}
}