diff options
author | sotech117 <michael_foiani@brown.edu> | 2023-09-26 06:52:14 +0000 |
---|---|---|
committer | sotech117 <michael_foiani@brown.edu> | 2023-09-26 06:52:14 +0000 |
commit | 448b84240f7d2e5a33d35c892ad8fbabded7feba (patch) | |
tree | 66b192852d927f3c58c4a13f69776e9910c54723 | |
parent | 87a678c2da2722ebb4f1dd540fc1ac422defb2af (diff) | |
parent | f06e9e954d0ff0ee56c852ae717bc62e460eeed1 (diff) |
Merge branch 'optimizations'
-rw-r--r-- | client.c | 2 | ||||
-rw-r--r-- | server.c | 98 |
2 files changed, 52 insertions, 48 deletions
@@ -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; @@ -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) { |