summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chatroom.c65
-rw-r--r--chatroom.h23
-rw-r--r--chatrooms.txt3
-rw-r--r--client.c102
-rw-r--r--client.h19
-rw-r--r--main.c57
-rw-r--r--makefile4
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
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..495d094
--- /dev/null
+++ b/main.c
@@ -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