mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-05-10 19:00:57 +08:00
fix: data races, missing persistence, and input safety bugs
- Make client width/height _Atomic to fix data race between window-change callback thread and session thread - Persist join/leave system messages via message_save() - Fix ftell() error handling: check <= 0 instead of == 0 - Make room_add_message static to enforce lock-must-be-held contract - Use local copy in execute_command to avoid mutating command_input - Increase help_copy buffer from 4096 to 8192 for CJK text safety - Add :q/:quit/:exit command for Vim-style disconnect - Fix unit test Makefile to link common.c
This commit is contained in:
parent
0de13a6314
commit
9ca1e9d977
7 changed files with 40 additions and 31 deletions
|
|
@ -36,9 +36,6 @@ void room_remove_client(chat_room_t *room, struct client *client);
|
|||
/* Broadcast message to all clients */
|
||||
void room_broadcast(chat_room_t *room, const message_t *msg);
|
||||
|
||||
/* Add message to room history */
|
||||
void room_add_message(chat_room_t *room, const message_t *msg);
|
||||
|
||||
/* Get message by index (thread-safe value copy) */
|
||||
bool room_get_message(chat_room_t *room, int index, message_t *out);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ typedef struct client {
|
|||
ssh_channel channel; /* SSH channel */
|
||||
char username[MAX_USERNAME_LEN];
|
||||
char client_ip[INET6_ADDRSTRLEN];
|
||||
int width;
|
||||
int height;
|
||||
_Atomic int width;
|
||||
_Atomic int height;
|
||||
client_mode_t mode;
|
||||
help_lang_t help_lang;
|
||||
int scroll_pos;
|
||||
|
|
|
|||
|
|
@ -87,23 +87,9 @@ void room_remove_client(chat_room_t *room, struct client *client) {
|
|||
pthread_rwlock_unlock(&room->lock);
|
||||
}
|
||||
|
||||
/* Broadcast message to all clients */
|
||||
void room_broadcast(chat_room_t *room, const message_t *msg) {
|
||||
pthread_rwlock_wrlock(&room->lock);
|
||||
|
||||
/* Add to history */
|
||||
room_add_message(room, msg);
|
||||
room->update_seq++;
|
||||
|
||||
pthread_rwlock_unlock(&room->lock);
|
||||
}
|
||||
|
||||
/* Add message to room history */
|
||||
void room_add_message(chat_room_t *room, const message_t *msg) {
|
||||
/* Caller should hold write lock */
|
||||
|
||||
/* Add message to room history (caller must hold write lock) */
|
||||
static void room_add_message(chat_room_t *room, const message_t *msg) {
|
||||
if (room->message_count >= MAX_MESSAGES) {
|
||||
/* Shift messages to make room */
|
||||
memmove(&room->messages[0], &room->messages[1],
|
||||
(MAX_MESSAGES - 1) * sizeof(message_t));
|
||||
room->message_count = MAX_MESSAGES - 1;
|
||||
|
|
@ -112,6 +98,16 @@ void room_add_message(chat_room_t *room, const message_t *msg) {
|
|||
room->messages[room->message_count++] = *msg;
|
||||
}
|
||||
|
||||
/* Broadcast message to all clients */
|
||||
void room_broadcast(chat_room_t *room, const message_t *msg) {
|
||||
pthread_rwlock_wrlock(&room->lock);
|
||||
|
||||
room_add_message(room, msg);
|
||||
room->update_seq++;
|
||||
|
||||
pthread_rwlock_unlock(&room->lock);
|
||||
}
|
||||
|
||||
/* Get message by index (thread-safe value copy) */
|
||||
bool room_get_message(chat_room_t *room, int index, message_t *out) {
|
||||
if (!room || !out) return false;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ int message_load(message_t **messages, int max_messages) {
|
|||
}
|
||||
|
||||
long file_size = ftell(fp);
|
||||
if (file_size == 0) {
|
||||
if (file_size <= 0) {
|
||||
fclose(fp);
|
||||
*messages = msg_array;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1069,7 +1069,10 @@ static int execute_exec_command(client_t *client) {
|
|||
|
||||
/* Execute a command */
|
||||
static void execute_command(client_t *client) {
|
||||
char *cmd = client->command_input;
|
||||
char cmd_buf[256];
|
||||
strncpy(cmd_buf, client->command_input, sizeof(cmd_buf) - 1);
|
||||
cmd_buf[sizeof(cmd_buf) - 1] = '\0';
|
||||
char *cmd = cmd_buf;
|
||||
char output[2048] = {0};
|
||||
size_t pos = 0;
|
||||
|
||||
|
|
@ -1118,8 +1121,14 @@ static void execute_command(client_t *client) {
|
|||
"list, users, who - Show online users\n"
|
||||
"help, commands - Show this help\n"
|
||||
"clear, cls - Clear command output\n"
|
||||
"q, quit, exit - Disconnect from chat\n"
|
||||
"========================================\n");
|
||||
|
||||
} else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0 ||
|
||||
strcmp(cmd, "exit") == 0) {
|
||||
client->connected = false;
|
||||
return;
|
||||
|
||||
} else if (strcmp(cmd, "clear") == 0 || strcmp(cmd, "cls") == 0) {
|
||||
buffer_appendf(output, sizeof(output), &pos, "Command output cleared\n");
|
||||
|
||||
|
|
@ -1367,6 +1376,7 @@ void* client_handle_session(void *arg) {
|
|||
join_msg.username[MAX_USERNAME_LEN - 1] = '\0';
|
||||
snprintf(join_msg.content, MAX_MESSAGE_LEN, "%s 加入了聊天室", client->username);
|
||||
room_broadcast(g_room, &join_msg);
|
||||
message_save(&join_msg);
|
||||
|
||||
/* Render initial screen */
|
||||
tui_render_screen(client);
|
||||
|
|
@ -1496,6 +1506,7 @@ cleanup:
|
|||
client->connected = false;
|
||||
room_remove_client(g_room, client);
|
||||
room_broadcast(g_room, &leave_msg);
|
||||
message_save(&leave_msg);
|
||||
}
|
||||
|
||||
release_ip_connection(client->client_ip);
|
||||
|
|
@ -1768,9 +1779,11 @@ static int client_channel_window_change(ssh_session session, ssh_channel channel
|
|||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
client->width = width;
|
||||
client->height = height;
|
||||
sanitize_terminal_size(&client->width, &client->height);
|
||||
int w = width;
|
||||
int h = height;
|
||||
sanitize_terminal_size(&w, &h);
|
||||
client->width = w;
|
||||
client->height = h;
|
||||
client->redraw_pending = true;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
|
@ -1942,9 +1955,11 @@ static void *bootstrap_client_session(void *arg) {
|
|||
|
||||
client->session = session;
|
||||
client->channel = channel;
|
||||
client->width = ctx->pty_width;
|
||||
client->height = ctx->pty_height;
|
||||
sanitize_terminal_size(&client->width, &client->height);
|
||||
int init_w = ctx->pty_width;
|
||||
int init_h = ctx->pty_height;
|
||||
sanitize_terminal_size(&init_w, &init_h);
|
||||
client->width = init_w;
|
||||
client->height = init_h;
|
||||
client->ref_count = 1;
|
||||
pthread_mutex_init(&client->ref_lock, NULL);
|
||||
pthread_mutex_init(&client->io_lock, NULL);
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ void tui_render_help(client_t *client) {
|
|||
|
||||
/* Help content */
|
||||
const char *help_text = tui_get_help_text(client->help_lang);
|
||||
char help_copy[4096];
|
||||
char help_copy[8192];
|
||||
strncpy(help_copy, help_text, sizeof(help_copy) - 1);
|
||||
help_copy[sizeof(help_copy) - 1] = '\0';
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ LDFLAGS = -pthread
|
|||
# Source files
|
||||
UTF8_SRC = ../../src/utf8.c
|
||||
MESSAGE_SRC = ../../src/message.c
|
||||
COMMON_SRC = ../../src/common.c
|
||||
|
||||
TESTS = test_utf8 test_message
|
||||
|
||||
|
|
@ -16,7 +17,7 @@ all: $(TESTS)
|
|||
test_utf8: test_utf8.c $(UTF8_SRC)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
test_message: test_message.c $(MESSAGE_SRC) $(UTF8_SRC)
|
||||
test_message: test_message.c $(MESSAGE_SRC) $(UTF8_SRC) $(COMMON_SRC)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
run: all
|
||||
|
|
|
|||
Loading…
Reference in a new issue