aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2023-09-26 06:52:14 +0000
committersotech117 <michael_foiani@brown.edu>2023-09-26 06:52:14 +0000
commit448b84240f7d2e5a33d35c892ad8fbabded7feba (patch)
tree66b192852d927f3c58c4a13f69776e9910c54723
parent87a678c2da2722ebb4f1dd540fc1ac422defb2af (diff)
parentf06e9e954d0ff0ee56c852ae717bc62e460eeed1 (diff)
Merge branch 'optimizations'
-rw-r--r--client.c2
-rw-r--r--server.c98
2 files changed, 52 insertions, 48 deletions
diff --git a/client.c b/client.c
index dbbc204..07e413f 100644
--- a/client.c
+++ b/client.c
@@ -313,7 +313,7 @@ void *command_line_routine(void* args) {
int inputInt = atoi(input);
if (input[0] != '0' && inputInt == 0) {
// if we're in here, it's ~likely~ not a number (ik it's not perfect, sorry :/)
- printf("unknown command: %si", input);
+ printf("unknown command: %s", input);
printf("snowcast_control> ");
fflush(stdout);
continue;
diff --git a/server.c b/server.c
index 48bd90b..22ab353 100644
--- a/server.c
+++ b/server.c
@@ -56,9 +56,12 @@ int read_file(int fd, char buffer[FILE_READ_SIZE], int station_num);
// ----------------------------------------------------------------------------------------------------------
typedef struct user
{
- int udpPort;
- int stationNum;
int tcpfd;
+ int stationNum;
+ int udpPort; // need this (& the following) for udp packet sending
+ int udpfd;
+ socklen_t addrlen;
+ struct sockaddr addr;
} user_t;
int max_active_users = 0; // maximum number of users that have been connected at once
int max_tcpfd = 0; // maximum tcpfd for users that has been seen
@@ -79,7 +82,6 @@ struct send_udp_packet_routine_args {
int start_threads = 0; // for synchronization, with the cond
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // for synchronization, with the following routine
void *send_udp_packet_routine(void* arg);
-void send_udp_packet_routine_cleanup(void *arg);
int setup_udp_connection(int udp_port, int *udp_sockfd, socklen_t *addrlen, struct sockaddr *addr);
int send_all_udp(int udp_sockfd, char *buf, int *len, struct sockaddr *addr, socklen_t addrlen);
@@ -120,7 +122,7 @@ void cleanup_readfds_and_sockets();
// 7) EXTRA CREDIT
// ---------------------------------------------------------------------------------------------------------
// ability for client to receive station list
-void *send_stationsinfo_routine(void *arg); // sends station info (index, name) to client
+void send_stationinfo_reply(int clientfd); // sends station info (index, name) to client
// ability for server to add/remove stations through command line
void add_station(char *station_name);
void send_newstation_reply(uint16_t station_num); // notifies users that a new station has been added
@@ -404,9 +406,15 @@ int read_file(int fd, char buffer[FILE_READ_SIZE], int station_num) {
// ----------------------------------------------------------------------------------------------------------
/*
given the newfd and udp_port of a newly connected user, initializes them to the data structure
+ 1) update the tcpfd_to_user map size if needed
+ 2) find the first available index in the users array
+ 3) make a new user, set the tcp info & udp info
+ 4) map the tcpfd to the user index
+ 5) send WELCOME reply
note: this function does its best to optimize memory (dynamic resize of tcpfd map & resusing space in array)
*/
void init_user(int newfd, int udp_port) {
+
pthread_mutex_lock(&mutex_users);
// FOLLOWING IS FOR MEMORY OPTIMIZATION
@@ -438,9 +446,20 @@ void init_user(int newfd, int udp_port) {
if (!more_users) { perror("realloc in init_user2"); exit(1); }
users = more_users;
}
-
+
+ // make new user, set tcp info
+ user_t new_user;
+ new_user.tcpfd = newfd;
+ new_user.stationNum = -1;
+ new_user.udpPort = udp_port;
+ // set the udp info
+ if(setup_udp_connection(udp_port, &new_user.udpfd, &new_user.addrlen, &new_user.addr) == -1) {
+ fprintf(stderr, "failure in init_user (setup_udp_connection)");
+ return; // error occured
+ }
+
// map TCP tcpfd to this user index
- users[running_index] = (user_t){udp_port, -1, newfd};
+ users[running_index] = new_user;
tcpfd_to_user[newfd] = running_index;
pthread_mutex_unlock(&mutex_users);
@@ -450,18 +469,22 @@ void init_user(int newfd, int udp_port) {
}
/*
given the tcpfd of a user, destroys them from the data structures
- 1) close the tcpfd
+ 1) close both tcpfd and udpfd of user
2) remove from master set
3) remove from data structures
note: destroying a user sets all fields of that user to -1. often, this is how it's known if a user exists
*/
void destroy_user(int tcpfd) {
- close(tcpfd); // bye!
+ close(tcpfd); // close tcpfd!
FD_CLR(tcpfd, &master); // remove from master set
+ if (tcpfd_to_user[tcpfd] == -1) return; // if -1, user has already been destroyed
+
+ close(users[tcpfd_to_user[tcpfd]].udpfd); // close udpfd
+
// remove user from data structures
pthread_mutex_lock(&mutex_users);
- users[tcpfd_to_user[tcpfd]] = (user_t) {-1, -1, -1};
+ users[tcpfd_to_user[tcpfd]] = (user_t) { -1, -1, -1, -1, 0, 0 }; // set all fields to -1 or 0
// map tcpfd to -1
tcpfd_to_user[tcpfd] = -1;
@@ -488,20 +511,6 @@ void *send_udp_packet_routine(void *arg) {
// setup variables
int did_work = 1;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
- // only these two following properties of addrinfo are needed to send udp packets
- struct sockaddr addr;
- socklen_t addrlen;
-
- // setup udp socket for this thread/user
- int udp_port = users[user_index].udpPort;
- int udp_sockfd;
- if (setup_udp_connection(udp_port, &udp_sockfd, &addrlen, &addr) == -1){
- fprintf(stderr, "failure in setup_udp_connection");
- return (NULL); // error occured
- }
-
- // setup cleanup for thread that closes the fd if closed
- pthread_cleanup_push(send_udp_packet_routine_cleanup, (void *)&udp_sockfd);
pthread_mutex_lock(&m);
// wait for threads
@@ -517,21 +526,12 @@ void *send_udp_packet_routine(void *arg) {
}
// send the data! (no error check since udp)
- send_all_udp(udp_sockfd, (char *) data_ptr, &buffer_size, &addr, addrlen);
-
- // cleanup
- close(udp_sockfd);
+ send_all_udp(users[user_index].udpfd, (char *) data_ptr, &buffer_size, &users[user_index].addr, users[user_index].addrlen);
pthread_mutex_unlock(&m);
- pthread_cleanup_pop(1);
return (NULL);
}
-void send_udp_packet_routine_cleanup(void *arg) // closes the udpfd if thread is cancelled
-{
- int sockfd = * (int *) arg;
- close(sockfd);
-}
/*
given the udp_port, makes a socket and returns it's file descriptor. (returns -1 on failure)
@@ -692,6 +692,15 @@ int handle_new_connection(int listener) {
return 0;
}
+ // determine if we've seen this udp_port before
+ for (int i = 0; i < max_active_users; i++) {
+ if (users[i].udpPort == udp_port) {
+ // if we have, we need to close the fd and move on
+ fprintf(stderr, "error connecting new user: udp port already in use\n");
+ return 0;
+ }
+ }
+
// add the user to the set
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the max
@@ -787,8 +796,7 @@ int handle_client_command(int clientfd) {
if (command_type == LISTSTATIONS) {
if (l) printf("received a LISTSTATIONS from socket %d\n", clientfd);
- pthread_t send_thread; // send STATIONINFO from a different thread
- pthread_create(&send_thread, NULL, send_stationsinfo_routine, (void *) &clientfd);
+ send_stationinfo_reply(clientfd);
return 1;
}
@@ -869,7 +877,7 @@ uint8_t handle_setstation_command(int tcpfd) {
station_number = ntohs(station_number);
// check if user has a udpPort to stream to
- if (users[tcpfd_to_user[tcpfd]].udpPort == -1) {
+ if (users[tcpfd_to_user[tcpfd]].udpfd == -1) {
if (l) printf("received a SETSTATION from socket %d before HELLO command. sending INVALID reply.\n", tcpfd);
// send back in invalid command and drop user
char * message = "must send Hello message first";
@@ -1047,8 +1055,8 @@ void write_int_to_fd(int fd, int n) {
free(num);
}
void print_user_data(int index) {
- printf("user: %d -> udpPort: %d, stationNum: %d, tcpfd: %d\n", index,
- users[index].udpPort, users[index].stationNum, users[index].tcpfd);
+ printf("user: %d -> tcpfd: %d, stationNum: %d, udpPort: %d, udpfd: %d, addrlen: %d\n",
+ index, users[index].tcpfd, users[index].stationNum, users[index].udpPort, users[index].udpfd, users[index].addrlen);
}
void print_station_data(int station) {
printf("station: %d -> filePath: %s, readfd: %d\n",
@@ -1075,10 +1083,8 @@ void cleanup_readfds_and_sockets() {
// ----------------------------------------------------------------------------------------------------------
// 7) EXTRA CREDIT IMPLEMENTATIONS (no broad function comments below, but it is all pretty self explanatory)
// ----------------------------------------------------------------------------------------------------------
-void *send_stationsinfo_routine(void * arg) {
- int fd = * (int *) arg;
-
- if (l) printf("sending STATIONSINFO reply to socket %d\n", fd);
+void send_stationinfo_reply(int clientfd) {
+ if (l) printf("sending STATIONSINFO reply to socket %d\n", clientfd);
uint32_t reply_size = 0;
for (int i = 0; i < num_stations; i++) {
@@ -1089,13 +1095,13 @@ void *send_stationsinfo_routine(void * arg) {
// send type
uint8_t reply_num = 6;
- if (send(fd, &reply_num, 1, 0) == -1)
+ if (send(clientfd, &reply_num, 1, 0) == -1)
perror("send in send stations info");
// send payload size
uint32_t reply_size_endian = htonl(reply_size);
int bytes = sizeof(uint32_t);
- if (send_all(fd, (char *) &reply_size_endian, &bytes) == -1)
+ if (send_all(clientfd, (char *) &reply_size_endian, &bytes) == -1)
perror("send_all in send stations info");
char send_buffer[reply_size];
@@ -1106,10 +1112,8 @@ void *send_stationsinfo_routine(void * arg) {
}
int bytes_to_send = reply_size; // don't want final \n
- if (send_all(fd, (char *) &send_buffer, &bytes_to_send) == -1)
+ if (send_all(clientfd, (char *) &send_buffer, &bytes_to_send) == -1)
perror("send_all buffer");
-
- return (NULL);
}
void add_station(char *file_path) {