Fix tunnel_close forwarding and add client event logging

- Modified websocket_handle_message to properly forward tunnel_close messages
  to the correct endpoint regardless of sender (wssshc or wsssht)
- Fixed build warning by casting ws_state_t to int
- Added client registration/disconnection events in non-debug mode
parent f4937b01
...@@ -361,8 +361,51 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -361,8 +361,51 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
} }
if (state->debug) { if (state->debug) {
// Check if this is a tunnel_data or tunnel_response message to avoid printing large data
if (strstr(msg_copy, "\"type\":\"tunnel_data\"") || strstr(msg_copy, "\"type\": \"tunnel_data\"") ||
strstr(msg_copy, "\"type\":\"tunnel_response\"") || strstr(msg_copy, "\"type\": \"tunnel_response\"")) {
// Extract request_id and data size for tunnel messages
char *request_id_start = strstr(msg_copy, "\"request_id\"");
char request_id[256] = "...";
if (request_id_start) {
char *colon = strchr(request_id_start, ':');
if (colon) {
char *quote = strchr(colon, '"');
if (quote) {
request_id_start = quote + 1;
char *end_quote = strchr(request_id_start, '"');
if (end_quote) {
size_t len = end_quote - request_id_start;
if (len < sizeof(request_id) - 1) {
memcpy(request_id, request_id_start, len);
request_id[len] = '\0';
}
}
}
}
}
char *data_start = strstr(msg_copy, "\"data\"");
size_t data_size = 0;
if (data_start) {
char *data_colon = strchr(data_start, ':');
if (data_colon) {
char *data_quote = strchr(data_colon, '"');
if (data_quote) {
data_start = data_quote + 1;
char *data_end = strchr(data_start, '"');
if (data_end) {
data_size = data_end - data_start;
}
}
}
}
const char *msg_type = strstr(msg_copy, "tunnel_data") ? "tunnel_data" : "tunnel_response";
printf("[DEBUG - %s -> wssshd] Handling message: {\"type\":\"%s\", \"request_id\":\"%s\", \"data\":\"<size: %zu bytes>\"}\n",
direction, msg_type, request_id, data_size);
} else {
printf("[DEBUG - %s -> wssshd] Handling message: %.*s\n", direction, (int)message_len, message); printf("[DEBUG - %s -> wssshd] Handling message: %.*s\n", direction, (int)message_len, message);
} }
}
int result = 0; int result = 0;
...@@ -460,7 +503,7 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -460,7 +503,7 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
snprintf(response, sizeof(response), REGISTERED_MSG, client_id); snprintf(response, sizeof(response), REGISTERED_MSG, client_id);
if (state->debug) printf("[DEBUG - wssshd -> wssshc] Sending registration success: %s\n", response); if (state->debug) printf("[DEBUG - wssshd -> wssshc] Sending registration success: %s\n", response);
ws_send_frame(conn, WS_OPCODE_TEXT, response, strlen(response)); ws_send_frame(conn, WS_OPCODE_TEXT, response, strlen(response));
if (state->debug) printf("[EVENT] Client %s registered\n", client_id); if (!state->debug) printf("[EVENT] Client %s registered\n", client_id);
} }
} else { } else {
// Send registration error // Send registration error
...@@ -761,10 +804,29 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -761,10 +804,29 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
} }
if (target_conn) { if (target_conn) {
// Check connection health before attempting to send
if (!ws_connection_is_healthy(target_conn)) {
if (state->debug) printf("[DEBUG - %s -> wssshd] Target connection for request %s is not healthy, closing tunnel\n", direction, request_id);
// Send tunnel_close to the still-connected end
ws_connection_t *other_conn = (strcmp(direction, "wssshc") == 0) ? tunnel->wsssh_ws : tunnel->client_ws;
if (other_conn && ((ws_connection_t *)other_conn)->state == WS_STATE_OPEN) {
char close_msg[256];
snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id);
ws_send_frame(other_conn, WS_OPCODE_TEXT, close_msg, strlen(close_msg));
if (state->debug) printf("[DEBUG - wssshd -> %s] Sent tunnel_close for request %s due to unhealthy connection\n", (strcmp(direction, "wssshc") == 0) ? "wsssht" : "wssshc", request_id);
}
// Mark tunnel as error and remove it
tunnel_update_status(tunnel, TUNNEL_STATUS_ERROR, "Target connection unhealthy");
websocket_remove_tunnel(state, request_id);
} else {
// Calculate binary size from hex data length // Calculate binary size from hex data length
size_t hex_len = strlen(data); size_t hex_len = strlen(data);
size_t binary_size = hex_len / 2; size_t binary_size = hex_len / 2;
// Update tunnel statistics
tunnel->total_bytes_sent += binary_size;
tunnel->bytes_last_period += binary_size;
// Forward hex data directly without decode/re-encode cycle // Forward hex data directly without decode/re-encode cycle
size_t request_id_len = strlen(request_id); size_t request_id_len = strlen(request_id);
size_t data_len = strlen(data); size_t data_len = strlen(data);
...@@ -776,12 +838,23 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -776,12 +838,23 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
if (forward_msg) { if (forward_msg) {
int msg_len = snprintf(forward_msg, total_size, "{\"type\":\"tunnel_data\",\"request_id\":\"%s\",\"size\":%zu,\"data\":\"%s\"}", request_id, binary_size, data); int msg_len = snprintf(forward_msg, total_size, "{\"type\":\"tunnel_data\",\"request_id\":\"%s\",\"size\":%zu,\"data\":\"%s\"}", request_id, binary_size, data);
if (msg_len > 0 && (size_t)msg_len < total_size) { if (msg_len > 0 && (size_t)msg_len < total_size) {
if (state->debug) printf("[DEBUG - wssshd -> %s] Forwarding tunnel data: %.*s\n", target_side, msg_len, forward_msg); if (state->debug) printf("[DEBUG - wssshd -> %s] Forwarding tunnel data: request_id=%s, size=%zu bytes\n", target_side, request_id, binary_size);
bool send_result = ws_send_frame(target_conn, WS_OPCODE_TEXT, forward_msg, msg_len); bool send_result = ws_send_frame(target_conn, WS_OPCODE_TEXT, forward_msg, msg_len);
if (send_result) { if (send_result) {
if (state->debug) printf("[DEBUG - %s -> wssshd] Forwarded tunnel data for request %s to %s, hex length: %zu bytes (binary size: %zu bytes)\n", direction, request_id, target_side, data_len, binary_size); if (state->debug) printf("[DEBUG - %s -> wssshd] Forwarded tunnel data for request %s to %s, hex length: %zu bytes (binary size: %zu bytes)\n", direction, request_id, target_side, data_len, binary_size);
} else { } else {
if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to send tunnel data for request %s to %s (connection may be broken)\n", direction, request_id, target_side); if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to send tunnel data for request %s to %s (connection may be broken)\n", direction, request_id, target_side);
// Send tunnel_close to the still-connected end when forwarding fails
ws_connection_t *other_conn = (strcmp(direction, "wssshc") == 0) ? tunnel->wsssh_ws : tunnel->client_ws;
if (other_conn && ((ws_connection_t *)other_conn)->state == WS_STATE_OPEN) {
char close_msg[256];
snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id);
ws_send_frame(other_conn, WS_OPCODE_TEXT, close_msg, strlen(close_msg));
if (state->debug) printf("[DEBUG - wssshd -> %s] Sent tunnel_close for request %s due to forwarding failure\n", (strcmp(direction, "wssshc") == 0) ? "wsssht" : "wssshc", request_id);
}
// Mark tunnel as error and remove it
tunnel_update_status(tunnel, TUNNEL_STATUS_ERROR, "Connection broken during data forwarding");
websocket_remove_tunnel(state, request_id);
} }
} else { } else {
if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to format forward message (msg_len=%d, total_size=%zu)\n", direction, msg_len, total_size); if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to format forward message (msg_len=%d, total_size=%zu)\n", direction, msg_len, total_size);
...@@ -790,6 +863,7 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -790,6 +863,7 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
} else { } else {
if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to allocate buffer for forward message\n", direction); if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to allocate buffer for forward message\n", direction);
} }
}
} else { } else {
if (state->debug) { if (state->debug) {
if (!target_conn) { if (!target_conn) {
...@@ -865,6 +939,29 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -865,6 +939,29 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
} }
if (target_conn) { if (target_conn) {
// Check connection health before attempting to send
if (!ws_connection_is_healthy(target_conn)) {
if (state->debug) printf("[DEBUG - %s -> wssshd] Target connection for request %s is not healthy, closing tunnel\n", direction, request_id);
// Send tunnel_close to the still-connected end
ws_connection_t *other_conn = (strcmp(direction, "wssshc") == 0) ? tunnel->wsssh_ws : tunnel->client_ws;
if (other_conn && ((ws_connection_t *)other_conn)->state == WS_STATE_OPEN) {
char close_msg[256];
snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id);
ws_send_frame(other_conn, WS_OPCODE_TEXT, close_msg, strlen(close_msg));
if (state->debug) printf("[DEBUG - wssshd -> %s] Sent tunnel_close for request %s due to unhealthy connection\n", (strcmp(direction, "wssshc") == 0) ? "wsssht" : "wssshc", request_id);
}
// Mark tunnel as error and remove it
tunnel_update_status(tunnel, TUNNEL_STATUS_ERROR, "Target connection unhealthy");
websocket_remove_tunnel(state, request_id);
} else {
// Calculate binary size from hex data length
size_t hex_len = strlen(data);
size_t binary_size = hex_len / 2;
// Update tunnel statistics
tunnel->total_bytes_sent += binary_size;
tunnel->bytes_last_period += binary_size;
// Forward hex data directly without decode/re-encode cycle // Forward hex data directly without decode/re-encode cycle
size_t request_id_len = strlen(request_id); size_t request_id_len = strlen(request_id);
size_t data_len = strlen(data); size_t data_len = strlen(data);
...@@ -882,6 +979,17 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -882,6 +979,17 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
if (state->debug) printf("[DEBUG - %s -> wssshd] Forwarded tunnel response for request %s to %s, hex length: %zu bytes\n", direction, request_id, target_side, data_len); if (state->debug) printf("[DEBUG - %s -> wssshd] Forwarded tunnel response for request %s to %s, hex length: %zu bytes\n", direction, request_id, target_side, data_len);
} else { } else {
if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to send tunnel response for request %s to %s (connection may be broken)\n", direction, request_id, target_side); if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to send tunnel response for request %s to %s (connection may be broken)\n", direction, request_id, target_side);
// Send tunnel_close to the still-connected end when forwarding fails
ws_connection_t *other_conn = (strcmp(direction, "wssshc") == 0) ? tunnel->wsssh_ws : tunnel->client_ws;
if (other_conn && ((ws_connection_t *)other_conn)->state == WS_STATE_OPEN) {
char close_msg[256];
snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id);
ws_send_frame(other_conn, WS_OPCODE_TEXT, close_msg, strlen(close_msg));
if (state->debug) printf("[DEBUG - wssshd -> %s] Sent tunnel_close for request %s due to forwarding failure\n", (strcmp(direction, "wssshc") == 0) ? "wsssht" : "wssshc", request_id);
}
// Mark tunnel as error and remove it
tunnel_update_status(tunnel, TUNNEL_STATUS_ERROR, "Connection broken during response forwarding");
websocket_remove_tunnel(state, request_id);
} }
} else { } else {
if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to format forward message (msg_len=%d, total_size=%zu)\n", direction, msg_len, total_size); if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to format forward message (msg_len=%d, total_size=%zu)\n", direction, msg_len, total_size);
...@@ -890,6 +998,7 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -890,6 +998,7 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
} else { } else {
if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to allocate buffer for forward message\n", direction); if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to allocate buffer for forward message\n", direction);
} }
}
} else { } else {
if (state->debug) { if (state->debug) {
if (!target_conn) { if (!target_conn) {
...@@ -910,7 +1019,7 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -910,7 +1019,7 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
if (state->debug) { if (state->debug) {
printf("[DEBUG - %s -> wssshd] Processing tunnel close\n", direction); printf("[DEBUG - %s -> wssshd] Processing tunnel close\n", direction);
} }
// Handle tunnel close from wssshc // Handle tunnel close from either wssshc or wsssht
char *request_id = NULL; char *request_id = NULL;
char *close_request_id_start = strstr(msg_copy, "\"request_id\":\""); char *close_request_id_start = strstr(msg_copy, "\"request_id\":\"");
...@@ -930,21 +1039,36 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr ...@@ -930,21 +1039,36 @@ int websocket_handle_message(wssshd_state_t *state, ws_connection_t *conn __attr
} }
if (request_id) { if (request_id) {
// Find the tunnel and forward close to wsssht // Find the tunnel and forward close to the other end
tunnel_t *tunnel = websocket_find_tunnel(state, request_id); tunnel_t *tunnel = websocket_find_tunnel(state, request_id);
if (tunnel && tunnel->wsssh_ws) { if (tunnel) {
// Forward the close message to wsssht // Determine target based on sender
ws_connection_t *target_conn = NULL;
const char *target_side = NULL;
if (conn == tunnel->client_ws) {
// Message from wssshc, forward to wsssht
target_conn = tunnel->wsssh_ws;
target_side = "wsssht";
} else if (conn == tunnel->wsssh_ws) {
// Message from wsssht, forward to wssshc
target_conn = tunnel->client_ws;
target_side = "wssshc";
}
if (target_conn && ((ws_connection_t *)target_conn)->state == WS_STATE_OPEN) {
char close_msg[256]; char close_msg[256];
snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id); snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id);
if (state->debug) printf("[DEBUG - wssshd -> wsssht] Forwarding tunnel close: %s\n", close_msg); if (state->debug) printf("[DEBUG - wssshd -> %s] Forwarding tunnel close: %s\n", target_side, close_msg);
bool send_result = ws_send_frame(tunnel->wsssh_ws, WS_OPCODE_TEXT, close_msg, strlen(close_msg)); bool send_result = ws_send_frame(target_conn, WS_OPCODE_TEXT, close_msg, strlen(close_msg));
if (send_result) { if (send_result) {
if (state->debug) printf("[DEBUG - %s -> wssshd] Forwarded tunnel_close for request %s to wsssht\n", direction, request_id); if (state->debug) printf("[DEBUG - %s -> wssshd] Forwarded tunnel_close for request %s to %s\n", direction, request_id, target_side);
} else { } else {
if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to send tunnel_close for request %s to wsssht (connection may be broken)\n", direction, request_id); if (state->debug) printf("[DEBUG - %s -> wssshd] Failed to send tunnel_close for request %s to %s (connection may be broken)\n", direction, request_id, target_side);
}
} else if (target_conn && ((ws_connection_t *)target_conn)->state != WS_STATE_OPEN) {
if (state->debug) printf("[DEBUG - %s -> wssshd] Not forwarding tunnel_close for request %s - %s connection is not open (state=%d)\n", direction, request_id, target_side ? target_side : "target", target_conn ? (int)((ws_connection_t *)target_conn)->state : -1);
} }
} else if (tunnel && tunnel->wsssh_ws && ((ws_connection_t *)tunnel->wsssh_ws)->state != WS_STATE_OPEN) {
if (state->debug) printf("[DEBUG - %s -> wssshd] Not forwarding tunnel_close for request %s - wsssht connection is not open (state=%d)\n", direction, request_id, ((ws_connection_t *)tunnel->wsssh_ws)->state);
} }
// Remove the tunnel // Remove the tunnel
...@@ -1163,8 +1287,45 @@ static void *client_handler_thread(void *arg) { ...@@ -1163,8 +1287,45 @@ static void *client_handler_thread(void *arg) {
direction = "wsssht"; direction = "wsssht";
} }
if (state->debug) { if (state->debug) {
// Check if this is a tunnel_data or tunnel_response message to avoid printing large data
if (strstr(message, "\"type\":\"tunnel_data\"") || strstr(message, "\"type\": \"tunnel_data\"") ||
strstr(message, "\"type\":\"tunnel_response\"") || strstr(message, "\"type\": \"tunnel_response\"")) {
// Extract request_id
char *request_id_start = strstr(message, "\"request_id\"");
char request_id[256] = "...";
if (request_id_start) {
char *colon = strchr(request_id_start, ':');
if (colon) {
char *quote = strchr(colon, '"');
if (quote) {
request_id_start = quote + 1;
char *end_quote = strchr(request_id_start, '"');
if (end_quote) {
size_t len = end_quote - request_id_start;
if (len < sizeof(request_id) - 1) {
memcpy(request_id, request_id_start, len);
request_id[len] = '\0';
}
}
}
}
}
// Extract size value
size_t size_val = 0;
char *size_start = strstr(message, "\"size\"");
if (size_start) {
char *size_colon = strchr(size_start, ':');
if (size_colon) {
size_val = strtoul(size_colon + 1, NULL, 10);
}
}
const char *msg_type = strstr(message, "tunnel_data") ? "tunnel_data" : "tunnel_response";
printf("[DEBUG - %s -> wssshd] Received message: {\"type\":\"%s\",\"request_id\":\"%s\",\"size\":%zu,\"data\":\"<size: %zu bytes>\"}\n",
direction, msg_type, request_id, size_val, size_val);
} else {
printf("[DEBUG - %s -> wssshd] Received message: %s\n", direction, message); printf("[DEBUG - %s -> wssshd] Received message: %s\n", direction, message);
} }
}
// Handle message with crash protection // Handle message with crash protection
websocket_handle_message(state, conn, message, len); websocket_handle_message(state, conn, message, len);
} }
...@@ -1179,9 +1340,9 @@ static void *client_handler_thread(void *arg) { ...@@ -1179,9 +1340,9 @@ static void *client_handler_thread(void *arg) {
if (state->debug) { if (state->debug) {
printf("[DEBUG - %s -> wssshd] Received ping, sending pong\n", direction); printf("[DEBUG - %s -> wssshd] Received ping, sending pong\n", direction);
} }
// Send pong frame with retry logic for robustness // Send pong frame with improved retry logic for robustness
int pong_retries = 0; int pong_retries = 0;
const int max_pong_retries = 3; const int max_pong_retries = 5; // Increased retries
bool pong_sent = false; bool pong_sent = false;
while (!pong_sent && pong_retries < max_pong_retries) { while (!pong_sent && pong_retries < max_pong_retries) {
...@@ -1196,15 +1357,16 @@ static void *client_handler_thread(void *arg) { ...@@ -1196,15 +1357,16 @@ static void *client_handler_thread(void *arg) {
if (state->debug) { if (state->debug) {
printf("[DEBUG - %s -> wssshd] Pong failed, retrying (%d/%d)\n", direction, pong_retries, max_pong_retries); printf("[DEBUG - %s -> wssshd] Pong failed, retrying (%d/%d)\n", direction, pong_retries, max_pong_retries);
} }
usleep(50000); // Wait 50ms before retry // Exponential backoff for pong retries
usleep(20000 * (1 << pong_retries)); // 20ms, 40ms, 80ms, 160ms
} }
} }
} }
if (!pong_sent) { if (!pong_sent) {
fprintf(stderr, "[ERROR] Failed to send pong frame after %d retries, connection may be unstable\n", max_pong_retries); fprintf(stderr, "[ERROR] Failed to send pong frame after %d retries, connection may be unstable\n", max_pong_retries);
// Don't close connection immediately, let it timeout naturally // Mark connection as potentially unstable but don't close immediately
// but mark connection as potentially unstable for future operations // The connection health will be monitored through keepalive timeouts
} }
} else { } else {
if (state->debug) { if (state->debug) {
...@@ -1246,9 +1408,14 @@ static void *client_handler_thread(void *arg) { ...@@ -1246,9 +1408,14 @@ static void *client_handler_thread(void *arg) {
other_conn = tunnel->client_ws; other_conn = tunnel->client_ws;
} }
// Save request_id before freeing
char request_id_copy[64];
strncpy(request_id_copy, tunnel->request_id, sizeof(request_id_copy) - 1);
request_id_copy[sizeof(request_id_copy) - 1] = '\0';
if (other_conn) { if (other_conn) {
char close_msg[256]; char close_msg[256];
snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", tunnel->request_id); snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id_copy);
ws_send_frame(other_conn, WS_OPCODE_TEXT, close_msg, strlen(close_msg)); ws_send_frame(other_conn, WS_OPCODE_TEXT, close_msg, strlen(close_msg));
} }
...@@ -1261,7 +1428,7 @@ static void *client_handler_thread(void *arg) { ...@@ -1261,7 +1428,7 @@ static void *client_handler_thread(void *arg) {
tunnel_removed = true; tunnel_removed = true;
if (state->debug) { if (state->debug) {
printf("[DEBUG] Cleaned up tunnel %s due to websocket connection closure\n", tunnel->request_id); printf("[DEBUG] Cleaned up tunnel %s due to websocket connection closure\n", request_id_copy);
} }
} }
...@@ -1270,6 +1437,27 @@ static void *client_handler_thread(void *arg) { ...@@ -1270,6 +1437,27 @@ static void *client_handler_thread(void *arg) {
} }
} }
pthread_mutex_unlock(&state->tunnel_mutex); pthread_mutex_unlock(&state->tunnel_mutex);
// Remove client registration if this was a wssshc connection
pthread_mutex_lock(&state->client_mutex);
for (size_t i = 0; i < state->clients_count; ) {
if (state->clients[i].websocket == conn) {
// Remove this client
if (!state->debug) {
printf("[EVENT] Client %s disconnected\n", state->clients[i].client_id);
}
memmove(&state->clients[i], &state->clients[i + 1],
(state->clients_count - i - 1) * sizeof(client_t));
state->clients_count--;
if (state->debug) {
printf("[DEBUG] Removed client registration due to websocket connection closure\n");
}
break;
} else {
i++;
}
}
pthread_mutex_unlock(&state->client_mutex);
} }
printf("WebSocket connection closed\n"); printf("WebSocket connection closed\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment