Compare commits

...

39 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
65f731651b Added code for returning User instead of IP address 2023-04-05 16:24:22 -05:00
84a2a79b89 Used Users instead of IP addresses 2023-04-05 16:23:59 -05:00
3b71854b62 Finished message address checking, worked on SIGINT handling 2023-04-05 10:29:12 -05:00
d294a4411f Added 'allwarn' and 'debug' targerts 2023-04-05 10:28:43 -05:00
770c03cf76 Added delimiter to 'strtok' function 2023-04-05 10:28:29 -05:00
a940d7acad Updated .gitignore to ignore object files 2023-04-05 08:13:29 -05:00
67466ade6e Continued working on retrieving IP address from message 2023-04-05 08:13:05 -05:00
eefe9fbf1b Added Makefile rules for compiling, linking and deleting compiled files 2023-04-04 08:08:55 -05:00
ba35b8acdd Moved file manipulation functions to helper files 2023-04-04 08:08:22 -05:00
cfc8fbbb7b Updated .gitignore 2023-04-04 08:07:36 -05:00
d0c624e319 Added helper functions for file manipulation 2023-04-04 08:07:08 -05:00
f3f66297c2 Added helper functions for message string manipulation 2023-04-04 08:06:44 -05:00
13858dc352 Added helper functions for file manipulation 2023-04-04 08:06:28 -05:00
e5e3e8db72 Fixed segfault issue by using MAX_CONNECTIONS instead of 'sizeof' 2023-04-03 10:24:45 -05:00
423404826e Removed socket library, I'm using the '.so' file instead 2023-04-03 10:23:47 -05:00
14 changed files with 509 additions and 331 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
main
user_file.txt
*.o

34
Makefile Normal file
View File

@@ -0,0 +1,34 @@
EXEC_FILE=main
TARGETS=$(EXEC_FILE).o message.o user.o message_helpers.o file_helpers.o stack.o
CFLAGS=
all: $(EXEC_FILE)
$(EXEC_FILE): $(TARGETS)
gcc $(CFLAGS) -o $(EXEC_FILE) $^ -leasysock
$(EXEC_FILE).o: $(EXEC_FILE).c
message.o: message.c
user.o: user.c
message_helpers.o: message_helpers.c
file_helpers.o: file_helpers.c
stack.o: stack.c
$(TARGETS):
gcc $(CFLAGS) -c -o $@ $^
.PHONY: debug
debug: CFLAGS+=-g
debug: $(EXEC_FILE)
.PHONY: allwarn
allwarn: CFLAGS+=-Wall -Wextra -pedantic
allwarn: $(EXEC_FILE)
.PHONY: clean
clean:
rm $(TARGETS)
rm $(EXEC_FILE)

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

