updated client and server

This commit is contained in:
wt
2026-02-13 21:36:45 +07:00
parent be0007b68a
commit 53887821d5
2 changed files with 225 additions and 159 deletions
+41 -11
View File
@@ -12,7 +12,8 @@
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#define PORT 7777 #define DEFAULT_PORT 7777
#define DEFAULT_IP "127.0.0.1"
#define BUFFER_SIZE 4096 #define BUFFER_SIZE 4096
#define USERNAME_MAX 50 #define USERNAME_MAX 50
#define INPUT_HEIGHT 3 #define INPUT_HEIGHT 3
@@ -34,6 +35,10 @@ int scroll_offset = 0;
unsigned char aes_key[AES_KEY_SIZE]; unsigned char aes_key[AES_KEY_SIZE];
// Параметры подключения
char server_ip[256] = DEFAULT_IP;
int server_port = DEFAULT_PORT;
volatile int need_redraw = 0; volatile int need_redraw = 0;
volatile int running = 1; volatile int running = 1;
@@ -299,7 +304,6 @@ void scroll_down() {
} }
} }
// Формат пакета: [total_len:4][iv:12][tag:16][ciphertext:N]
void send_encrypted_message(int socket, const char *plaintext) { void send_encrypted_message(int socket, const char *plaintext) {
unsigned char iv[AES_IV_SIZE]; unsigned char iv[AES_IV_SIZE];
RAND_bytes(iv, AES_IV_SIZE); RAND_bytes(iv, AES_IV_SIZE);
@@ -324,7 +328,6 @@ void send_encrypted_message(int socket, const char *plaintext) {
send(socket, ciphertext, ciphertext_len, 0); send(socket, ciphertext, ciphertext_len, 0);
} }
// Получить и расшифровать сообщение
int receive_encrypted_message(int socket, char *plaintext, int max_len) { int receive_encrypted_message(int socket, char *plaintext, int max_len) {
int net_total_len; int net_total_len;
int valread = read(socket, &net_total_len, sizeof(int)); int valread = read(socket, &net_total_len, sizeof(int));
@@ -424,7 +427,14 @@ void handle_input() {
return; return;
} }
// Форматируем и отправляем на сервер, НЕ добавляем локально! // Проверяем длину чтобы избежать truncation
int max_msg_len = BUFFER_SIZE - strlen(username) - 5;
if (max_msg_len < 0) max_msg_len = 0;
if ((int) strlen(input_buffer) > max_msg_len) {
input_buffer[max_msg_len] = '\0';
}
char full_msg[BUFFER_SIZE]; char full_msg[BUFFER_SIZE];
int written = snprintf(full_msg, sizeof(full_msg), "[%s]: %s", username, int written = snprintf(full_msg, sizeof(full_msg), "[%s]: %s", username,
input_buffer); input_buffer);
@@ -435,7 +445,6 @@ void handle_input() {
} }
send_encrypted_message(sock, full_msg); send_encrypted_message(sock, full_msg);
// Сообщение появится когда придёт от сервера в receive_messages()
pos = 0; pos = 0;
input_buffer[0] = '\0'; input_buffer[0] = '\0';
@@ -481,7 +490,6 @@ void receive_messages() {
char plaintext[BUFFER_SIZE]; char plaintext[BUFFER_SIZE];
int len = receive_encrypted_message(sock, plaintext, BUFFER_SIZE); int len = receive_encrypted_message(sock, plaintext, BUFFER_SIZE);
if (len > 0) { if (len > 0) {
// ВСЕ сообщения приходят через сервер — и свои, и чужие
add_chat_message(plaintext); add_chat_message(plaintext);
} else if (len < 0) { } else if (len < 0) {
add_chat_message("*** Ошибка расшифровки сообщения ***"); add_chat_message("*** Ошибка расшифровки сообщения ***");
@@ -498,18 +506,35 @@ void sigwinch_handler(int sig) {
void parse_args(int argc, char *argv[]) { void parse_args(int argc, char *argv[]) {
static struct option long_options[] = { static struct option long_options[] = {
{"messagebuffer", required_argument, 0, 'm'}, {0, 0, 0, 0}}; {"messagebuffer", required_argument, 0, 'm'},
{"ip", required_argument, 0, 'i'},
{"port", required_argument, 0, 'p'},
{0, 0, 0, 0}};
int opt; int opt;
while ((opt = getopt_long(argc, argv, "m:", long_options, NULL)) != -1) { while ((opt = getopt_long(argc, argv, "m:i:p:", long_options, NULL)) != -1) {
switch (opt) { switch (opt) {
case 'm': case 'm':
msg_buffer_size = atoi(optarg); msg_buffer_size = atoi(optarg);
if (msg_buffer_size < 10) msg_buffer_size = 10; if (msg_buffer_size < 10) msg_buffer_size = 10;
if (msg_buffer_size > 10000) msg_buffer_size = 10000; if (msg_buffer_size > 10000) msg_buffer_size = 10000;
break; break;
case 'i':
strncpy(server_ip, optarg, sizeof(server_ip) - 1);
server_ip[sizeof(server_ip) - 1] = '\0';
break;
case 'p':
server_port = atoi(optarg);
if (server_port < 1 || server_port > 65535) {
fprintf(stderr, "Invalid port: %s\n", optarg);
exit(1);
}
break;
default: default:
fprintf(stderr, "Usage: %s [-m N|--messagebuffer=N]\n", argv[0]); fprintf(stderr,
"Usage: %s [-m N|--messagebuffer=N] [-i IP|--ip=IP] [-p "
"PORT|--port=PORT]\n",
argv[0]);
exit(1); exit(1);
} }
} }
@@ -540,8 +565,13 @@ int main(int argc, char *argv[]) {
} }
server_addr.sin_family = AF_INET; server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT); server_addr.sin_port = htons(server_port);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); if (inet_pton(AF_INET, server_ip, &server_addr.sin_addr) <= 0) {
fprintf(stderr, "Invalid address: %s\n", server_ip);
return 1;
}
printf("[INFO] Connecting to %s:%d\n", server_ip, server_port);
if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) <
0) { 0) {
+49 -13
View File
@@ -1,4 +1,5 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <getopt.h>
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -6,7 +7,8 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#define PORT 7777 #define DEFAULT_PORT 7777
#define DEFAULT_IP "0.0.0.0"
#define BUFFER_SIZE 8192 #define BUFFER_SIZE 8192
#define MAX_CLIENTS 100 #define MAX_CLIENTS 100
#define HISTORY_SIZE 1000 #define HISTORY_SIZE 1000
@@ -32,6 +34,10 @@ int history_count = 0;
int history_start = 0; int history_start = 0;
pthread_mutex_t history_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t history_mutex = PTHREAD_MUTEX_INITIALIZER;
// Параметры сервера
char bind_ip[256] = DEFAULT_IP;
int bind_port = DEFAULT_PORT;
void add_to_history(const unsigned char *data, int len) { void add_to_history(const unsigned char *data, int len) {
pthread_mutex_lock(&history_mutex); pthread_mutex_lock(&history_mutex);
int idx = (history_start + history_count) % HISTORY_SIZE; int idx = (history_start + history_count) % HISTORY_SIZE;
@@ -65,7 +71,6 @@ void send_history(int socket) {
pthread_mutex_unlock(&history_mutex); pthread_mutex_unlock(&history_mutex);
} }
// Рассылка ВСЕМ клиентам включая отправителя (-1 = всем)
void broadcast_to_all(const unsigned char *data, int len) { void broadcast_to_all(const unsigned char *data, int len) {
pthread_mutex_lock(&clients_mutex); pthread_mutex_lock(&clients_mutex);
for (int i = 0; i < MAX_CLIENTS; i++) { for (int i = 0; i < MAX_CLIENTS; i++) {
@@ -79,14 +84,15 @@ void broadcast_to_all(const unsigned char *data, int len) {
} }
void *handle_client(void *arg) { void *handle_client(void *arg) {
client_t *cli = (client_t *)arg; client_t *cli = (client_t *) arg;
int valread = read(cli->socket, cli->username, USERNAME_MAX); int valread = read(cli->socket, cli->username, USERNAME_MAX);
if (valread <= 0) goto cleanup; if (valread <= 0) goto cleanup;
cli->username[valread] = '\0'; cli->username[valread] = '\0';
cli->username[strcspn(cli->username, "\n")] = '\0'; cli->username[strcspn(cli->username, "\n")] = '\0';
printf("User '%s' connected\n", cli->username); printf("User '%s' connected from %s\n", cli->username,
inet_ntoa(((struct sockaddr_in *) &cli)->sin_addr));
send_history(cli->socket); send_history(cli->socket);
@@ -112,10 +118,7 @@ void *handle_client(void *arg) {
total_read += valread; total_read += valread;
} }
// Сохраняем
add_to_history(data, total_len); add_to_history(data, total_len);
// Рассылаем ВСЕМ включая отправителя
broadcast_to_all(data, total_len); broadcast_to_all(data, total_len);
free(data); free(data);
@@ -138,12 +141,41 @@ cleanup:
pthread_exit(NULL); pthread_exit(NULL);
} }
int main() { void parse_args(int argc, char *argv[]) {
static struct option long_options[] = {{"ip", required_argument, 0, 'i'},
{"port", required_argument, 0, 'p'},
{0, 0, 0, 0}};
int opt;
while ((opt = getopt_long(argc, argv, "i:p:", long_options, NULL)) != -1) {
switch (opt) {
case 'i':
strncpy(bind_ip, optarg, sizeof(bind_ip) - 1);
bind_ip[sizeof(bind_ip) - 1] = '\0';
break;
case 'p':
bind_port = atoi(optarg);
if (bind_port < 1 || bind_port > 65535) {
fprintf(stderr, "Invalid port: %s\n", optarg);
exit(1);
}
break;
default:
fprintf(stderr, "Usage: %s [-i IP|--ip=IP] [-p PORT|--port=PORT]\n",
argv[0]);
exit(1);
}
}
}
int main(int argc, char *argv[]) {
int server_fd, new_socket; int server_fd, new_socket;
struct sockaddr_in address; struct sockaddr_in address;
int opt = 1; int opt = 1;
int addrlen = sizeof(address); int addrlen = sizeof(address);
parse_args(argc, argv);
for (int i = 0; i < HISTORY_SIZE; i++) { for (int i = 0; i < HISTORY_SIZE; i++) {
message_history[i].data = NULL; message_history[i].data = NULL;
message_history[i].data_len = 0; message_history[i].data_len = 0;
@@ -160,10 +192,13 @@ int main() {
} }
address.sin_family = AF_INET; address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(bind_port);
address.sin_port = htons(PORT); if (inet_pton(AF_INET, bind_ip, &address.sin_addr) <= 0) {
fprintf(stderr, "Invalid bind address: %s\n", bind_ip);
exit(EXIT_FAILURE);
}
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { if (bind(server_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
perror("bind failed"); perror("bind failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -173,10 +208,11 @@ int main() {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("E2E Encrypted Server listening on port %d\n", PORT); printf("E2E Encrypted Server listening on %s:%d\n", bind_ip, bind_port);
while (1) { while (1) {
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
(socklen_t *) &addrlen)) < 0) {
perror("accept"); perror("accept");
continue; continue;
} }