update with end to end encryption
This commit is contained in:
1 parent
df50428f4c
commit
be0007b68a
5 files changed
+748
-134
No files matched your search
+186
-104
@@ -1,129 +1,211 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <asm-generic/socket.h>
|
||||
#include <colors.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include "log.h"
|
||||
|
||||
#define PORT 7777
|
||||
#define MAX_CLIENTS 10
|
||||
#define BUFFER_SIZE 1024
|
||||
#define BUFFER_SIZE 8192
|
||||
#define MAX_CLIENTS 100
|
||||
#define HISTORY_SIZE 1000
|
||||
#define USERNAME_MAX 50
|
||||
#define AES_IV_SIZE 12
|
||||
#define AES_TAG_SIZE 16
|
||||
|
||||
struct client_t {
|
||||
int sock;
|
||||
char username[50];
|
||||
};
|
||||
typedef struct {
|
||||
int socket;
|
||||
char username[USERNAME_MAX];
|
||||
} client_t;
|
||||
|
||||
client_t *clients[MAX_CLIENTS];
|
||||
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
typedef struct {
|
||||
int data_len;
|
||||
unsigned char *data;
|
||||
} encrypted_message_t;
|
||||
|
||||
encrypted_message_t message_history[HISTORY_SIZE];
|
||||
int history_count = 0;
|
||||
int history_start = 0;
|
||||
pthread_mutex_t history_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void add_to_history(const unsigned char *data, int len) {
|
||||
pthread_mutex_lock(&history_mutex);
|
||||
int idx = (history_start + history_count) % HISTORY_SIZE;
|
||||
|
||||
free(message_history[idx].data);
|
||||
message_history[idx].data = malloc(len);
|
||||
memcpy(message_history[idx].data, data, len);
|
||||
message_history[idx].data_len = len;
|
||||
|
||||
if (history_count < HISTORY_SIZE) {
|
||||
history_count++;
|
||||
} else {
|
||||
history_start = (history_start + 1) % HISTORY_SIZE;
|
||||
}
|
||||
pthread_mutex_unlock(&history_mutex);
|
||||
}
|
||||
|
||||
void send_history(int socket) {
|
||||
pthread_mutex_lock(&history_mutex);
|
||||
|
||||
int net_count = htonl(history_count);
|
||||
write(socket, &net_count, sizeof(int));
|
||||
|
||||
for (int i = 0; i < history_count; i++) {
|
||||
int idx = (history_start + i) % HISTORY_SIZE;
|
||||
int net_len = htonl(message_history[idx].data_len);
|
||||
write(socket, &net_len, sizeof(int));
|
||||
write(socket, message_history[idx].data, message_history[idx].data_len);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&history_mutex);
|
||||
}
|
||||
|
||||
// Рассылка ВСЕМ клиентам включая отправителя (-1 = всем)
|
||||
void broadcast_to_all(const unsigned char *data, int len) {
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
if (clients[i]) {
|
||||
int net_len = htonl(len);
|
||||
send(clients[i]->socket, &net_len, sizeof(int), 0);
|
||||
send(clients[i]->socket, data, len, 0);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
}
|
||||
|
||||
void *handle_client(void *arg) {
|
||||
client_t *cli = (client_t *)arg;
|
||||
|
||||
int valread = read(cli->socket, cli->username, USERNAME_MAX);
|
||||
if (valread <= 0) goto cleanup;
|
||||
cli->username[valread] = '\0';
|
||||
cli->username[strcspn(cli->username, "\n")] = '\0';
|
||||
|
||||
printf("User '%s' connected\n", cli->username);
|
||||
|
||||
send_history(cli->socket);
|
||||
|
||||
while (1) {
|
||||
int net_total_len;
|
||||
valread = read(cli->socket, &net_total_len, sizeof(int));
|
||||
if (valread <= 0) break;
|
||||
|
||||
int total_len = ntohl(net_total_len);
|
||||
if (total_len <= 0 || total_len > BUFFER_SIZE) {
|
||||
printf("Invalid length from %s: %d\n", cli->username, total_len);
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned char *data = malloc(total_len);
|
||||
int total_read = 0;
|
||||
while (total_read < total_len) {
|
||||
valread = read(cli->socket, data + total_read, total_len - total_read);
|
||||
if (valread <= 0) {
|
||||
free(data);
|
||||
goto cleanup;
|
||||
}
|
||||
total_read += valread;
|
||||
}
|
||||
|
||||
// Сохраняем
|
||||
add_to_history(data, total_len);
|
||||
|
||||
// Рассылаем ВСЕМ включая отправителя
|
||||
broadcast_to_all(data, total_len);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
printf("User '%s' disconnected\n", cli->username);
|
||||
close(cli->socket);
|
||||
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
if (clients[i] == cli) {
|
||||
clients[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
|
||||
free(cli);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
int server_fd;
|
||||
struct client_t clients[MAX_CLIENTS];
|
||||
struct sockaddr_in address;
|
||||
int addrlen = sizeof(address);
|
||||
fd_set readfds;
|
||||
char buffer[BUFFER_SIZE];
|
||||
int server_fd, new_socket;
|
||||
struct sockaddr_in address;
|
||||
int opt = 1;
|
||||
int addrlen = sizeof(address);
|
||||
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
clients[i].sock = 0;
|
||||
bzero(clients[i].username, sizeof(clients[i].username));
|
||||
}
|
||||
|
||||
server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_fd < 0) {
|
||||
log_error("socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
|
||||
log_error("setsockopt");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(PORT);
|
||||
|
||||
if (bind(server_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
|
||||
log_error("bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (listen(server_fd, 5) < 0) {
|
||||
log_error("listen");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Chat server started on port %d\n", PORT);
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(server_fd, &readfds);
|
||||
int max_sd = server_fd;
|
||||
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
int sd = clients[i].sock;
|
||||
if (sd > 0) FD_SET(sd, &readfds);
|
||||
if (sd > max_sd) max_sd = sd;
|
||||
for (int i = 0; i < HISTORY_SIZE; i++) {
|
||||
message_history[i].data = NULL;
|
||||
message_history[i].data_len = 0;
|
||||
}
|
||||
|
||||
if (select(max_sd + 1, &readfds, NULL, NULL, NULL) < 0) {
|
||||
log_error("select");
|
||||
exit(EXIT_FAILURE);
|
||||
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||
perror("socket failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Новое подключение
|
||||
if (FD_ISSET(server_fd, &readfds)) {
|
||||
int new_socket = accept(server_fd, (struct sockaddr *) &address,
|
||||
(socklen_t *) &addrlen);
|
||||
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
|
||||
perror("setsockopt");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
log_info("New connection: socket %d\n", new_socket);
|
||||
read(new_socket, buffer, BUFFER_SIZE);
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(PORT);
|
||||
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
if (clients[i].sock == 0) {
|
||||
clients[i].sock = new_socket;
|
||||
strcpy(clients[i].username, buffer);
|
||||
break;
|
||||
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
||||
perror("bind failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (listen(server_fd, 3) < 0) {
|
||||
perror("listen");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("E2E Encrypted Server listening on port %d\n", PORT);
|
||||
|
||||
while (1) {
|
||||
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
|
||||
perror("accept");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Сообщения от клиентов
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
int sd = clients[i].sock;
|
||||
char sd_username[50];
|
||||
bzero(sd_username, sizeof(sd_username));
|
||||
strcpy(sd_username, clients[i].username);
|
||||
client_t *cli = malloc(sizeof(client_t));
|
||||
cli->socket = new_socket;
|
||||
|
||||
if (FD_ISSET(sd, &readfds)) {
|
||||
int valread = read(sd, buffer, BUFFER_SIZE);
|
||||
|
||||
if (valread == 0) {
|
||||
log_info("Client disconnected: socket %d\n", sd);
|
||||
close(sd);
|
||||
clients[i].sock = 0;
|
||||
bzero(clients[i].username, sizeof(clients[i].username));
|
||||
} else {
|
||||
buffer[valread] = '\0';
|
||||
log_info("[%s]: %s", sd_username, buffer);
|
||||
char *message = malloc(strlen(buffer) + strlen(sd_username) + 5);
|
||||
sprintf(message, "[%s]: %s", sd_username, buffer);
|
||||
// Рассылка всем другим
|
||||
for (int j = 0; j < MAX_CLIENTS; j++) {
|
||||
if (clients[j].sock != 0 && clients[j].sock != sd) {
|
||||
send(clients[j].sock, message, strlen(message), 0);
|
||||
free(message);
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
int added = 0;
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
if (!clients[i]) {
|
||||
clients[i] = cli;
|
||||
added = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
|
||||
return 0;
|
||||
if (!added) {
|
||||
printf("Max clients reached\n");
|
||||
close(new_socket);
|
||||
free(cli);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_t tid;
|
||||
pthread_create(&tid, NULL, handle_client, cli);
|
||||
pthread_detach(tid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user