@@ -1,169 +0,0 @@
#include "easysock.h"
int create_socket(int network, char transport) {
int domain;
int type;
if (network == 4) {
domain = AF_INET;
} else if (network == 6) {
domain = AF_INET6;
} else {
return -1;
}
if (transport == 'T') {
type = SOCK_STREAM;
} else if (transport == 'U') {
type = SOCK_DGRAM;
} else {
return -1;
}
int newSock = socket(domain,type,0);
return newSock;
}
void create_addr(int network, char* address, int port,struct sockaddr* dest) {
if (network == 4) {
struct sockaddr_in listen_address;
listen_address.sin_family = AF_INET;
listen_address.sin_port = htons(port);
inet_pton(AF_INET,address,&listen_address.sin_addr);
memcpy(dest,&listen_address,sizeof(listen_address));
return;
} else if (network == 6) {
struct sockaddr_in6 listen_ipv6;
listen_ipv6.sin6_family = AF_INET6;
listen_ipv6.sin6_port = htons(port);
inet_pton(AF_INET6,address,&listen_ipv6.sin6_addr);
memcpy(dest,&listen_ipv6,sizeof(listen_ipv6));
return;
} else {
exit(202);
}
}
int create_local (int network, char transport, char* address, int port,struct sockaddr* addr_struct) {
int socket = create_socket(network,transport);
if (socket < 0) {
exit(errno);
}
create_addr(network,address,port,addr_struct);
int addrlen;
if (network == 4) {
addrlen = sizeof(struct sockaddr_in);
} else if (network == 6) {
addrlen = sizeof(struct sockaddr_in6);
} else {
exit(207);
}
/* The value of addrlen should be the size of the 'sockaddr'.
This should be set to the size of 'sockaddr_in' for IPv4, and 'sockaddr_in6' for IPv6.
See https://stackoverflow.com/questions/73707162/socket-bind-failed-with-invalid-argument-error-for-program-running-on-macos */
int i = bind (socket,addr_struct,(socklen_t)addrlen);
if (i < 0) {
exit(errno);
}
return socket;
}
int create_remote (int network,char transport,char* address,int port,struct sockaddr* remote_addr_struct) {
struct addrinfo hints; /* Used to tell getaddrinfo what kind of address we want */
struct addrinfo* results; /* Used by getaddrinfo to store the addresses */
if (check_ip_ver(address) < 0) { /* If the address is a domain name */
int err_code;
char* port_str = malloc(10 * sizeof(char));
sprintf(port_str,"%d",port); /* getaddrinfo expects a string for its port */
memset(&hints,'\0',sizeof(hints));
hints.ai_socktype = char_to_socktype(transport);
err_code = getaddrinfo(address,port_str,&hints,&results);
if (err_code != 0) {
exit(err_code);
}
remote_addr_struct = results->ai_addr;
network = inet_to_int(results->ai_family);
} else {
create_addr(network,address,port,remote_addr_struct);
}
int socket = create_socket(network,transport);
if (socket < 0) {
exit(errno);
}
int addrlen;
if (network == 4) {
addrlen = sizeof(struct sockaddr_in);
} else if (network == 6) {
addrlen = sizeof(struct sockaddr_in6);
} else {
exit(207);
}
/* The value of addrlen should be the size of the 'sockaddr'.
This should be set to the size of 'sockaddr_in' for IPv4, and 'sockaddr_in6' for IPv6.
See https://stackoverflow.com/questions/73707162/socket-bind-failed-with-invalid-argument-error-for-program-running-on-macos */
int i = connect(socket,remote_addr_struct,(socklen_t)addrlen);
if (i < 0) {
exit(errno);
}
return socket;
}
int check_ip_ver(char* address) {
char buffer[16]; /* 16 chars - 128 bits - is enough to hold an ipv6 address */
if (inet_pton(AF_INET,address,buffer) == 1) {
return 4;
} else if (inet_pton(AF_INET6,address,buffer) == 1) {
return 6;
} else {
return -1;
}
}
int int_to_inet(int network) {
if (network == 4) {
return AF_INET;
} else if (network == 6) {
return AF_INET6;
} else {
exit(207);
}
}
int inet_to_int(int af_type) {
if (af_type == AF_INET) {
return 4;
} else if (af_type == AF_INET6) {
return 6;
} else {
exit(207);
}
}
int char_to_socktype(char transport) {
if (transport == 'T') {
return SOCK_STREAM;
} else if (transport == 'U') {
return SOCK_DGRAM;
} else {
exit(250);
}
}

View File

@@ -1,75 +0,0 @@
#ifndef EASYSOCK_H_
#define EASYSOCK_H_
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
/* This function takes:
a layer 3 - network layer - integer, which must be '4' for IPv4
and 6 for IPv6; and
a layer 4 - transport layer - character, which must be 'T' for
TCP or 'U' for UDP.
It returns the created socket, or -1 if the socket creation failed.*/
int create_socket(int network, char transport);
/* This function fills in the sockaddr struct 'dest' based on the given information.
'network' is an integer that contains '4' for IPv4 or '6' for IPv6;
'address' is the address that is filled into the struct;
port is self-explanatory;
and dest is a pointer to the sockaddr struct that will be filled in.
The function exits with error code 202 if the network parameter contained neither '4'
nor '6'. */
void create_addr(int network, char* address, int port,struct sockaddr* dest);
/* This function utilizes the above two functions; it creates the socket and
_binds_ the addresses. It is used for local sockets (server sockets). Parameters are
same as above.
It prints the error returned by 'bind' if something went wrong, and exits with errno.*/
int create_local (int network, char transport, char* address, int port,struct sockaddr* addr_struct);
/* This function utilizes the same functions as 'create_local' but _connects_ to the
requested address. It is used for remote sockets (client sockets). The paramters are same
as above. This function needs an empty 'sockaddr *' structure passed to it, which it will fill.
It prints the error returned by 'connect' if something went wrong, and exits with errno.*/
int create_remote (int network,char transport,char* address,int port,struct sockaddr* remote_addr_struct);
/* check_ip_ver - This function checks if the given string is an IPv4 address (returns 4),
IPv6 address (returns 6) or neither (returns -1). */
int check_ip_ver(char* address);
/* int_to_inet - Takes an int value (4 for IPv4, 6 for IPv6) and returns AF_INET or
AF_INET6 respectively. */
int int_to_inet(int network);
/* char_to_socktype - Takes a character that represents a transport-layer protocol
(currently only supports 'T' for TCP or 'U' for UDP - exits with error code 250 if
the given characters is neither of these) and return the appropriate SOCKTYPE value. */
int char_to_socktype(char transport);
/* inet_to_int - Takes an int value that corresponds to AF_INET or AF_INET6,
and returns the appropriate int value. */
int inet_to_int(int af_type);
#endif

