Compare commits

...

24 Commits

Author SHA1 Message Date
291a727dd3 Tried to work on fixing message string bug 2023-04-28 16:21:32 -05:00
a565c7ef29 Started working on README 2023-04-18 16:21:28 -05:00
fa1e8610f8 Fixed bug with manipulation of the message string, by creating a copy of the string parameter 2023-04-14 15:30:51 -05:00
9c87de7196 NEED TO FIX: updated some code, but it still retrieves wrong message length 2023-04-14 14:45:24 -05:00
34861b4644 Lots of little fixes, cleared buffer, fixed some minor bugs 2023-04-14 14:32:31 -05:00
a83338e8db Updated stack file; removed 'free' call 2023-04-14 14:31:43 -05:00
5bc6c575fc Started working on receiving messages 2023-04-14 08:11:09 -05:00
c8c9a34aab Used 'tm*' instead of 'tm' for storing time 2023-04-14 08:10:52 -05:00
868aaccf28 Added check for whether the destination user exists 2023-04-13 10:28:16 -05:00
97d1c9153b Added libstack files to Makefile 2023-04-13 10:27:10 -05:00
2c46754cb4 Took 'user*' as a parameter instead of 'user', returned 'Message*' instead of 'Message' 2023-04-13 10:26:10 -05:00
ad70f43da9 DOESN'T COMPILE - Started working on adding message to stack 2023-04-13 08:11:34 -05:00
df9a05a56e Added libstack files 2023-04-13 08:11:15 -05:00
1456b60ad9 Added check for NULL message 2023-04-11 23:02:20 -05:00
6be0bd8ce2 Finished working on 'fetch_message_string' function 2023-04-11 23:01:59 -05:00
d46d250b84 Continued refactoring code 2023-04-11 14:29:16 -05:00
70ecbae964 Removed unnecessary functions 2023-04-11 14:29:02 -05:00
ace4e3c8e5 Added code to retrieve sender (by calling the appropriate message_helper function), started refactoring code so that all data is processed in one shot, instead of waiting for multiple 'recv's 2023-04-11 08:09:27 -05:00
3e07370f31 Added function for retrieving sender, message, and a generic string 2023-04-11 08:08:32 -05:00
3125dd48d6 Fixed memory allocation bug in 'create_user_list' function 2023-04-09 10:52:28 -05:00
5bf131d00c Changed function name 2023-04-09 09:39:35 -05:00
42e12def81 Routine bugfixes 2023-04-09 09:39:12 -05:00
a5ac16f884 Reversed the order of file manipulation functions, which fixed the 'Corrupted top size' error 2023-04-06 17:51:17 -05:00
768d3fcedf Rewinded 'fp' before closing it 2023-04-06 17:50:10 -05:00
10 changed files with 371 additions and 71 deletions

View File

@@ -1,5 +1,5 @@
EXEC_FILE=main EXEC_FILE=main
TARGETS=$(EXEC_FILE).o message.o user.o message_helpers.o file_helpers.o TARGETS=$(EXEC_FILE).o message.o user.o message_helpers.o file_helpers.o stack.o
CFLAGS= CFLAGS=
@@ -14,6 +14,7 @@ message.o: message.c
user.o: user.c user.o: user.c
message_helpers.o: message_helpers.c message_helpers.o: message_helpers.c
file_helpers.o: file_helpers.c file_helpers.o: file_helpers.c
stack.o: stack.c
$(TARGETS): $(TARGETS):
gcc $(CFLAGS) -c -o $@ $^ gcc $(CFLAGS) -c -o $@ $^

14
README.md Normal file
View File

