diff options
-rw-r--r-- | chatroom.c | 65 | ||||
-rw-r--r-- | chatroom.h | 23 | ||||
-rw-r--r-- | chatrooms.txt | 3 | ||||
-rw-r--r-- | client.c | 102 | ||||
-rw-r--r-- | client.h | 19 | ||||
-rw-r--r-- | main.c | 57 | ||||
-rw-r--r-- | makefile | 4 |
7 files changed, 273 insertions, 0 deletions
diff --git a/chatroom.c b/chatroom.c new file mode 100644 index 0000000..e2a6b1a --- /dev/null +++ b/chatroom.c @@ -0,0 +1,65 @@ +#include "client.h" +#include "chatroom.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +chatroom_t chatrooms[MAX_CHATROOMS]; +int chatroom_count = 0; + +void load_chatrooms(const char *filename) { + FILE *fp = fopen(filename, "r"); + if (!fp) { + perror("chatroom file"); + exit(1); + } + + while (fscanf(fp, "%s %d %s %s %[^\n]", + chatrooms[chatroom_count].name, + &chatrooms[chatroom_count].users, + chatrooms[chatroom_count].created, + chatrooms[chatroom_count].time, + chatrooms[chatroom_count].topic) == 5) { + chatroom_count++; + } + + fclose(fp); +} + +void print_chatroom_list(int sock) { + send_to_client(sock, "room-name # created time topic\n"); + send_to_client(sock, "--------------------------------------------------------\n"); + for (int i = 0; i < chatroom_count; i++) { + char line[BUFFER_SIZE]; + snprintf(line, sizeof(line), "%-10s %-4d %-12s %-8s %s\n", + chatrooms[i].name, + chatrooms[i].users, + chatrooms[i].created, + chatrooms[i].time, + chatrooms[i].topic); + send_to_client(sock, line); + } + send_to_client(sock, "--------------------------------------------------------\n"); +} + +int join_chatroom(const char *name, client_t *cli) { + for (int i = 0; i < chatroom_count; i++) { + if (strcmp(chatrooms[i].name, name) == 0) { + leave_chatroom(cli); + strncpy(cli->room, name, sizeof(cli->room) - 1); + chatrooms[i].users++; + return 1; + } + } + return 0; +} + +void leave_chatroom(client_t *cli) { + for (int i = 0; i < chatroom_count; i++) { + if (strcmp(chatrooms[i].name, cli->room) == 0) { + chatrooms[i].users--; + break; + } + } + strcpy(cli->room, ""); +} diff --git a/chatroom.h b/chatroom.h new file mode 100644 index 0000000..a51f984 --- /dev/null +++ b/chatroom.h @@ -0,0 +1,23 @@ +#ifndef CHATROOM_H +#define CHATROOM_H + +#define MAX_CHATROOMS 32 + +typedef struct { + char name[50]; + int users; + char created[20]; + char time[20]; + char topic[100]; +} chatroom_t; + +extern chatroom_t chatrooms[MAX_CHATROOMS]; +extern int chatroom_count; + +void load_chatrooms(const char *filename); +void print_chatroom_list(int sock); +int join_chatroom(const char *name, client_t *cli); +void leave_chatroom(client_t *cli); + +#endif + diff --git a/chatrooms.txt b/chatrooms.txt new file mode 100644 index 0000000..255513a --- /dev/null +++ b/chatrooms.txt @@ -0,0 +1,3 @@ +spacebar 0 22-Aug-16 08:49:32 there is life out there +lobby 0 09-Sep-16 08:49:13 SDF's Welcoming Room +anonradio 0 09-Sep-16 04:11:06 DJ Kumata! diff --git a/client.c b/client.c new file mode 100644 index 0000000..2099862 --- /dev/null +++ b/client.c @@ -0,0 +1,102 @@ +#include "client.h" +#include "chatroom.h" +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <arpa/inet.h> + +extern client_t *clients[]; +extern pthread_mutex_t clients_mutex; + +void send_to_client(int sock, const char *msg) { + send(sock, msg, strlen(msg), 0); +} + +void broadcast_message(const char *message, int sender_sock) { + pthread_mutex_lock(&clients_mutex); + + client_t *sender = NULL; + for (int i = 0; i < 10; i++) { + if (clients[i] && clients[i]->socket == sender_sock) { + sender = clients[i]; + break; + } + } + + if (sender == NULL || strlen(sender->room) == 0) { + pthread_mutex_unlock(&clients_mutex); + return; + } + + for (int i = 0; i < 10; i++) { + if (clients[i] && clients[i]->socket != sender_sock && + strcmp(clients[i]->room, sender->room) == 0) { + send_to_client(clients[i]->socket, message); + } + } + + pthread_mutex_unlock(&clients_mutex); +} + +void *handle_client(void *arg) { + client_t *cli = (client_t *)arg; + char buffer[BUFFER_SIZE]; + int bytes; + + while ((bytes = recv(cli->socket, buffer, BUFFER_SIZE - 1, 0)) > 0) { + buffer[bytes] = '\0'; + + if (strncmp(buffer, "/join ", 6) == 0) { + char room[50]; + sscanf(buffer + 6, "%s", room); + if (join_chatroom(room, cli)) { + char msg[128]; + snprintf(msg, sizeof(msg), "You joined '%s'\n", room); + send_to_client(cli->socket, msg); + } else { + send_to_client(cli->socket, "Room does not exist.\n"); + } + } + else if (strncmp(buffer, "/list", 5) == 0) { + print_chatroom_list(cli->socket); + } + else if (strncmp(buffer, "/users", 6) == 0) { + pthread_mutex_lock(&clients_mutex); + int count = 0; + for (int i = 0; i < 10; i++) + if (clients[i] && strcmp(clients[i]->room, cli->room) == 0) + count++; + + char header[BUFFER_SIZE]; + snprintf(header, sizeof(header), "[you are in '%s' among %d]\n\n", cli->room, count); + send_to_client(cli->socket, header); + + for (int i = 0; i < 10; i++) { + if (clients[i] && strcmp(clients[i]->room, cli->room) == 0) { + char line[BUFFER_SIZE]; + snprintf(line, sizeof(line), "%s@%s\n", clients[i]->username, + inet_ntoa(clients[i]->address.sin_addr)); + send_to_client(cli->socket, line); + } + } + pthread_mutex_unlock(&clients_mutex); + } + else { + broadcast_message(buffer, cli->socket); + } + } + + close(cli->socket); + pthread_mutex_lock(&clients_mutex); + for (int i = 0; i < 10; i++) { + if (clients[i] == cli) { + leave_chatroom(cli); + clients[i] = NULL; + break; + } + } + pthread_mutex_unlock(&clients_mutex); + free(cli); + pthread_exit(NULL); +} diff --git a/client.h b/client.h new file mode 100644 index 0000000..ea19034 --- /dev/null +++ b/client.h @@ -0,0 +1,19 @@ +#ifndef CLIENT_H +#define CLIENT_H + +#include <netinet/in.h> + +#define BUFFER_SIZE 512 + +typedef struct { + int socket; + struct sockaddr_in address; + char username[50]; + char room[50]; +} client_t; + +void *handle_client(void *arg); +void send_to_client(int sock, const char *msg); +void broadcast_message(const char *message, int sender_sock); + +#endif @@ -0,0 +1,57 @@ +#include "client.h" +#include "chatroom.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <pthread.h> + +#define PORT 6667 +#define MAX_CLIENTS 10 + +client_t *clients[MAX_CLIENTS] = {0}; +pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; + +int main() { + int server_sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in server_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = INADDR_ANY, + .sin_port = htons(PORT) + }; + + bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)); + listen(server_sock, MAX_CLIENTS); + load_chatrooms("chatrooms.txt"); + + printf("Server listening on port %d...\n", PORT); + + while (1) { + struct sockaddr_in client_addr; + socklen_t len = sizeof(client_addr); + int client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &len); + + client_t *cli = malloc(sizeof(client_t)); + cli->socket = client_sock; + cli->address = client_addr; + strcpy(cli->username, "anonymous"); + strcpy(cli->room, ""); + + pthread_mutex_lock(&clients_mutex); + for (int i = 0; i < MAX_CLIENTS; i++) { + if (!clients[i]) { + clients[i] = cli; + pthread_t tid; + pthread_create(&tid, NULL, handle_client, cli); + pthread_detach(tid); + break; + } + } + pthread_mutex_unlock(&clients_mutex); + } + + close(server_sock); + return 0; +} + diff --git a/makefile b/makefile new file mode 100644 index 0000000..41d3b13 --- /dev/null +++ b/makefile @@ -0,0 +1,4 @@ +all: chatserver + +chatserver: main.c client.c chatroom.c + $(CC) -pthread -o chatserver main.c client.c chatroom.c |