53
file_helpers.c Normal file
View File

@@ -0,0 +1,53 @@
#include <stdlib.h>
#include <stdio.h>
#include "file_helpers.h"
char* file_to_string(char* filename) {
FILE* fp = fopen(filename,"r");
fseek(fp,0,SEEK_END);
long file_size = ftell(fp);
rewind(fp);
char* buffer = calloc(sizeof(char),file_size+1);
fread(buffer,1,file_size,fp);
rewind(fp);
fclose(fp);
return buffer;
}
/* Finds the number of lines in a file (Which MUST end in a new-line, if the last
line is to be counted) */
int num_of_lines(char* filename) {
int num_lines = 0;
FILE* fp = fopen(filename,"r");
if (fp == NULL) {
return -1;
}
for (int c = getc(fp); c != EOF; c = getc(fp)) {
if (c == '\n') {
num_lines++;
}
}
rewind(fp);
fclose(fp);
return num_lines;
}

11
file_helpers.h Normal file
View File

@@ -0,0 +1,11 @@
/* Takes a string that represents a filename, and converts the contents
of the file into a string */
char* file_to_string(char* filename);
/*Finds the number of new-line characters in the given file */
int num_of_lines(char* filename);

282
main.c
View File

@@ -1,30 +1,58 @@
#include "message.h"
#include "user.h"
#include "easysock.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include "message.h"
#include "user.h"
#include "easysock.h"
#include "file_helpers.h"
#include "message_helpers.h"
#include "stack.h"
#define BUFFER_SIZE 10000
#define MAX_CONNECTIONS 100
#define DATA_SIZE 50000
#define MESSAGE_SIZE 50000
int num_of_lines(char* filename);
char* file_to_string(char* filename);
User* create_user_list(char* filename);
User** create_user_list(char* filename);
void sigint_handler(int dummy);
User* fetch_user(char* username);
int user_to_index(User* user);
bool user_equals(User* this, User* other);
User** users;
int num_users;
bool stop_running;
int main() {
stop_running = false;
signal(SIGINT,sigint_handler);
struct sockaddr temp_addr;
socklen_t temp_addrlen;
fd_set read_fd_set;
int conn_sockets[MAX_CONNECTIONS] = {0};
FD_ZERO(&read_fd_set);
char buffer[BUFFER_SIZE];
User* users = create_user_list("user_file.txt");
int conn_sockets[MAX_CONNECTIONS] = {-1};
User* to_user[MAX_CONNECTIONS] = {NULL};
User* from_user[MAX_CONNECTIONS] = {NULL};
FD_ZERO(&read_fd_set); char buffer[BUFFER_SIZE];
char data[DATA_SIZE];
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;
int server_sock = create_local(4,'T',"127.0.0.1",30000,&addr_struct);
conn_sockets[0] = server_sock;
@@ -33,7 +61,7 @@ int main() {
while (true) {
FD_ZERO(&read_fd_set);
for (int i=0; i < sizeof(conn_sockets); i++) {
for (int i=0; i < MAX_CONNECTIONS; i++) {
if (conn_sockets[i] > 0) {
FD_SET(conn_sockets[i],&read_fd_set);
}
@@ -44,7 +72,7 @@ int main() {
if (num_conns > 0) {
if (FD_ISSET(conn_sockets[0],&read_fd_set)) {
int client_sock = accept(conn_sockets[0],&temp_addr,&temp_addrlen);
for (int i=0;i < sizeof(conn_sockets); i++) {
for (int i=0;i < MAX_CONNECTIONS; i++) {
if (conn_sockets[i] <= 0) {
conn_sockets[i] = client_sock;
break;
@@ -52,41 +80,150 @@ int main() {
}
}
for (int i=1; i < sizeof(conn_sockets); i++) {
printf("Checking FD: %d\n",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] = -1;
} else {
for (int i=0;i<num_bytes_read;i++) {
printf("%c",buffer[i]);
}
}
for (int i=1; i < MAX_CONNECTIONS; i++) {
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 {
printf("You are not sending or receiving.\n");
}
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 == true) {
printf("Stopping...\n");
for (int i=MAX_CONNECTIONS-1; i>= 0; i--) {
close(i);
close(conn_sockets[i]);
}
return 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));
}
User* create_user_list(char* filename) {
User** create_user_list(char* filename) {
/* Structure of user file - <username> <password> on every line */
@@ -94,13 +231,17 @@ User* create_user_list(char* filename) {
char* file_str = file_to_string(filename);
char* token = malloc(sizeof(char) * 30);
User* users = calloc(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");
for (int i=0;i<num_users;i++) {
users[i].username = token;
(*(users + i))->username = strdup(token);
token = strtok(NULL," \r\n");
users[i].password = token;
(*(users + i))->password = strdup(token);
token = strtok(NULL," \r\n");
}
@@ -108,50 +249,43 @@ User* create_user_list(char* filename) {
}
char* file_to_string(char* filename) {
FILE* fp = fopen(filename,"r");
fseek(fp,0,SEEK_END);
long file_size = ftell(fp);
rewind(fp);
char* buffer = calloc(sizeof(char),file_size+1);
fread(buffer,1,file_size,fp);
fclose(fp);
return buffer;
void sigint_handler(int dummy) {
stop_running = true;
printf("sigint_handler is stopping...\n");
exit(130);
}
/* Finds the number of lines in a file (Which MUST end in a new-line, if the last
line is to be counted) */
int num_of_lines(char* filename) {
int num_lines = 0;
FILE* fp = fopen(filename,"r");
if (fp == NULL) {
return -1;
User* fetch_user(char* username) {
if (username == NULL) {
return NULL;
}
for (int c = getc(fp); c != EOF; c = getc(fp)) {
if (c == '\n') {
num_lines++;
for (int i=0;i<num_users;i++) {
if (strcmp(users[i]->username, username) == 0) {
return users[i];
}
}
fclose(fp);
return NULL;
}
return num_lines;
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 "message.h"
Message new_message(char* string, User from, User to) {
Message new_message;
Message* new_message(char* string, User* from, User* to) {
Message* new_message;
new_message.text = malloc((strlen(string)+1)*sizeof(char));
strcpy(new_message.text,string);
new_message = malloc(sizeof(Message));
new_message->text = malloc((strlen(string)+1)*sizeof(char));
strcpy(new_message->text,string);
new_message.sender = from;
new_message.recipient = to;
new_message->sender = malloc(sizeof(User));
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;
struct tm timeinfo;
struct tm* timeinfo;
time(&rawtime);
timeinfo = *localtime(&rawtime);
timeinfo = localtime(&rawtime);
new_message.timeinfo = timeinfo;
new_message->timeinfo = timeinfo;
return new_message;

View File

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

81
message_helpers.c Normal file
View File

@@ -0,0 +1,81 @@
#include <easysock.h>
#include "message_helpers.h"
char* fetch_from_string(char* message, char* indicator) {
char* message_copy = malloc(strlen(message));
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");
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;
}
start_index = start - message_copy;
start_index += strlen("START_OF_MESSAGE");
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;
}

12
message_helpers.h Normal file
View File

@@ -0,0 +1,12 @@
/* If the message contains a string of the form:
<Indicator>: <Value>
Then return 'value' */
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);