@@ -0,0 +1,14 @@
## Chat server
This is a simple, barely-working chat server (which uses a custom protocol). It is written in C, and relies on BSD sockets.
##Usage
To use it, compile the program with `make`.
TODO:
- Finish README
- Implement password authentication
- Fix bugs with message string manipulation (the actual message isn't being stored correctly, and contains extra characters).
- Do additional testing to ensure that everything works correctly (it probably doesn't).

View File

@@ -15,6 +15,7 @@ char* file_to_string(char* filename) {
fread(buffer,1,file_size,fp); fread(buffer,1,file_size,fp);
rewind(fp);
fclose(fp); fclose(fp);
return buffer; return buffer;
@@ -44,6 +45,7 @@ int num_of_lines(char* filename) {
} }
} }
rewind(fp);
fclose(fp); fclose(fp);
return num_lines; return num_lines;

224
main.c
View File

@@ -11,20 +11,26 @@
#include "easysock.h" #include "easysock.h"
#include "file_helpers.h" #include "file_helpers.h"
#include "message_helpers.h" #include "message_helpers.h"
#include "stack.h"
#define BUFFER_SIZE 10000 #define BUFFER_SIZE 10000
#define MAX_CONNECTIONS 100 #define MAX_CONNECTIONS 100
#define DATA_SIZE 50000
#define MESSAGE_SIZE 50000
User** create_user_list(char* filename); User** create_user_list(char* filename);
void sigint_handler(int dummy); void sigint_handler(int dummy);
User* fetch_user(char* username); User* fetch_user(char* username);
int user_to_index(User* user);
bool user_equals(User* this, User* other);
User** users; User** users;
int num_users; int num_users;
bool stop_running = false; bool stop_running;
int main() { int main() {
stop_running = false;
signal(SIGINT,sigint_handler); signal(SIGINT,sigint_handler);
@@ -32,13 +38,21 @@ int main() {
socklen_t temp_addrlen; socklen_t temp_addrlen;
fd_set read_fd_set; fd_set read_fd_set;
int conn_sockets[MAX_CONNECTIONS] = {-1}; int conn_sockets[MAX_CONNECTIONS] = {-1};
User* dest_users[MAX_CONNECTIONS] = {NULL}; User* to_user[MAX_CONNECTIONS] = {NULL};
FD_ZERO(&read_fd_set); User* from_user[MAX_CONNECTIONS] = {NULL};
char buffer[BUFFER_SIZE]; FD_ZERO(&read_fd_set); char buffer[BUFFER_SIZE];
users = create_user_list("user_file.txt"); char data[DATA_SIZE];
num_users = num_of_lines("user_file.txt");
num_users = num_of_lines("user_file.txt");
users = create_user_list("user_file.txt");
Stack* message_stack[num_users];
for (int i=0;i < num_users; i++) {
message_stack[i] = new_stack(10);
}
struct sockaddr addr_struct; struct sockaddr addr_struct;
int server_sock = create_local(4,'T',"127.0.0.1",30000,&addr_struct); int server_sock = create_local(4,'T',"127.0.0.1",30000,&addr_struct);
conn_sockets[0] = server_sock; conn_sockets[0] = server_sock;
@@ -67,55 +81,144 @@ int main() {
} }
for (int i=1; i < MAX_CONNECTIONS; i++) { for (int i=1; i < MAX_CONNECTIONS; i++) {
if (FD_ISSET(conn_sockets[i],&read_fd_set)) {
int num_bytes_read = recv(conn_sockets[i],buffer,sizeof(buffer),0);
if (num_bytes_read <= 0) {
close(conn_sockets[i]);
conn_sockets[i] = 0;
dest_users[i] = NULL;
} else {
if (dest_users[i] == NULL) {
dest_users[i] = fetch_user(user_string(buffer));
if (dest_users[i] == NULL) {
printf("Invalid message format or User\n");
exit(241);
} else {
printf("Message intended for %s\n",dest_users[i]->username);
exit(0);
}
memset(data,0x00,DATA_SIZE);
if (FD_ISSET(conn_sockets[i],&read_fd_set)) {
while ( strstr(buffer,"END_OF_DATA") == NULL ) {
int num_bytes_read = recv(conn_sockets[i],buffer,sizeof(buffer),0);
if (num_bytes_read <= 0) {
close(conn_sockets[i]);
conn_sockets[i] = 0;
to_user[i] = NULL;
goto continue_for_loop;
}
strcat(data, buffer);
}
strcat(data,"\0");
buffer[0] = '\0'; /* Clear the buffer */
char* send_or_receive = malloc(10);
int k=0;
while (*(data + k) != '\n') {
k++;
}
memcpy(send_or_receive,data,k);
if (strstr(send_or_receive, "SENDING") != NULL) {
if (from_user[i] == NULL) {
from_user[i] = fetch_user(fetch_from_string(data,"IAM"));
if (from_user[i] == NULL) {
printf("Please identify yourself.\n");
close(conn_sockets[i]);
continue;
} else {
printf("You are %s\n",from_user[i]->username);
}
}
if (to_user[i] == NULL) {
to_user[i] = fetch_user(fetch_from_string(data,"TO"));
if (to_user[i] == NULL) {
printf("Invalid user or message format.\n");
close(conn_sockets[i]);
continue;
} else {
printf("Message intended for %s\n",to_user[i]->username);
}
}
char* message_string = malloc(sizeof(char) * MESSAGE_SIZE);
memset(message_string, 0x00, MESSAGE_SIZE);
message_string = fetch_message_string(data);
if (message_string == NULL) {
printf("Invalid message.\n");
return -10;
}
printf("Your message is: \n------------------\n%s\n------------------\n",message_string);
if (user_to_index(to_user[i]) < 0) {
printf("Recipient user does not exist!\n");
return -20;
}
Message* message = new_message(message_string,from_user[i],to_user[i]);
stack_push( message_stack[user_to_index(to_user[i])],message );
printf("Message has been pushed onto stack for %s\n",to_user[i]->username);
} else if (strstr(send_or_receive, "RECEIVING") != NULL) {
if (from_user[i] == NULL) {
from_user[i] = fetch_user(fetch_from_string(data,"IAM"));
if (from_user[i] == NULL) {
printf("Please identify yourself.\n");
close(conn_sockets[i]);
continue;
} else {
printf("You are %s\n",from_user[i]->username);
}
}
int num_of_messages;
char* num_of_messages_string = fetch_from_string(data,"GETLAST");
if (num_of_messages_string == NULL) {
printf("Invalid GET request.\n");
return -30;
} else {
if (strstr(num_of_messages_string,"ALL") != NULL) {
num_of_messages = stack_size(message_stack[user_to_index(from_user[i])]);
} else {
num_of_messages = atoi(num_of_messages_string);
}
}
if (num_of_messages > stack_size(message_stack[user_to_index(from_user[i])])) {
num_of_messages = stack_size(message_stack[user_to_index(from_user[i])]);
}
for (int k=0;k<num_of_messages;k++) {
Message* message = stack_pop(message_stack[user_to_index(from_user[i])]);
printf("You have a message from %s"
", sent at %s"
": \"%s\"\n",
message->sender->username,
asctime(message->timeinfo),
message->text);
} }
} else {
// for (int i=0;i<num_bytes_read;i++) { printf("You are not sending or receiving.\n");
// printf("%c",buffer[i]);
// }
} }
close(conn_sockets[i]);
conn_sockets[i] = -1;
continue_for_loop:
memset(data,0,DATA_SIZE);
memset(buffer,0,BUFFER_SIZE);
to_user[i] = NULL;
from_user[i] = NULL;
} }
} }
}
if (stop_running) { if (stop_running == true) {
for (int i=0; i< MAX_CONNECTIONS; i++) { printf("Stopping...\n");
close(conn_sockets[i]); for (int i=MAX_CONNECTIONS-1; i>= 0; i--) {
close(i);
close(conn_sockets[i]);
}
return 130;
}
} }
exit(130);
}
} }
// Message message = new_message("Hello, this is a text message",users[0],users[1]);
// printf("Message was: %s\nSentfrom: %s\nSent to: %s\nWith password: %s\nSent at: %s\n",message.text, message.sender.username, message.recipient.username, message.recipient.password, asctime(&message.timeinfo));
} }
@@ -130,11 +233,15 @@ User** create_user_list(char* filename) {
char* token = malloc(sizeof(char) * 30); char* token = malloc(sizeof(char) * 30);
User** users = malloc (num_users * sizeof(User*)); User** users = malloc (num_users * sizeof(User*));
for (int i=0;i<num_users;i++) {
(*(users+i)) = malloc(sizeof(User));
}
token = strtok(file_str," \r\n"); token = strtok(file_str," \r\n");
for (int i=0;i<num_users-1;i++) { for (int i=0;i<num_users;i++) {
users[i]->username = strdup(token); (*(users + i))->username = strdup(token);
token = strtok(NULL," \r\n"); token = strtok(NULL," \r\n");
users[i]->password = strdup(token); (*(users + i))->password = strdup(token);
token = strtok(NULL," \r\n"); token = strtok(NULL," \r\n");
} }
@@ -143,7 +250,9 @@ User** create_user_list(char* filename) {
} }
void sigint_handler(int dummy) { void sigint_handler(int dummy) {
stop_running = true; stop_running = true;
printf("sigint_handler is stopping...\n");
exit(130);
} }
User* fetch_user(char* username) { User* fetch_user(char* username) {
@@ -159,3 +268,24 @@ User* fetch_user(char* username) {
return NULL; return NULL;
} }
int user_to_index(User* user) {
int index = -1;
for (int i=0;i < num_users; i++) {
if (user_equals(users[i],user) == true) {
index = i;
break;
}
}
return index;
}
bool user_equals(User* this, User* other) {
if (( strcmp(this->username,other->username) == 0 ) && ( strcmp(this->password,other->password) == 0 )) {
return true;
} else {
return false;
}
}

View File

@@ -4,22 +4,30 @@
#include <time.h> #include <time.h>
#include "message.h" #include "message.h"
Message new_message(char* string, User from, User to) { Message* new_message(char* string, User* from, User* to) {
Message new_message; Message* new_message;
new_message.text = malloc((strlen(string)+1)*sizeof(char)); new_message = malloc(sizeof(Message));
strcpy(new_message.text,string); new_message->text = malloc((strlen(string)+1)*sizeof(char));
strcpy(new_message->text,string);
new_message.sender = from; new_message->sender = malloc(sizeof(User));
new_message.recipient = to; new_message->recipient = malloc(sizeof(User));
memcpy(new_message->sender, from, sizeof(User));
memcpy(new_message->recipient, to, sizeof(User));
// *(new_message->sender) = *from;
// *(new_message->recipient) = *to;
time_t rawtime; time_t rawtime;
struct tm timeinfo; struct tm* timeinfo;
time(&rawtime); time(&rawtime);
timeinfo = *localtime(&rawtime); timeinfo = localtime(&rawtime);
new_message.timeinfo = timeinfo; new_message->timeinfo = timeinfo;
return new_message; return new_message;

View File

@@ -10,11 +10,11 @@ typedef struct Message_s Message;
struct Message_s { struct Message_s {
char* text; char* text;
struct tm timeinfo; struct tm* timeinfo;
User sender; User* sender;
User recipient; User* recipient;
}; };
Message new_message(char* text,User from,User to); Message* new_message(char* text,User* from,User* to);
#endif #endif

View File

@@ -2,14 +2,80 @@
#include "message_helpers.h" #include "message_helpers.h"
char* user_string(char* message) { char* fetch_from_string(char* message, char* indicator) {
char* token = malloc (sizeof(char) * strlen(message));
token = strtok(message," \r\n"); char* message_copy = malloc(strlen(message));
if (strcmp(token,"TO:") == 0) { strcpy(message_copy,message);
char* token = malloc (sizeof(char) * strlen(message_copy));
char* string_to_search = malloc(strlen(indicator) + 1);
strcpy(string_to_search,indicator);
strcat(string_to_search,":");
token = strtok(message_copy," r\n");
while (strcmp(token,string_to_search) != 0) {
token = strtok(NULL," \r\n"); token = strtok(NULL," \r\n");
} else { if (token == NULL) {
return NULL;
}
}
token = strtok(NULL," \r\n");
return token;
}
char* fetch_message_string(char* message) {
char* message_copy = malloc(strlen(message));
strcpy(message_copy,message);
int num_of_terminators = 0;
int start_index = 0;
int end_index = 0;
int message_length = 0;
char* start = strstr(message_copy,"START_OF_MESSAGE");
if (start == NULL) {
return NULL; return NULL;
} }
start_index = start - message_copy;
start_index += strlen("START_OF_MESSAGE");
return token; while (*(message_copy + start_index) == '\n' || *(message_copy + start_index) == '\r') {
start_index++;
}
char* end = strstr(message_copy,"END_OF_MESSAGE");
if (end == NULL) {
return NULL;
}
end_index = end - message_copy;
if (*(message_copy + end_index-2) == '\r') {
num_of_terminators = 2;
} else {
num_of_terminators = 1;
}
end_index -= num_of_terminators;
message_length = end_index - start_index;
char* message_string = malloc(message_length + 2);
printf("Message goes from %d to %d\n",start_index,end_index);
for (int i=0; i<message_length; i++) { /* The reason the upper-bound is message_length-1 is because the last
character is a new-line, which the user would not have typed. */
*(message_string + i) = *(message_copy + start_index + i);
printf("%c",*(message_string + i));
}
strcat(message_string,"\0");
// printf("%s\n",message_string);
// *(message_string + (message_length - num_of_terminators)) = '\0';
return message_string;
} }

View File

@@ -1,6 +1,12 @@
/* If the message contains a string of the form: /* If the message contains a string of the form:
TO: <Username> <Indicator>: <Value>
then return 'Username' */ Then return 'value' */
char* user_string(char* message); char* fetch_from_string(char* message, char* indicator);
/* If the message contains a string of the form:
START_OF_MESSAGE
<text>
END_OF_MESSAGE
Then return <text> */
char* fetch_message_string(char* message);

62
stack.c Normal file
View File

@@ -0,0 +1,62 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include "stack.h"
struct Stack {
void** data;
int top_index;
int capacity;
int curr_size;
};
Stack* new_stack(int stack_size) {
assert(stack_size > 0);
Stack* my_stack = malloc(sizeof(Stack));
my_stack->capacity = stack_size;
my_stack->data = malloc(stack_size);
my_stack->top_index = 0;
my_stack->curr_size = 0;
return my_stack;
}
void stack_push(Stack* stack,void* element) {
if (stack->curr_size >= stack->capacity-1) {
stack->data = realloc(stack->data, stack->capacity*2);
stack->capacity *= 2;
}
*(stack->data + stack->top_index) = element;
stack->top_index++;
stack->curr_size++;
return;
}
void* stack_pop(Stack* stack) {
assert( !(stack_isEmpty(stack)) );
// free(stack->data + stack->top_index);
stack->top_index--;
void* to_return = *(stack->data + stack->top_index);
*(stack->data + stack->top_index) = NULL;
stack->curr_size--;
return to_return;
}
void* stack_peek(Stack* stack) {
void* to_return = *(stack->data + stack->top_index - 1);
return to_return;
}
int stack_size(Stack* stack) {
return (stack->curr_size);
}
bool stack_isEmpty(Stack* stack) {
if (stack_size(stack) == 0) {
return true;
}
return false;
}

11
stack.h Normal file
View File

@@ -0,0 +1,11 @@
#include <stdbool.h>
typedef struct Stack Stack;
Stack* new_stack(int stack_size);
void stack_push(Stack* stack, void* element);
void* stack_pop(Stack* stack);
void* stack_peek(Stack* stack);
int stack_size(Stack* stack);
bool stack_isEmpty(Stack* stack);