Skip to content
Snippets Groups Projects
Commit 1188ab50 authored by Christopher Bohn's avatar Christopher Bohn :thinking:
Browse files

Added thread-based chat server

parent 35a3ff8b
No related branches found
No related tags found
No related merge requests found
......@@ -5,6 +5,7 @@ set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "-lncurses -lpthread")
add_executable(client chat.c chat-client.c)
add_executable(server chat.c chat-server.c chat-server-processes.c)
add_executable(server chat.c chat-server.c chat-server-threads.c)
add_executable(server-iterative chat.c chat-server.c chat-server-iterative.c)
add_executable(server-processes chat.c chat-server.c chat-server-processes.c)
add_executable(server-threads chat.c chat-server.c chat-server-threads.c)
\ No newline at end of file
......@@ -15,16 +15,13 @@ void initialize_curses(struct io_windows *windows);
void initialize_threads(struct io_threads *threads, struct io_windows *windows);
void *handle_inputs(void *window_arg);
void *handle_outputs(void *window_arg);
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
void on_signal();
#pragma clang diagnostic pop
void on_signal(int sig);
void cleanup();
bool running = true;
int socket_fd;
pthread_mutex_t mutex;
int initial_cursor_state;
bool running = true;
int main() {
struct io_windows windows;
......
......@@ -5,10 +5,10 @@ int accept_connection(int listening_socket_fd);
void manage_chat(int *socket_fd, char **client_names, int number_of_clients);
void on_signal(int sig);
bool running = true;
int client_count;
int *client_socket_fd;
bool *disconnected;
bool running = true;
int main(int argc, const char **argv) {
if (argc < 2) {
......
......@@ -9,7 +9,6 @@ void on_signal_listener(int sig);
void on_signal_handler(int sig);
void on_sigusr1(int sig);
bool running = true;
int pipe_to_repeater[2]; // write messages from clients to [1] -- repeater will read from [0]
int listening_socket_fd;
int accepted_socket_fd;
......@@ -17,6 +16,7 @@ int *client_socket_fd_list;
pid_t *client_handler_pid_list;
int client_list_length;
char name[BUFFER_SIZE];
bool running = true;
int main(int argc, const char **argv) {
if (argc != 2) {
......
#include <pthread.h>
#include "chat-server.h"
#include "chat.h"
void manage_server(int connect_socket_fd);
void *handle_client(void *args);
void on_signal(int sig);
void repeat_message(int *client_fd_list, int list_length, char *message);
int listening_socket_fd;
int *client_socket_fd_list;
int client_list_length;
pthread_mutex_t mutex;
bool running = true;
int main(int argc, const char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: ./server <portnumber>\n");
exit(1);
}
unsigned short port = (unsigned short)strtol(argv[1], NULL, 10);
struct sockaddr_in server_socket_address;
listening_socket_fd = listen_to_port(port, &server_socket_address);
sigset(SIGINT, on_signal);
sigset(SIGABRT, on_signal);
sigset(SIGKILL, on_signal);
sigset(SIGSEGV, on_signal);
sigset(SIGTERM, on_signal);
display_host_info(port);
pthread_mutex_init(&mutex, NULL);
manage_server(listening_socket_fd);
}
void manage_server(int connect_socket_fd) {
struct sockaddr_in client_address;
unsigned int client_address_length = sizeof(client_address);
client_socket_fd_list = calloc(CLIENT_QUEUE_DEPTH, sizeof(int)); // initial size
client_list_length = CLIENT_QUEUE_DEPTH;
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
pthread_t tid;
while (running) {
bzero((char *)&client_address, sizeof(struct sockaddr_in));
int *accepted_socket_fd = malloc(sizeof(int)); // so it's not on the original thread's stack
*accepted_socket_fd = accept(connect_socket_fd, (struct sockaddr *)&client_address, &client_address_length);
pthread_create(&tid, NULL, handle_client, accepted_socket_fd);
}
}
void *handle_client(void *args) {
int socket_fd = *((int *)args); // so it's on this thread's stack
free(args);
pthread_detach(pthread_self()); // so this thread can be reaped when it terminates
pthread_mutex_lock(&mutex);
add_client(socket_fd, &client_socket_fd_list, 0, NULL, &client_list_length);
pthread_mutex_unlock(&mutex);
char name[BUFFER_SIZE];
char *buffer = malloc(BUFFER_SIZE);
buffer = receive_message(socket_fd, buffer);
printf("[STATUS]\tAccepted connection from %s.\n", buffer);
strcpy(buffer, "[SERVER]\tPlease type your name.");
send_message(socket_fd, buffer);
buffer = receive_message(socket_fd, buffer);
printf("[STATUS]\tClient identified as %s.\n", buffer);
strncpy(name, buffer, BUFFER_SIZE);
sprintf(buffer, "[SERVER]\tWelcome, %s.", name);
send_message(socket_fd, buffer);
printf("[STATUS]\tThread %ld is listening for messages from %s.\n", (long)pthread_self(), name);
char *message_to_repeat = malloc(BUFFER_SIZE + strlen(name) + 3);
sprintf(message_to_repeat, "[SERVER]\t%s has joined the chat.", name);
bool me_running = true;
while (running && me_running) {
pthread_mutex_lock(&mutex);
repeat_message(client_socket_fd_list, client_list_length, message_to_repeat);
pthread_mutex_unlock(&mutex);
buffer = receive_message(socket_fd, buffer);
sprintf(message_to_repeat, "[%s]\t%s", name, buffer);
if (!strncmp(buffer, "EXIT", 4)) {
printf("%s\n", message_to_repeat);
pthread_mutex_lock(&mutex);
send_message(socket_fd, message_to_repeat);
pthread_mutex_unlock(&mutex);
sprintf(message_to_repeat, "[SERVER]\t%s has left the chat.", name);
me_running = false;
}
}
pthread_mutex_lock(&mutex);
remove_client(socket_fd, client_socket_fd_list, NULL);
repeat_message(client_socket_fd_list, client_list_length, message_to_repeat);
pthread_mutex_unlock(&mutex);
close(socket_fd);
free(message_to_repeat);
free(buffer);
return NULL;
}
void repeat_message(int *client_fd_list, int list_length, char *message) {
printf("%s\n", message);
for (int i = 0; i < list_length; i++) {
if (client_fd_list[i]) {
send_message(client_fd_list[i], message);
}
}
bzero(message, BUFFER_SIZE);
}
void on_signal(int sig) {
sigset(SIGINT, SIG_IGN);
sigset(SIGABRT, SIG_IGN);
sigset(SIGKILL, SIG_IGN);
sigset(SIGSEGV, SIG_IGN);
sigset(SIGTERM, SIG_IGN);
running = false;
close(listening_socket_fd);
pthread_mutex_lock(&mutex);
for(int i=0; i<client_list_length; i++) {
if(client_socket_fd_list[i]) {
send_message(client_socket_fd_list[i], "[SERVER]\tServer is terminating. EXIT");
close(client_socket_fd_list[i]);
}
}
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
exit(128 + sig);
}
\ No newline at end of file
#include "chat.h"
#include <signal.h>
#include <netdb.h>
#include "chat-server.h"
void display_host_info(unsigned short port) {
......@@ -56,35 +53,48 @@ int listen_to_port(unsigned short port, struct sockaddr_in *server_socket_addres
void add_client(int new_client_fd, int **client_fd_list, pid_t new_handler_pid, pid_t **handler_pid_list, int *list_length) {
int i = 0;
int *client_list = *client_fd_list;
int *handler_list = *handler_pid_list;
int *handler_list = NULL;
if (handler_pid_list) {
handler_list = *handler_pid_list;
}
while (client_list[i] && (i < *list_length)) {
i++;
}
if (i == *list_length) {
// need to grow the lists
client_list = calloc(2 * (*list_length), sizeof(int));
if (handler_list) {
handler_list = calloc(2 * (*list_length), sizeof(pid_t));
}
for (int j = 0; j < *list_length; j++) {
client_list[j] = (*client_fd_list)[j];
if (handler_list) {
handler_list[j] = (*handler_pid_list)[j];
}
}
free(*client_fd_list);
free(*handler_pid_list);
*list_length *= 2;
}
client_list[i] = new_client_fd;
handler_list[i] = new_handler_pid;
*client_fd_list = client_list;
if (handler_list) {
handler_list[i] = new_handler_pid;
*handler_pid_list = handler_list;
}
}
void remove_client(int exiting_client_fd, int *client_fd_list, pid_t *handler_pid_list) {
if (exiting_client_fd) {
while (*client_fd_list != exiting_client_fd) {
client_fd_list++;
if (handler_pid_list) {
handler_pid_list++;
}
}
*client_fd_list = 0;
if (handler_pid_list) {
*handler_pid_list = 0;
}
}
}
\ No newline at end of file
#include <errno.h>
#include "chat.h"
char *receive_message(int socket_fd, char *message_buffer) {
long number_of_received_bytes = read(socket_fd, message_buffer, BUFFER_SIZE - 1);
if (number_of_received_bytes < 0) {
if (!(errno == EBADF && !running)) {
perror("Error while receiving message");
}
number_of_received_bytes = 0;
}
message_buffer[number_of_received_bytes] = '\0';
......
......@@ -12,6 +12,8 @@
#define BUFFER_SIZE 256
extern bool running;
char *receive_message(int socket_fd, char *message_buffer);
void send_message(int socket_fd, char *message);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment