From cbfafaabbd846e625796f275b2e843376385cc36 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Fri, 15 Sep 2023 01:10:57 -0400 Subject: work on server handling multiple clients with a fd set --- Makefile | 2 +- broadcast.c | 67 +++++++++++++++++++ client.c | 33 ++++++++- protocol.h | 35 ++++++++-- server.c | 2 + snowcast-server.c | 0 snowcast_control | Bin 13864 -> 34461 bytes snowcast_server | Bin 14176 -> 34476 bytes snowcast_server.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 324 insertions(+), 10 deletions(-) create mode 100644 broadcast.c delete mode 100644 snowcast-server.c create mode 100644 snowcast_server.c diff --git a/Makefile b/Makefile index 23d8e32..be4e159 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ default: all all: server client server: server.c - $(CC) $(CFLAGS) -o snowcast_server server.c + $(CC) $(CFLAGS) -o snowcast_server snowcast_server.c client: client.c $(CC) $(CFLAGS) -o snowcast_control client.c \ No newline at end of file diff --git a/broadcast.c b/broadcast.c new file mode 100644 index 0000000..b10e633 --- /dev/null +++ b/broadcast.c @@ -0,0 +1,67 @@ +/* +** broadcaster.c -- a datagram "client" like talker.c, except +** this one can broadcast +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SERVERPORT 4950 // the port users will be connecting to + +int main(int argc, char *argv[]) +{ + int sockfd; + struct sockaddr_in their_addr; // connector's address information + struct hostent *he; + int numbytes; + int broadcast = 1; + //char broadcast = '1'; // if that doesn't work, try this + + if (argc != 3) { + fprintf(stderr,"usage: broadcaster hostname message\n"); + exit(1); + } + + if ((he=gethostbyname(argv[1])) == NULL) { // get the host info + perror("gethostbyname"); + exit(1); + } + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket"); + exit(1); + } + + // this call is what allows broadcast packets to be sent: + if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, + sizeof broadcast) == -1) { + perror("setsockopt (SO_BROADCAST)"); + exit(1); + } + + their_addr.sin_family = AF_INET; // host byte order + their_addr.sin_port = htons(SERVERPORT); // short, network byte order + their_addr.sin_addr = *((struct in_addr *)he->h_addr); + memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero); + + if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0, + (struct sockaddr *)&their_addr, sizeof their_addr)) == -1) { + perror("sendto"); + exit(1); + } + + printf("sent %d bytes to %s\n", numbytes, + inet_ntoa(their_addr.sin_addr)); + + close(sockfd); + + return 0; +} \ No newline at end of file diff --git a/client.c b/client.c index 6458227..49d2cdf 100644 --- a/client.c +++ b/client.c @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -18,6 +19,10 @@ #define MAXDATASIZE 100 // max number of bytes we can get at once +#define MAX_READ_SIZE 1024 +#define LINE_MAX 1024 + + // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { @@ -83,7 +88,7 @@ int main(int argc, char *argv[]) struct Welcome msg; // recv the message, check for errors too - if ((recvbytes = recv(sockfd, (char*)&msg, sizeof(struct snowcast_message), 0)) == -1) { + if ((recvbytes = recv(sockfd, (char*)&msg, sizeof(struct Welcome), 0)) == -1) { perror("recv"); exit(1); } @@ -95,12 +100,34 @@ int main(int argc, char *argv[]) // convert updPort to an int int udpPortInt = atoi(udpPort); hello.udpPort = htons(udpPortInt); - if ((numbytessent = send(sockfd, &hello, sizeof(struct Hello), 0)) == -1) { perror("send"); exit(1); } - close(sockfd); + + char input[LINE_MAX]; + printf("Enter a number to change to it's station. Click q to end stream.\n"); + while (1==1) { + char *line = fgets(input, LINE_MAX, stdin); + + if (line == NULL) { + continue; + } else if (strncmp("q\n", input, LINE_MAX) == 0) { + printf("Exiting.\n"); + break; + } else { + // convert input to an int + int inputInt = (uint16_t)atoi(input); + + struct SetStation setStation; + setStation.commandType = 1; + setStation.stationNumber = htons(inputInt); + if ((numbytessent = send(sockfd, &setStation, sizeof(struct SetStation), 0)) == -1) { + perror("send"); + exit(1); + } + } + } return 0; } \ No newline at end of file diff --git a/protocol.h b/protocol.h index 0cdc998..b038901 100644 --- a/protocol.h +++ b/protocol.h @@ -1,16 +1,39 @@ #include // Provides uint8_t, int8_t, etc. -struct snowcast_message { - uint8_t type; - uint16_t number; +// client to server messages (commands) + +struct Command { + uint8_t commandType; + u_int16_t number; +} __attribute__((packed)); + +struct Hello { + uint8_t commandType; + uint16_t udpPort; +} __attribute__((packed)); +struct SetStation { + uint8_t commandType; + uint16_t stationNumber; } __attribute__((packed)); +// server to client message (replies) struct Welcome { uint8_t replyType; uint16_t numStations; } __attribute__((packed)); -struct Hello { - uint8_t commandType; - uint16_t udpPort; +struct Reply { + uint8_t replyType; + uint8_t stringSize; + char *string; +} __attribute__((packed)); +struct Announce { + uint8_t replyType; + uint8_t songnameSize; + char *songname; } __attribute__((packed)); +struct InvalidCommand { + uint8_t replyType; + uint8_t replyStringSize; + char *replyString; +} __attribute__((packed)); \ No newline at end of file diff --git a/server.c b/server.c index 475535c..be9f603 100644 --- a/server.c +++ b/server.c @@ -118,6 +118,8 @@ int main(int argc, char *argv[]) printf("server: waiting for connections...\n"); + + while(1) { // main accept() loop sin_size = sizeof their_addr; new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); diff --git a/snowcast-server.c b/snowcast-server.c deleted file mode 100644 index e69de29..0000000 diff --git a/snowcast_control b/snowcast_control index 5e208f3..d6aaff0 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_server b/snowcast_server index 75713b7..1f61e9d 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.c b/snowcast_server.c new file mode 100644 index 0000000..f09bfcc --- /dev/null +++ b/snowcast_server.c @@ -0,0 +1,195 @@ +/* +** server.c -- a stream socket server demo +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "protocol.h" + +// get sockaddr, IPv4 or IPv6: +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +int main(int argc, char *argv[]) +{ + fd_set master; // master file descriptor list + fd_set read_fds; // temp file descriptor list for select() + int fdmax; // maximum file descriptor number + + int listener; // listening socket descriptor + int newfd; // newly accept()ed socket descriptor + struct sockaddr_storage remoteaddr; // client address + socklen_t addrlen; + + char buf[256]; // buffer for client data + int nbytes; + + char remoteIP[INET6_ADDRSTRLEN]; + + int yes=1; // for setsockopt() SO_REUSEADDR, below + int i, j, rv; + + struct addrinfo hints, *ai, *p; + + // check and assign arguments + if (argc < 3) { + fprintf(stderr,"usage: [file 1] [file 2] ... \n"); + exit(1); + } + + const char* port = argv[1]; + + FD_ZERO(&master); // clear the master and temp sets + FD_ZERO(&read_fds); + + // get us a socket and bind it + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) { + fprintf(stderr, "selectserver: %s\n", gai_strerror(rv)); + exit(1); + } + + for(p = ai; p != NULL; p = p->ai_next) { + listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (listener < 0) { + continue; + } + + // lose the pesky "address already in use" error message + setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + + if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) { + close(listener); + continue; + } + + break; + } + + // if we got here, it means we didn't get bound + if (p == NULL) { + fprintf(stderr, "snowcast_server: failed to bind\n"); + exit(2); + } + + freeaddrinfo(ai); // all done with this + + // listen + if (listen(listener, 10) == -1) { + perror("listen"); + exit(3); + } + + // add the listener to the master set + FD_SET(listener, &master); + + // keep track of the biggest file descriptor + fdmax = listener; // so far, it's this one + + // main loop + while(1==1) { + read_fds = master; // copy it + if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { + perror("select"); + exit(4); + } + + // run through the existing connections looking for data to read + for(i = 0; i <= fdmax; i++) { + if (FD_ISSET(i, &read_fds)) { // we got one!! + if (i == listener) { + // handle new connections + addrlen = sizeof remoteaddr; + newfd = accept(listener, + (struct sockaddr *)&remoteaddr, + &addrlen); + + if (newfd == -1) { + perror("accept"); + } else { + FD_SET(newfd, &master); // add to master set + if (newfd > fdmax) { // keep track of the max + fdmax = newfd; + } + printf("selectserver: new connection from %s on " + "socket %d\n", + inet_ntop(remoteaddr.ss_family, + get_in_addr((struct sockaddr*)&remoteaddr), + remoteIP, INET6_ADDRSTRLEN), + newfd); + // send the welcome message to client + struct Welcome welcome; + welcome.replyType = 2; + welcome.numStations = htons(argc - 2); + if ((send(newfd, &welcome, sizeof(struct Welcome), 0)) == -1) + perror("send"); + } + } else { + // handle data from a client + struct Command command; + if ((nbytes = recv(i, (char*)&command, sizeof(struct Command), 0)) <= 0) { + // got error or connection closed by client + if (nbytes == 0) { + // connection closed + printf("selectserver: socket %d hung up\n", i); + } else { + perror("recv"); + } + close(i); // bye! + FD_CLR(i, &master); // remove from master set + } else { + // we got some data from a client + if (command.commandType == 1) { + // update the station for the user + printf("TODO: set station to %d\n", ntohs(command.number)); + } + else { + // send back ianinvalid command + struct InvalidCommand invalid; + invalid.replyType = 4; + invalid.replyStringSize = 21; + // make a string with the command.commmandType type in it + invalid.replyString = "Invalid command type"; + if ((send(i, &invalid, sizeof(struct InvalidCommand), 0)) == -1) + perror("send"); + } + // for(j = 0; j <= fdmax; j++) { + // // send to everyone! + // if (FD_ISSET(j, &master)) { + // // except the listener and ourselves + // if (j != listener && j != i) { + // if (send(j, buf, nbytes, 0) == -1) { + // perror("send"); + // } + // } + // } + // } + } + } // END handle data from client + } // END got new incoming connection + } // END looping through file descriptors + } // END for(;;)--and you thought it would never end! + + return 0; +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 97b4913de92b150ca18690df1b41e62c856aab05 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Fri, 15 Sep 2023 01:20:36 -0400 Subject: cleanup the hello and welcome interactoin --- client.c | 4 +++- snowcast_server | Bin 34476 -> 34476 bytes snowcast_server.c | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/client.c b/client.c index 49d2cdf..cb524cf 100644 --- a/client.c +++ b/client.c @@ -113,12 +113,14 @@ int main(int argc, char *argv[]) if (line == NULL) { continue; } else if (strncmp("q\n", input, LINE_MAX) == 0) { + // end code if type in q printf("Exiting.\n"); break; } else { // convert input to an int int inputInt = (uint16_t)atoi(input); - + + // send the command to change the station struct SetStation setStation; setStation.commandType = 1; setStation.stationNumber = htons(inputInt); diff --git a/snowcast_server b/snowcast_server index 1f61e9d..395e06e 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.c b/snowcast_server.c index f09bfcc..e8f9525 100644 --- a/snowcast_server.c +++ b/snowcast_server.c @@ -138,6 +138,7 @@ int main(int argc, char *argv[]) get_in_addr((struct sockaddr*)&remoteaddr), remoteIP, INET6_ADDRSTRLEN), newfd); + // send the welcome message to client struct Welcome welcome; welcome.replyType = 2; @@ -160,8 +161,12 @@ int main(int argc, char *argv[]) FD_CLR(i, &master); // remove from master set } else { // we got some data from a client + if (command.commandType == 0) { + // hello message with udpPort + printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); + } if (command.commandType == 1) { - // update the station for the user + // setStation command for the user printf("TODO: set station to %d\n", ntohs(command.number)); } else { -- cgit v1.2.3-70-g09d2 From 35f464738c990752ffdb65ef3adcb2812925c07d Mon Sep 17 00:00:00 2001 From: sotech117 Date: Fri, 15 Sep 2023 01:22:05 -0400 Subject: small cleanup --- snowcast_server.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/snowcast_server.c b/snowcast_server.c index e8f9525..b1d7d8a 100644 --- a/snowcast_server.c +++ b/snowcast_server.c @@ -170,7 +170,7 @@ int main(int argc, char *argv[]) printf("TODO: set station to %d\n", ntohs(command.number)); } else { - // send back ianinvalid command + // send back in invalid command struct InvalidCommand invalid; invalid.replyType = 4; invalid.replyStringSize = 21; @@ -178,18 +178,11 @@ int main(int argc, char *argv[]) invalid.replyString = "Invalid command type"; if ((send(i, &invalid, sizeof(struct InvalidCommand), 0)) == -1) perror("send"); + + // drop connection upon invalid command + close(i); + FD_CLR(i, &master); } - // for(j = 0; j <= fdmax; j++) { - // // send to everyone! - // if (FD_ISSET(j, &master)) { - // // except the listener and ourselves - // if (j != listener && j != i) { - // if (send(j, buf, nbytes, 0) == -1) { - // perror("send"); - // } - // } - // } - // } } } // END handle data from client } // END got new incoming connection -- cgit v1.2.3-70-g09d2 From 9e0994d5a997a5b8c298992f05c94ba1b22a692c Mon Sep 17 00:00:00 2001 From: sotech117 Date: Fri, 15 Sep 2023 01:56:35 -0400 Subject: decents stopping point. developed some udp code --- snowcast_server | Bin 34476 -> 34476 bytes snowcast_server.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/snowcast_server b/snowcast_server index 395e06e..a4dfc51 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.c b/snowcast_server.c index b1d7d8a..6043157 100644 --- a/snowcast_server.c +++ b/snowcast_server.c @@ -60,13 +60,13 @@ int main(int argc, char *argv[]) FD_ZERO(&master); // clear the master and temp sets FD_ZERO(&read_fds); - // get us a socket and bind it + // LISTENER: get us a socket and bind it memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) { - fprintf(stderr, "selectserver: %s\n", gai_strerror(rv)); + fprintf(stderr, "snowcast_server: %s\n", gai_strerror(rv)); exit(1); } @@ -133,7 +133,7 @@ int main(int argc, char *argv[]) fdmax = newfd; } printf("selectserver: new connection from %s on " - "socket %d\n", + "socket %d\n.", inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), remoteIP, INET6_ADDRSTRLEN), @@ -164,6 +164,44 @@ int main(int argc, char *argv[]) if (command.commandType == 0) { // hello message with udpPort printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); + + // TALKER: get us a udp socket and bind it + struct addrinfo hintsUdp, *servinfoUdp, *pUdp; + int rvUdp, sockfdUdp, numbytesUdp; + memset(&hintsUdp, 0, sizeof hintsUdp); + hintsUdp.ai_family = AF_INET; // IPv4 + hintsUdp.ai_socktype = SOCK_DGRAM; // UDP + if ((rvUdp = getaddrinfo(argv[1], command.number, &hints, &servinfoUdp)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rvUdp)); + return 1; + } + + // loop through all the results and make a socket + for(p = servinfoUdp; p != NULL; p = p->ai_next) { + if ((sockfdUdp = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("talker: socket"); + continue; + } + break; + } + + if (p == NULL) { + fprintf(stderr, "talker: failed to create socket\n"); + return 2; + } + + + if ((numbytesUdp = sendto(sockfdUdp, "test", strlen("test"), 0, + p->ai_addr, p->ai_addrlen)) == -1) { + perror("talker: sendto"); + exit(1); + } + + freeaddrinfo(servinfoUdp); + + printf("talker: sent %d bytes to %d\n", numbytesUdp, sockfdUdp); + // close(sockfdUdp); } if (command.commandType == 1) { // setStation command for the user @@ -187,6 +225,9 @@ int main(int argc, char *argv[]) } // END handle data from client } // END got new incoming connection } // END looping through file descriptors + + // broadcast the new files over the udp socket list for each use + } // END for(;;)--and you thought it would never end! return 0; -- cgit v1.2.3-70-g09d2 From 6ed8bef65e54efdb98841ef9b6eb3ea3c9be82d5 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 18 Sep 2023 02:34:12 -0400 Subject: big progress on streaming in sync and controlling multiple users --- Makefile | 5 +- client.c | 5 +- htable.c | 78 ++++++++ htable.h | 45 +++++ list.h | 137 +++++++++++++ protocol.h | 2 +- snowcast_control | Bin 34461 -> 34461 bytes snowcast_server | Bin 34476 -> 34636 bytes snowcast_server_concurrent.c | 457 +++++++++++++++++++++++++++++++++++++++++++ test | Bin 0 -> 52849 bytes 10 files changed, 725 insertions(+), 4 deletions(-) create mode 100644 htable.c create mode 100644 htable.h create mode 100644 list.h create mode 100644 snowcast_server_concurrent.c create mode 100755 test diff --git a/Makefile b/Makefile index be4e159..1603f38 100644 --- a/Makefile +++ b/Makefile @@ -10,4 +10,7 @@ server: server.c $(CC) $(CFLAGS) -o snowcast_server snowcast_server.c client: client.c - $(CC) $(CFLAGS) -o snowcast_control client.c \ No newline at end of file + $(CC) $(CFLAGS) -o snowcast_control client.c + +new: + $(CC) $(CFLAGS) -o test snowcast_server_concurrent.c \ No newline at end of file diff --git a/client.c b/client.c index cb524cf..1acd3ae 100644 --- a/client.c +++ b/client.c @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) char input[LINE_MAX]; printf("Enter a number to change to it's station. Click q to end stream.\n"); - while (1==1) { + while (1) { char *line = fgets(input, LINE_MAX, stdin); if (line == NULL) { @@ -118,7 +118,8 @@ int main(int argc, char *argv[]) break; } else { // convert input to an int - int inputInt = (uint16_t)atoi(input); + int inputInt = atoi(input); + printf("Changing to station %d.\n", inputInt); // send the command to change the station struct SetStation setStation; diff --git a/htable.c b/htable.c new file mode 100644 index 0000000..a39c3c6 --- /dev/null +++ b/htable.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include + +#include "htable.h" + +static htable_node_t *__htable_lookup( htable_t *ht, unsigned int id ); + +void htable_init( htable_t *ht, unsigned int cap ) { + unsigned int i; + + ht->ht_hash = (list_t*) malloc( sizeof( list_t ) * cap ); + ht->ht_cap = cap; + ht->ht_size = 0; + + for( i = 0; i < cap; i++ ) + list_init( &ht->ht_hash[ i ] ); +} + +void htable_destroy( htable_t *ht ) { + unsigned int i; + htable_node_t *hn; + + for( i = 0; i < ht->ht_cap; i++ ) { + list_iterate_begin( &ht->ht_hash[ i ], hn, htable_node_t, hn_link ) { + free( hn ); + } list_iterate_end(); + } + + free( ht->ht_hash ); +} + +void *htable_get( htable_t *ht, unsigned int id ) { + htable_node_t *hn; + + if( ( hn = __htable_lookup( ht, id ) ) ) return hn->hn_data; + else return NULL; +} + +void *htable_put( htable_t *ht, unsigned int id, void *data ) { + htable_node_t *hn; + void *old = NULL; + + if( !( hn = __htable_lookup( ht, id ) ) ) { + hn = (htable_node_t*) malloc( sizeof( htable_node_t ) ); + hn->hn_id = id; + list_insert_head( &ht->ht_hash[ id % ht->ht_cap ], &hn->hn_link ); + ht->ht_size++; + } else old = hn->hn_data; + + hn->hn_data = data; + + return old; +} + +void *htable_remove( htable_t *ht, unsigned int id ) { + htable_node_t *hn; + + if( ( hn = __htable_lookup( ht, id ) ) ) { + void *data = hn->hn_data; + list_remove( &hn->hn_link ); + free( hn ); + ht->ht_size--; + return data; + } else return NULL; +} + +htable_node_t *__htable_lookup( htable_t *ht, unsigned int id ) { + htable_node_t *hn; + + list_iterate_begin( &ht->ht_hash[ id % ht->ht_cap ], hn, htable_node_t, hn_link ) { + if( hn->hn_id == id ) return hn; + } list_iterate_end(); + + return NULL; +} \ No newline at end of file diff --git a/htable.h b/htable.h new file mode 100644 index 0000000..65eac58 --- /dev/null +++ b/htable.h @@ -0,0 +1,45 @@ +#ifndef __HASHTABLE_H__ +#define __HASHTABLE_H__ + +#include + +#include "list.h" + +/* FIXME make this a doubly-hashed, dynamically groweable hashtable */ + +typedef struct htable { + list_t *ht_hash; /* table entries */ + unsigned int ht_size; /* table size */ + unsigned int ht_cap; /* table capacity */ +} htable_t; + +typedef struct htable_node { + list_t hn_link; /* link */ + unsigned int hn_id; /* hash id */ + void *hn_data; /* data */ +} htable_node_t; + +void htable_init( htable_t *ht, unsigned int cap ); +void htable_destroy( htable_t *ht ); +void *htable_get( htable_t *ht, unsigned int id ); +void *htable_put( htable_t *ht, unsigned int id, void *data ); +void *htable_remove( htable_t *ht, unsigned int id ); + +#define htable_iterate_begin( ht, key, var, type ) \ +do { \ + unsigned int ___i; \ + htable_t *__ht = (ht); \ + htable_node_t *__hnode; \ + for(___i = 0;___i < __ht->ht_cap;___i++ ) { \ + list_iterate_begin( &__ht->ht_hash[___i ], __hnode, htable_node_t, hn_link ) { \ + (var) = (type*) __hnode->hn_data; \ + (key) = __hnode->hn_id; \ + do + +#define htable_iterate_end() \ + while( 0 ); \ + } list_iterate_end(); \ + } \ +} while( 0 ) + +#endif /* __HASHTABLE_H__ */ \ No newline at end of file diff --git a/list.h b/list.h new file mode 100644 index 0000000..03fcdc5 --- /dev/null +++ b/list.h @@ -0,0 +1,137 @@ +#ifndef __LIST_H__ +#define __LIST_H__ + +#include + +/* +** Generic circular doubly linked list implementation. +** +** list_t is the head of the list. +** list_link_t should be included in structures which want to be +** linked on a list_t. +** +** All of the list functions take pointers to list_t and list_link_t +** types, unless otherwise specified. +** +** list_init(list) initializes a list_t to an empty list. +** +** list_empty(list) returns 1 iff the list is empty. +** +** Insertion functions. +** list_insert_head(list, link) inserts at the front of the list. +** list_insert_tail(list, link) inserts at the end of the list. +** list_insert_before(olink, nlink) inserts nlink before olink in list. +** +** Removal functions. +** Head is list->l_next. Tail is list->l_prev. +** The following functions should only be called on non-empty lists. +** list_remove(link) removes a specific element from the list. +** list_remove_head(list) removes the first element. +** list_remove_tail(list) removes the last element. +** +** Item accessors. +** list_item(link, type, member) given a list_link_t* and the name +** of the type of structure which contains the list_link_t and +** the name of the member corresponding to the list_link_t, +** returns a pointer (of type "type*") to the item. +** +** To iterate over a list, +** +** list_link_t *link; +** for (link = list->l_next; +** link != list; link = link->l_next) +** ... +** +** Or, use the macros, which will work even if you list_remove() the +** current link: +** +** type iterator; +** list_iterate_begin(list, iterator, type, member) { +** ... use iterator ... +** } list_iterate_end; +*/ + +typedef struct llist { + struct llist *l_next; + struct llist *l_prev; +} list_t, list_link_t; + +#define list_init(list) \ + (list)->l_next = (list)->l_prev = (list); + +#define list_link_init(link) \ + (link)->l_next = (link)->l_prev = NULL; + +#define list_empty(list) \ + ((list)->l_next == (list)) + +#define list_insert_before(old, new) \ + do { \ + list_link_t *prev = (new); \ + list_link_t *next = (old); \ + prev->l_next = next; \ + prev->l_prev = next->l_prev; \ + next->l_prev->l_next = prev; \ + next->l_prev = prev; \ + } while(0) + +#define list_insert_head(list, link) \ + list_insert_before((list)->l_next, link) + +#define list_insert_tail(list, link) \ + list_insert_before(list, link) + +#define list_remove(link) \ + do { \ + list_link_t *ll = (link); \ + list_link_t *prev = ll->l_prev; \ + list_link_t *next = ll->l_next; \ + prev->l_next = next; \ + next->l_prev = prev; \ + ll->l_next = ll->l_prev = 0; \ + } while(0) + +#define list_remove_head(list) \ + list_remove((list)->l_next) + +#define list_remove_tail(list) \ + list_remove((list)->l_prev) + +#define list_item(link, type, member) \ + (type*)((char*)(link) - offsetof(type, member)) + +#define list_head(list, type, member) \ + list_item((list)->l_next, type, member) + +#define list_tail(list, type, member) \ + list_item((list)->l_prev, type, member) + +#define list_iterate_begin(list, var, type, member) \ + do { \ + list_link_t *__link; \ + list_link_t *__next; \ + for (__link = (list)->l_next; \ + __link != (list); \ + __link = __next) { \ + var = list_item(__link, type, member); \ + __next = __link->l_next; + +#define list_iterate_end() \ + } \ + } while(0) + +#define list_iterate_reverse_begin(list, var, type, member) \ + do { \ + list_link_t *__link; \ + list_link_t *__prev; \ + for (__link = (list)->l_prev; \ + __link != (list); \ + __link = __prev) { \ + var = list_item(__link, type, member); \ + __prev = __link->l_prev; + +#define list_iterate_reverse_end() \ + } \ + } while(0) + +#endif /* __LIST_H__ */ \ No newline at end of file diff --git a/protocol.h b/protocol.h index b038901..39f26e6 100644 --- a/protocol.h +++ b/protocol.h @@ -4,7 +4,7 @@ struct Command { uint8_t commandType; - u_int16_t number; + uint16_t number; } __attribute__((packed)); struct Hello { diff --git a/snowcast_control b/snowcast_control index d6aaff0..1b879ff 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_server b/snowcast_server index a4dfc51..bf1801b 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c new file mode 100644 index 0000000..7f70294 --- /dev/null +++ b/snowcast_server_concurrent.c @@ -0,0 +1,457 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "protocol.h" + +typedef struct station { + char* filePath; + int currentChunk; +} station_t; + +typedef struct user { + int udpPort; + int stationNum; + int sockfd; +} user_t; + +#define NUM_STATIONS 2 +#define LINE_MAX 1024 +#define MAX_USERS 1000 + +/* For safe condition variable usage, must use a boolean predicate and */ +/* a mutex with the condition. */ +int count = 0; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + +int start_threads = 0; + +int max_active_users = 0; + +pthread_mutex_t mutex_user_data = PTHREAD_MUTEX_INITIALIZER; +// array from fd to users +user_t *user_data; +// array from fd to user's stream thread +pthread_t *user_stream_threads; +station_t station_data[NUM_STATIONS]; +int sockfd_to_user[MAX_USERS + 4]; + +char* port = "4950"; + +void *send_udp_packet_routine(void* arg); +void *select_thread(void* arg); +void *synchronization_thread(void* arg); + +void *get_in_addr(struct sockaddr *sa); + +void *init_user(int sockfd); +void *update_user_udpPort(int sockfd, int udpPort); +void *update_user_station(int sockfd, int stationNum); +void *print_user_data(int sockfd); +void *destroy_user(int sockfd); + + +// void *load_file(void* arg); + +main(int argc, char *argv[]) +{ + // temporary + station_data[0] = (station_t) {"mp3/Beethoven-SymphonyNo5.mp3", 0}; + station_data[1] = (station_t) {"mp3/DukeEllington-Caravan.mp3", 0}; + + // threads to control reading files at chunks while the other threads sleep + + user_data = malloc(sizeof(user_t) * max_active_users); + if (!user_data) { perror("malloc"); return 1; } + user_stream_threads = malloc(sizeof(pthread_t) * max_active_users); + if (!user_stream_threads) + { + perror("malloc"); return 1; + } + + // thread that manages file descriptors + pthread_t s_thread, sync_thread; + pthread_create(&s_thread, NULL, select_thread, NULL); + + // starts the threads after created + // sleep(1); + // startThreads = 0; + // pthread_cond_broadcast(&cond); + + // command line interface + char input[LINE_MAX]; + while (1) { + char *line = fgets(input, LINE_MAX, stdin); + + if (line == NULL) { + continue; + } else if (strncmp("q\n", input, LINE_MAX) == 0) { + // end code if type in q + printf("Exiting.\n"); + break; + } else if (strncmp("p\n", input, LINE_MAX) == 0) { + // print all user data + for (int i = 0; i < max_active_users; i++) { + print_user_data(i); + } + } else if (strncmp("s\n", input, LINE_MAX) == 0) { + // start the streaming threads + pthread_create(&sync_thread, NULL, synchronization_thread, NULL); + } + } + + return 0; +} + +/* Make the manager routine */ +void *send_udp_packet_routine(void *arg) { + // pthread_mutex_lock(&mutex); + // while(startThreads) { + // pthread_cond_wait(&cond, &mutex); + // } + // pthread_mutex_unlock(&mutex); + int did_send_data = 0; + int did_load_data = 0; + + int * i = (int *) arg; + while (1) + { + pthread_mutex_lock(&mutex); + if (!start_threads && did_send_data && did_load_data) { + did_load_data = 0; + did_send_data = 0; + } + while(!start_threads) { + pthread_cond_wait(&cond, &mutex); + } + pthread_mutex_unlock(&mutex); + if(!did_send_data && start_threads) { + printf("send data: thread %d \n", i); + did_send_data = 1; + } + if(!did_load_data && start_threads) { + printf("load data: thread %d \n", i); + did_load_data = 1; + } + } + return NULL; +} + +// /* Make the manager routine */ +// void *load_file(void *arg) { +// // read first data off the files +// pthread_mutex_lock(&mutex); +// while(startThreads) { +// pthread_cond_wait(&cond, &mutex); +// } +// pthread_mutex_unlock(&mutex); + +// int * i = (int *) arg; +// while (1) +// { +// pthread_mutex_lock(&mutex); +// while(startThreads) { +// pthread_cond_wait(&cond, &mutex); +// } +// pthread_mutex_unlock(&mutex); +// /* Do some work. */ +// printf("Thread %d \n", i); +// // send data to port +// // read data coming in off the file +// // sleep for a secong +// sleep(1); +// } +// return NULL; +// } + +void *synchronization_thread(void *arg) { + int c = 0; + while (1) + { + start_threads = 1; + printf("\nbroadcast %d\n", c++); + pthread_cond_broadcast(&cond); + usleep(10000); + start_threads = 0; + sleep(1); + } +} + +void *select_thread(void *arg) { + fd_set master; // master file descriptor list + fd_set read_fds; // temp file descriptor list for select() + int fdmax; // maximum file descriptor number + + int listener; // listening socket descriptor + int newfd; // newly accept()ed socket descriptor + struct sockaddr_storage remoteaddr; // client address + socklen_t addrlen; + + char buf[256]; // buffer for client data + int nbytes; + + + char remoteIP[INET6_ADDRSTRLEN]; + + int yes=1; // for setsockopt() SO_REUSEADDR, below + int i, j, rv; + + struct addrinfo hints, *ai, *p; + + // const char* port = argv[1]; + + FD_ZERO(&master); // clear the master and temp sets + FD_ZERO(&read_fds); + + // LISTENER: get us a socket and bind it + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) { + fprintf(stderr, "snowcast_server: %s\n", gai_strerror(rv)); + exit(1); + } + + for(p = ai; p != NULL; p = p->ai_next) { + listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (listener < 0) { + continue; + } + + // lose the pesky "address already in use" error message + setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + + if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) { + close(listener); + continue; + } + + break; + } + + // if we got here, it means we didn't get bound + if (p == NULL) { + fprintf(stderr, "snowcast_server: failed to bind\n"); + exit(2); + } + + freeaddrinfo(ai); // all done with this + + // listen + if (listen(listener, 10) == -1) { + perror("listen"); + exit(3); + } + + // add the listener to the master set + FD_SET(listener, &master); + + // keep track of the biggest file descriptor + fdmax = listener; // so far, it's this one + + while(1==1) { + read_fds = master; // copy it + if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { + perror("select"); + exit(4); + } + + // run through the existing connections looking for data to read + for(i = 0; i <= fdmax; i++) { + if (FD_ISSET(i, &read_fds)) { // we got one!! + if (i == listener) { + // handle new connections + addrlen = sizeof remoteaddr; + newfd = accept(listener, + (struct sockaddr *)&remoteaddr, + &addrlen); + + if (newfd == -1) { + perror("accept"); + } else { + FD_SET(newfd, &master); // add to master set + if (newfd > fdmax) { // keep track of the max + fdmax = newfd; + } + printf("selectserver: new connection from %s on " + "socket %d\n.", + inet_ntop(remoteaddr.ss_family, + get_in_addr((struct sockaddr*)&remoteaddr), + remoteIP, INET6_ADDRSTRLEN), + newfd); + + // init user with this newfd + init_user(newfd); + + // send the welcome message to client + struct Welcome welcome; + welcome.replyType = 2; + welcome.numStations = htons(NUM_STATIONS); + if ((send(newfd, &welcome, sizeof(struct Welcome), 0)) == -1) + perror("send"); + } + } else { + // handle data from a client + struct Command command; + if ((nbytes = recv(i, (char*)&command, sizeof(struct Command), 0)) <= 0) { + // got error or connection closed by client + if (nbytes == 0) { + // connection closed + printf("selectserver: socket %d hung up\n", i); + } else { + perror("recv"); + } + close(i); // bye! + FD_CLR(i, &master); // remove from master set + // remove user from data structures + destroy_user(i); + } else { + // we got some data from a client + if (command.commandType == 0) { + // hello message with udpPort + printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); + // update udp port of user + update_user_udpPort(i, ntohs(command.number)); + + + + // // TALKER: get us a udp socket and bind it + // struct addrinfo hintsUdp, *servinfoUdp, *pUdp; + // int rvUdp, sockfdUdp, numbytesUdp; + // memset(&hintsUdp, 0, sizeof hintsUdp); + // hintsUdp.ai_family = AF_INET; // IPv4 + // hintsUdp.ai_socktype = SOCK_DGRAM; // UDP + // if ((rvUdp = getaddrinfo(argv[1], command.number, &hints, &servinfoUdp)) != 0) { + // fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rvUdp)); + // return 1; + // } + + // // loop through all the results and make a socket + // for(p = servinfoUdp; p != NULL; p = p->ai_next) { + // if ((sockfdUdp = socket(p->ai_family, p->ai_socktype, + // p->ai_protocol)) == -1) { + // perror("talker: socket"); + // continue; + // } + // break; + // } + + // if (p == NULL) { + // fprintf(stderr, "talker: failed to create socket\n"); + // return 2; + // } + + + // if ((numbytesUdp = sendto(sockfdUdp, "test", strlen("test"), 0, + // p->ai_addr, p->ai_addrlen)) == -1) { + // perror("talker: sendto"); + // exit(1); + // } + + // freeaddrinfo(servinfoUdp); + + // printf("talker: sent %d bytes to %d\n", numbytesUdp, sockfdUdp); + // close(sockfdUdp); + } + else if (command.commandType == 1) { + // setStation command for the user + printf("TODO: set station to %d\n", ntohs(command.number)); + // update station of user + update_user_station(i, ntohs(command.number)); + } + else { + // send back in invalid command + struct InvalidCommand invalid; + invalid.replyType = 4; + invalid.replyStringSize = 21; + // make a string with the command.commmandType type in it + invalid.replyString = "Invalid command type"; + if ((send(i, &invalid, sizeof(struct InvalidCommand), 0)) == -1) + perror("send"); + + // drop connection upon invalid command + close(i); + FD_CLR(i, &master); + } + } + } // END handle data from client + } // END got new incoming connection + } // END looping through file descriptors + + // broadcast the new files over the udp socket list for each use + + } // END for(;;)--and you thought it would never end! +} + +void *init_user(int sockfd) { + // add the user to the list of user data + pthread_mutex_lock(&mutex_user_data); + + // this is to save memory space. + // in general, the displacement of 4 is where a user "used to be" + int user_index = max_active_users++; + if(user_data[sockfd-4].sockfd == -1) { + printf("reusing memory\n"); + user_index = sockfd - 4; + } else { + printf("making new memory\n"); + // have to make more memory + user_t *more_users = realloc(user_data, sizeof(user_t) * max_active_users); + if (!more_users) { perror("realloc"); exit(1); } + user_data = more_users; + pthread_t *more_stream_threads = realloc(user_stream_threads, sizeof(pthread_t) * max_active_users); + if (!more_stream_threads) { perror("realloc"); exit(1); } + user_stream_threads = more_stream_threads; + } + // map sockfd to this user index & create its stream thread + user_data[user_index] = (user_t) {-1, -1, sockfd}; + sockfd_to_user[sockfd] = user_index; + pthread_create(&user_stream_threads[user_index], NULL, send_udp_packet_routine, (void *)sockfd); + // free(user_stream_threads); + pthread_mutex_unlock(&mutex_user_data); +} +void *update_user_udpPort(int sockfd, int udpPort) { + pthread_mutex_lock(&mutex_user_data); + user_data[sockfd_to_user[sockfd]].udpPort = udpPort; + pthread_mutex_unlock(&mutex_user_data); +} +void *update_user_station(int sockfd, int stationNum) { + pthread_mutex_lock(&mutex_user_data); + user_data[sockfd_to_user[sockfd]].stationNum = stationNum; + pthread_mutex_unlock(&mutex_user_data); +} +void *print_user_data(int index) { + printf("udpPort: %d, stationNum: %d, sockfd: %d\n", + user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd); +} +void *destroy_user(int sockfd) { + pthread_mutex_lock(&mutex_user_data); + + // stop the thread streaming to the user + pthread_cancel(user_stream_threads[sockfd_to_user[sockfd]]); + // "remove" the user from the list of user data + user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1}; + // map sockfd to -1 + sockfd_to_user[sockfd] = -1; + + pthread_mutex_unlock(&mutex_user_data); +} + + +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} \ No newline at end of file diff --git a/test b/test new file mode 100755 index 0000000..4bb883b Binary files /dev/null and b/test differ -- cgit v1.2.3-70-g09d2 From c77bc555ba1cc3b43f19b6a76b563d67eee2c347 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 18 Sep 2023 03:02:53 -0400 Subject: good stopping point before experimenting --- snowcast_server_concurrent.c | 42 +++++++++++++++++++----------------------- test | Bin 52849 -> 52785 bytes 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 7f70294..0586635 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -19,6 +19,7 @@ typedef struct user { int udpPort; int stationNum; int sockfd; + pthread_t streamThread; } user_t; #define NUM_STATIONS 2 @@ -37,10 +38,8 @@ int start_threads = 0; int max_active_users = 0; pthread_mutex_t mutex_user_data = PTHREAD_MUTEX_INITIALIZER; -// array from fd to users +// array from index to user_data user_t *user_data; -// array from fd to user's stream thread -pthread_t *user_stream_threads; station_t station_data[NUM_STATIONS]; int sockfd_to_user[MAX_USERS + 4]; @@ -71,11 +70,6 @@ main(int argc, char *argv[]) user_data = malloc(sizeof(user_t) * max_active_users); if (!user_data) { perror("malloc"); return 1; } - user_stream_threads = malloc(sizeof(pthread_t) * max_active_users); - if (!user_stream_threads) - { - perror("malloc"); return 1; - } // thread that manages file descriptors pthread_t s_thread, sync_thread; @@ -121,26 +115,29 @@ void *send_udp_packet_routine(void *arg) { int did_send_data = 0; int did_load_data = 0; + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + int * i = (int *) arg; while (1) { - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&m); if (!start_threads && did_send_data && did_load_data) { did_load_data = 0; did_send_data = 0; } while(!start_threads) { - pthread_cond_wait(&cond, &mutex); + pthread_cond_wait(&cond, &m); } - pthread_mutex_unlock(&mutex); - if(!did_send_data && start_threads) { + pthread_mutex_unlock(&m); + if(!did_send_data) { printf("send data: thread %d \n", i); did_send_data = 1; } - if(!did_load_data && start_threads) { + if(!did_load_data) { printf("load data: thread %d \n", i); did_load_data = 1; } + } return NULL; } @@ -179,9 +176,10 @@ void *synchronization_thread(void *arg) { start_threads = 1; printf("\nbroadcast %d\n", c++); pthread_cond_broadcast(&cond); - usleep(10000); + usleep(1000); start_threads = 0; sleep(1); + } } @@ -408,14 +406,12 @@ void *init_user(int sockfd) { user_t *more_users = realloc(user_data, sizeof(user_t) * max_active_users); if (!more_users) { perror("realloc"); exit(1); } user_data = more_users; - pthread_t *more_stream_threads = realloc(user_stream_threads, sizeof(pthread_t) * max_active_users); - if (!more_stream_threads) { perror("realloc"); exit(1); } - user_stream_threads = more_stream_threads; } // map sockfd to this user index & create its stream thread - user_data[user_index] = (user_t) {-1, -1, sockfd}; + pthread_t user_thread; + pthread_create(&user_thread, NULL, send_udp_packet_routine, (void *)user_index); + user_data[user_index] = (user_t){-1, -1, sockfd, user_thread}; sockfd_to_user[sockfd] = user_index; - pthread_create(&user_stream_threads[user_index], NULL, send_udp_packet_routine, (void *)sockfd); // free(user_stream_threads); pthread_mutex_unlock(&mutex_user_data); } @@ -430,16 +426,16 @@ void *update_user_station(int sockfd, int stationNum) { pthread_mutex_unlock(&mutex_user_data); } void *print_user_data(int index) { - printf("udpPort: %d, stationNum: %d, sockfd: %d\n", - user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd); + printf("udpPort: %d, stationNum: %d, sockfd: %d, threadId:%d\n", + user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd, user_data[index].streamThread); } void *destroy_user(int sockfd) { pthread_mutex_lock(&mutex_user_data); // stop the thread streaming to the user - pthread_cancel(user_stream_threads[sockfd_to_user[sockfd]]); + pthread_cancel(user_data[sockfd_to_user[sockfd]].streamThread); // "remove" the user from the list of user data - user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1}; + user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1, -1}; // map sockfd to -1 sockfd_to_user[sockfd] = -1; diff --git a/test b/test index 4bb883b..39b0be5 100755 Binary files a/test and b/test differ -- cgit v1.2.3-70-g09d2 From 5236560176cfe8e4d06be4812719037937b7f4dc Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 18 Sep 2023 10:07:28 -0400 Subject: rever back to pthread_cancel --- snowcast_server_concurrent.c | 110 ++++++++----------------------------------- test | Bin 52785 -> 52753 bytes 2 files changed, 19 insertions(+), 91 deletions(-) diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 0586635..903b3fd 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -55,7 +55,7 @@ void *init_user(int sockfd); void *update_user_udpPort(int sockfd, int udpPort); void *update_user_station(int sockfd, int stationNum); void *print_user_data(int sockfd); -void *destroy_user(int sockfd); +void destroy_user(int sockfd); // void *load_file(void* arg); @@ -107,68 +107,36 @@ main(int argc, char *argv[]) /* Make the manager routine */ void *send_udp_packet_routine(void *arg) { - // pthread_mutex_lock(&mutex); - // while(startThreads) { - // pthread_cond_wait(&cond, &mutex); - // } - // pthread_mutex_unlock(&mutex); - int did_send_data = 0; - int did_load_data = 0; - pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + int did_work = 1; + int * i = (int *) arg; while (1) { + // wait for pthread_mutex_lock(&m); - if (!start_threads && did_send_data && did_load_data) { - did_load_data = 0; - did_send_data = 0; - } - while(!start_threads) { + did_work = 0; + while (!start_threads) + { pthread_cond_wait(&cond, &m); } - pthread_mutex_unlock(&m); - if(!did_send_data) { + + if (!did_work) { printf("send data: thread %d \n", i); - did_send_data = 1; - } - if(!did_load_data) { printf("load data: thread %d \n", i); - did_load_data = 1; + did_work = 1; } + pthread_mutex_unlock(&m); + usleep(500000); + // pthread_mutex_lock(&mutex); + // start_threads = 0; + // pthread_mutex_unlock(&mutex); } return NULL; } -// /* Make the manager routine */ -// void *load_file(void *arg) { -// // read first data off the files -// pthread_mutex_lock(&mutex); -// while(startThreads) { -// pthread_cond_wait(&cond, &mutex); -// } -// pthread_mutex_unlock(&mutex); - -// int * i = (int *) arg; -// while (1) -// { -// pthread_mutex_lock(&mutex); -// while(startThreads) { -// pthread_cond_wait(&cond, &mutex); -// } -// pthread_mutex_unlock(&mutex); -// /* Do some work. */ -// printf("Thread %d \n", i); -// // send data to port -// // read data coming in off the file -// // sleep for a secong -// sleep(1); -// } -// return NULL; -// } - void *synchronization_thread(void *arg) { int c = 0; while (1) @@ -176,10 +144,9 @@ void *synchronization_thread(void *arg) { start_threads = 1; printf("\nbroadcast %d\n", c++); pthread_cond_broadcast(&cond); - usleep(1000); + usleep(2000); start_threads = 0; - sleep(1); - + usleep(1000000-2000); } } @@ -319,46 +286,6 @@ void *select_thread(void *arg) { printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); // update udp port of user update_user_udpPort(i, ntohs(command.number)); - - - - // // TALKER: get us a udp socket and bind it - // struct addrinfo hintsUdp, *servinfoUdp, *pUdp; - // int rvUdp, sockfdUdp, numbytesUdp; - // memset(&hintsUdp, 0, sizeof hintsUdp); - // hintsUdp.ai_family = AF_INET; // IPv4 - // hintsUdp.ai_socktype = SOCK_DGRAM; // UDP - // if ((rvUdp = getaddrinfo(argv[1], command.number, &hints, &servinfoUdp)) != 0) { - // fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rvUdp)); - // return 1; - // } - - // // loop through all the results and make a socket - // for(p = servinfoUdp; p != NULL; p = p->ai_next) { - // if ((sockfdUdp = socket(p->ai_family, p->ai_socktype, - // p->ai_protocol)) == -1) { - // perror("talker: socket"); - // continue; - // } - // break; - // } - - // if (p == NULL) { - // fprintf(stderr, "talker: failed to create socket\n"); - // return 2; - // } - - - // if ((numbytesUdp = sendto(sockfdUdp, "test", strlen("test"), 0, - // p->ai_addr, p->ai_addrlen)) == -1) { - // perror("talker: sendto"); - // exit(1); - // } - - // freeaddrinfo(servinfoUdp); - - // printf("talker: sent %d bytes to %d\n", numbytesUdp, sockfdUdp); - // close(sockfdUdp); } else if (command.commandType == 1) { // setStation command for the user @@ -429,11 +356,12 @@ void *print_user_data(int index) { printf("udpPort: %d, stationNum: %d, sockfd: %d, threadId:%d\n", user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd, user_data[index].streamThread); } -void *destroy_user(int sockfd) { +void destroy_user(int sockfd) { pthread_mutex_lock(&mutex_user_data); // stop the thread streaming to the user pthread_cancel(user_data[sockfd_to_user[sockfd]].streamThread); + // pthread_kill(user_data[sockfd_to_user[sockfd]].streamThread, SIGINT); // "remove" the user from the list of user data user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1, -1}; // map sockfd to -1 diff --git a/test b/test index 39b0be5..5c87dd6 100755 Binary files a/test and b/test differ -- cgit v1.2.3-70-g09d2 From bc24590991cb27e8bd220fd6d0585e76f804601d Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 18 Sep 2023 15:32:05 -0400 Subject: good progress. basic num_station data going & listener udp port works --- Makefile | 4 +- c | Bin 0 -> 34446 bytes l | Bin 0 -> 34254 bytes listener.c | 50 +++++++----- s | Bin 0 -> 52974 bytes snowcast_server_concurrent.c | 181 ++++++++++++++++++++++++++++++++----------- test | Bin 52753 -> 52753 bytes 7 files changed, 169 insertions(+), 66 deletions(-) create mode 100755 c create mode 100755 l create mode 100755 s diff --git a/Makefile b/Makefile index 1603f38..c47fa52 100644 --- a/Makefile +++ b/Makefile @@ -13,4 +13,6 @@ client: client.c $(CC) $(CFLAGS) -o snowcast_control client.c new: - $(CC) $(CFLAGS) -o test snowcast_server_concurrent.c \ No newline at end of file + $(CC) $(CFLAGS) -o s snowcast_server_concurrent.c + $(CC) $(CFLAGS) -o l listener.c + $(CC) $(CFLAGS) -o c client.c \ No newline at end of file diff --git a/c b/c new file mode 100755 index 0000000..fdfd8d6 Binary files /dev/null and b/c differ diff --git a/l b/l new file mode 100755 index 0000000..6eaa41d Binary files /dev/null and b/l differ diff --git a/listener.c b/listener.c index 723cb1b..2d46307 100644 --- a/listener.c +++ b/listener.c @@ -13,9 +13,9 @@ #include #include -#define MYPORT "4950" // the port users will be connecting to +// #define MYPORT "4950" // the port users will be connecting to -#define MAXBUFLEN 100 +#define MAXBUFLEN 16384 // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) @@ -27,7 +27,7 @@ void *get_in_addr(struct sockaddr *sa) return &(((struct sockaddr_in6*)sa)->sin6_addr); } -int main(void) +int main(int argc, char *argv[]) { int sockfd; struct addrinfo hints, *servinfo, *p; @@ -38,12 +38,20 @@ int main(void) socklen_t addr_len; char s[INET6_ADDRSTRLEN]; + if (argc != 2) { + fprintf(stderr,"\n"); + exit(1); + } + + const char* udp_port = argv[1]; + + memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET6; // set to AF_INET to use IPv4 + hints.ai_family = AF_INET; // set to AF_INET to use IPv4 hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; // use my IP - if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) { + if ((rv = getaddrinfo(NULL, udp_port, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } @@ -72,22 +80,26 @@ int main(void) freeaddrinfo(servinfo); - printf("listener: waiting to recvfrom...\n"); + int count = 0; - addr_len = sizeof their_addr; - if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, - (struct sockaddr *)&their_addr, &addr_len)) == -1) { - perror("recvfrom"); - exit(1); - } + while(1) { + printf("\nlistener: waiting to recvfrom... %d times\n", count++); - printf("listener: got packet from %s\n", - inet_ntop(their_addr.ss_family, - get_in_addr((struct sockaddr *)&their_addr), - s, sizeof s)); - printf("listener: packet is %d bytes long\n", numbytes); - buf[numbytes] = '\0'; - printf("listener: packet contains \"%s\"\n", buf); + addr_len = sizeof their_addr; + if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN , 0, + (struct sockaddr *)&their_addr, &addr_len)) == -1) { + perror("recvfrom"); + exit(1); + } + + printf("listener: got packet from %s\n", + inet_ntop(their_addr.ss_family, + get_in_addr((struct sockaddr *)&their_addr), + s, sizeof s)); + printf("listener: packet is %d bytes long\n", numbytes); + buf[numbytes] = '\0'; + printf("listener: packet contains \"%s\"\n", buf); + } close(sockfd); diff --git a/s b/s new file mode 100755 index 0000000..05d1ffc Binary files /dev/null and b/s differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 903b3fd..e09e398 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -10,9 +10,14 @@ #include "protocol.h" +#define NUM_STATIONS 2 +#define LINE_MAX 1024 +#define MAX_USERS 1000 +#define MAX_PATH 50 + typedef struct station { - char* filePath; int currentChunk; + char* filePath; } station_t; typedef struct user { @@ -22,9 +27,6 @@ typedef struct user { pthread_t streamThread; } user_t; -#define NUM_STATIONS 2 -#define LINE_MAX 1024 -#define MAX_USERS 1000 /* For safe condition variable usage, must use a boolean predicate and */ /* a mutex with the condition. */ @@ -32,18 +34,18 @@ int count = 0; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +const char *port; int start_threads = 0; - int max_active_users = 0; pthread_mutex_t mutex_user_data = PTHREAD_MUTEX_INITIALIZER; // array from index to user_data user_t *user_data; -station_t station_data[NUM_STATIONS]; -int sockfd_to_user[MAX_USERS + 4]; +int sockfd_to_user[MAX_USERS]; -char* port = "4950"; +// stations array pointer +station_t *station_data; void *send_udp_packet_routine(void* arg); void *select_thread(void* arg); @@ -62,27 +64,49 @@ void destroy_user(int sockfd); main(int argc, char *argv[]) { - // temporary - station_data[0] = (station_t) {"mp3/Beethoven-SymphonyNo5.mp3", 0}; - station_data[1] = (station_t) {"mp3/DukeEllington-Caravan.mp3", 0}; - // threads to control reading files at chunks while the other threads sleep + // station_data = malloc(sizeof(station_t) * NUM_STATIONS); + // check and assign arguments + if (argc < 3) { + fprintf(stderr,"usage: ./snowcast_server [file 1] [file 2] ... \n"); + exit(1); + } + + port = argv[1]; + + // init stations + size_t totalSize = 0; + // get size to malloc + for (int i = 2; i < argc; i++) + { + printf("file: %s\n", argv[i]); + totalSize += sizeof(int) + strlen(argv[i]); + } + station_data = malloc(totalSize); + // assign the stations + for (int i = 2; i < argc; i++) + { + station_data[i - 2] = (station_t) { 0, argv[i]}; + } + + // print all indexes in station data + for (int i = 0; i < NUM_STATIONS; i++) + { + printf("station %d: %s\n", i, station_data[i].filePath); + } + // make array of user data user_data = malloc(sizeof(user_t) * max_active_users); if (!user_data) { perror("malloc"); return 1; } - // thread that manages file descriptors - pthread_t s_thread, sync_thread; + // make and start "select" thread that manages: + // 1) new connections, 2) requests from current connections, 3)cloing connections + pthread_t s_thread; pthread_create(&s_thread, NULL, select_thread, NULL); - // starts the threads after created - // sleep(1); - // startThreads = 0; - // pthread_cond_broadcast(&cond); - // command line interface char input[LINE_MAX]; - while (1) { + while (1) { char *line = fgets(input, LINE_MAX, stdin); if (line == NULL) { @@ -98,6 +122,7 @@ main(int argc, char *argv[]) } } else if (strncmp("s\n", input, LINE_MAX) == 0) { // start the streaming threads + pthread_t sync_thread; pthread_create(&sync_thread, NULL, synchronization_thread, NULL); } } @@ -107,33 +132,95 @@ main(int argc, char *argv[]) /* Make the manager routine */ void *send_udp_packet_routine(void *arg) { - pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + // unpack args + int user_index = (int) arg; + printf("thread : user_index: %d\n", user_index); + // print user data + print_user_data(user_index); + // declare vairables to be used int did_work = 1; + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + int s; + int udp_sockfd; + struct addrinfo thread_hints, *thread_res, *thread_servinfo; + int error_code; + + // TODO: add error checking on these calls*** + + // setup hints + memset(&thread_hints, 0, sizeof thread_hints); + thread_hints.ai_family = AF_INET; // use IPv4 only + thread_hints.ai_socktype = SOCK_DGRAM; + thread_hints.ai_flags = AI_PASSIVE; // fill in my IP for me + + // setup the socket for client listener DATAGRAM (udp) + // cover the port integer to a string + int int_port = user_data[user_index].udpPort; + int length = snprintf( NULL, 0, "%d", int_port ); + char* port = malloc( length + 1 ); + snprintf( port, length + 1, "%d", int_port ); + sprintf(port, "%d", int_port); + + if (error_code = getaddrinfo(NULL, port, &thread_hints, &thread_servinfo) != 0) + { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error_code)); + return 1; + } + free(port); - int * i = (int *) arg; - while (1) + // loop through all the results and make a socket + for(thread_res = thread_servinfo; thread_res != NULL; thread_res = thread_res->ai_next) { + if ((udp_sockfd = socket(thread_res->ai_family, thread_res->ai_socktype, + thread_res->ai_protocol)) == -1) { + perror("talker: socket"); + continue; + } + break; + } + if (udp_sockfd == NULL) { + fprintf(stderr, "talker: failed to create socket\n"); + return (NULL); + } + + // bind(udp_sockfd, thread_res->ai_addr, thread_res->ai_addrlen); + + + // freeaddrinfo(thread_servinfo); + + while (1) { + // wait for + pthread_mutex_lock(&m); + did_work = 0; + while (!start_threads) { - // wait for - pthread_mutex_lock(&m); - did_work = 0; - while (!start_threads) - { - pthread_cond_wait(&cond, &m); - } + pthread_cond_wait(&cond, &m); + } + int station_num = user_data[user_index].stationNum; + if (station_num == -1) { + did_work = 1; + } - if (!did_work) { - printf("send data: thread %d \n", i); - printf("load data: thread %d \n", i); - did_work = 1; + if (!did_work) { + // sendto a random string of data to the user + int station_num = user_data[user_index].stationNum - 1; + char *data = station_data[station_num].filePath; + printf("load data: thread %d \n", user_index); + int numbytes; + if ((numbytes = sendto(udp_sockfd, data, strlen(data), 0, + thread_res->ai_addr, thread_res->ai_addrlen)) == -1) { + perror("talker: sendto"); + return (NULL); } - pthread_mutex_unlock(&m); + printf("send data: thread %d \n", user_index); - usleep(500000); - // pthread_mutex_lock(&mutex); - // start_threads = 0; - // pthread_mutex_unlock(&mutex); + did_work = 1; } + + pthread_mutex_unlock(&m); + + usleep(500000); + } return NULL; } @@ -223,7 +310,7 @@ void *select_thread(void *arg) { // keep track of the biggest file descriptor fdmax = listener; // so far, it's this one - while(1==1) { + while(1) { read_fds = master; // copy it if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { perror("select"); @@ -253,7 +340,6 @@ void *select_thread(void *arg) { get_in_addr((struct sockaddr*)&remoteaddr), remoteIP, INET6_ADDRSTRLEN), newfd); - // init user with this newfd init_user(newfd); @@ -334,17 +420,20 @@ void *init_user(int sockfd) { if (!more_users) { perror("realloc"); exit(1); } user_data = more_users; } - // map sockfd to this user index & create its stream thread - pthread_t user_thread; - pthread_create(&user_thread, NULL, send_udp_packet_routine, (void *)user_index); - user_data[user_index] = (user_t){-1, -1, sockfd, user_thread}; + // map TCP sockfd to this user index + user_data[user_index] = (user_t){-1, -1, sockfd, -1}; sockfd_to_user[sockfd] = user_index; // free(user_stream_threads); pthread_mutex_unlock(&mutex_user_data); } void *update_user_udpPort(int sockfd, int udpPort) { pthread_mutex_lock(&mutex_user_data); - user_data[sockfd_to_user[sockfd]].udpPort = udpPort; + // get the user + user_t *user = &user_data[sockfd_to_user[sockfd]]; + // set the udpPort + user->udpPort = udpPort; + // start the stream thread, now that we have the udpPort + pthread_create(&user->streamThread, NULL, send_udp_packet_routine, (void *)sockfd_to_user[sockfd]); pthread_mutex_unlock(&mutex_user_data); } void *update_user_station(int sockfd, int stationNum) { diff --git a/test b/test index 5c87dd6..a576c5e 100755 Binary files a/test and b/test differ -- cgit v1.2.3-70-g09d2 From 8a25dcda67683817ddd55b669111f7dd8e3107ef Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 18 Sep 2023 18:23:35 -0400 Subject: decent connection, but not there yet --- Makefile | 2 +- c | Bin 34446 -> 35150 bytes c.dSYM/Contents/Info.plist | 20 ++++++++++++++++++ c.dSYM/Contents/Resources/DWARF/c | Bin 0 -> 13761 bytes client.c | 42 ++++++++++++++++++++++++++++++++++++++ l | Bin 34254 -> 34654 bytes l.dSYM/Contents/Info.plist | 20 ++++++++++++++++++ l.dSYM/Contents/Resources/DWARF/l | Bin 0 -> 11745 bytes s | Bin 52974 -> 54558 bytes s.dSYM/Contents/Info.plist | 20 ++++++++++++++++++ s.dSYM/Contents/Resources/DWARF/s | Bin 0 -> 21520 bytes snowcast_control | Bin 34461 -> 20992 bytes snowcast_server | Bin 34636 -> 25336 bytes snowcast_server_concurrent.c | 42 +++++++++++++++++++++++++++++++------- 14 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 c.dSYM/Contents/Info.plist create mode 100644 c.dSYM/Contents/Resources/DWARF/c create mode 100644 l.dSYM/Contents/Info.plist create mode 100644 l.dSYM/Contents/Resources/DWARF/l create mode 100644 s.dSYM/Contents/Info.plist create mode 100644 s.dSYM/Contents/Resources/DWARF/s diff --git a/Makefile b/Makefile index c47fa52..d48b036 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc # CFLAGS = -std=c99 -target x86_64-apple-darwin20 -g -# CFLAGS = -std=c99 -Wall -g +CFLAGS = -g -I. -std=gnu99 -Wall -pthread default: all diff --git a/c b/c index fdfd8d6..a1f2a86 100755 Binary files a/c and b/c differ diff --git a/c.dSYM/Contents/Info.plist b/c.dSYM/Contents/Info.plist new file mode 100644 index 0000000..ceced96 --- /dev/null +++ b/c.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.c + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/c.dSYM/Contents/Resources/DWARF/c b/c.dSYM/Contents/Resources/DWARF/c new file mode 100644 index 0000000..c325e9f Binary files /dev/null and b/c.dSYM/Contents/Resources/DWARF/c differ diff --git a/client.c b/client.c index 1acd3ae..6e6c95a 100644 --- a/client.c +++ b/client.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -22,6 +23,7 @@ #define MAX_READ_SIZE 1024 #define LINE_MAX 1024 +void *reply_thread_routine(void *args); // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) @@ -105,6 +107,9 @@ int main(int argc, char *argv[]) exit(1); } + pthread_t reply_thread; + pthread_create(&reply_thread, NULL, reply_thread_routine, (void*)sockfd); + char input[LINE_MAX]; printf("Enter a number to change to it's station. Click q to end stream.\n"); while (1) { @@ -133,4 +138,41 @@ int main(int argc, char *argv[]) } return 0; +} + +void *reply_thread_routine(void* args) { + int sockfd = (int)args; + int recvbytes; + char buf[MAX_READ_SIZE]; + while (1) { + // recv the message, check for errors too + if ((recvbytes = recv(sockfd, &buf, MAX_READ_SIZE, 0)) == -1) { + perror("recv"); + exit(1); + } + buf[recvbytes] = '\0'; + printf("client: received %d bytes on a reply call \n", recvbytes); + // print the two first field of the call + printf("client: replyType: %d, stringSize: %d\n", buf[0], buf[1]); + // print the while buffer by char + for (int i = 0; i < recvbytes; i++) { + printf("%d", buf[i]); + } + + struct Reply reply; + memcpy(&reply, buf, sizeof(struct Reply)); + + if (reply.replyType == 3) { + printf("client: received an announce message\n"); + + continue; + } else if (reply.replyType == 4) { + printf("client: received an invalid command message\n"); + + continue; + } + printf("client: received an unknown message\n"); + + memset(buf, 0, MAX_READ_SIZE); + } } \ No newline at end of file diff --git a/l b/l index 6eaa41d..265f692 100755 Binary files a/l and b/l differ diff --git a/l.dSYM/Contents/Info.plist b/l.dSYM/Contents/Info.plist new file mode 100644 index 0000000..7025c85 --- /dev/null +++ b/l.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.l + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/l.dSYM/Contents/Resources/DWARF/l b/l.dSYM/Contents/Resources/DWARF/l new file mode 100644 index 0000000..9843052 Binary files /dev/null and b/l.dSYM/Contents/Resources/DWARF/l differ diff --git a/s b/s index 05d1ffc..63b39b5 100755 Binary files a/s and b/s differ diff --git a/s.dSYM/Contents/Info.plist b/s.dSYM/Contents/Info.plist new file mode 100644 index 0000000..9ce500c --- /dev/null +++ b/s.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.s + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/s.dSYM/Contents/Resources/DWARF/s b/s.dSYM/Contents/Resources/DWARF/s new file mode 100644 index 0000000..09cab17 Binary files /dev/null and b/s.dSYM/Contents/Resources/DWARF/s differ diff --git a/snowcast_control b/snowcast_control index 1b879ff..24fe551 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_server b/snowcast_server index bf1801b..8a4c1cc 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index e09e398..4387407 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -62,7 +62,7 @@ void destroy_user(int sockfd); // void *load_file(void* arg); -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { // threads to control reading files at chunks while the other threads sleep // station_data = malloc(sizeof(station_t) * NUM_STATIONS); @@ -165,7 +165,7 @@ void *send_udp_packet_routine(void *arg) { if (error_code = getaddrinfo(NULL, port, &thread_hints, &thread_servinfo) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error_code)); - return 1; + return (NULL); } free(port); @@ -203,7 +203,7 @@ void *send_udp_packet_routine(void *arg) { if (!did_work) { // sendto a random string of data to the user - int station_num = user_data[user_index].stationNum - 1; + int station_num = user_data[user_index].stationNum; char *data = station_data[station_num].filePath; printf("load data: thread %d \n", user_index); int numbytes; @@ -374,10 +374,38 @@ void *select_thread(void *arg) { update_user_udpPort(i, ntohs(command.number)); } else if (command.commandType == 1) { - // setStation command for the user - printf("TODO: set station to %d\n", ntohs(command.number)); + int station_num = ntohs(command.number); + printf("setting station to %d\n", ntohs(command.number)); // update station of user update_user_station(i, ntohs(command.number)); + + const char* song_name = station_data[station_num].filePath; + size_t song_name_size = strlen(song_name); // don't add 1, don't want to include the null terminator + struct Announce *announce = malloc(sizeof *announce + song_name_size); + + printf("song_name: %s\n", song_name); + + announce->replyType = 3; + announce->songnameSize = song_name_size; + + announce->songname = malloc(song_name_size); + memcpy(announce->songname, song_name, song_name_size); + + // print out all fields on announce on one line + printf("announce: %d %d %s\n", announce->replyType, announce->songnameSize, announce->songname); + + char* send_buffer[sizeof(struct Announce) + song_name_size]; + memcpy(send_buffer, announce, sizeof(struct Announce)); + memcpy(send_buffer+sizeof(struct Announce), song_name, song_name_size); + + int bytessent; + if ((bytessent = send(newfd, send_buffer, sizeof(struct Announce) + song_name_size, 0)) == -1) + perror("send"); + // print the number of bytes sent + printf("sent %d bytes\n", bytessent); + + free(announce->songname); + free(announce); } else { // send back in invalid command @@ -410,9 +438,9 @@ void *init_user(int sockfd) { // this is to save memory space. // in general, the displacement of 4 is where a user "used to be" int user_index = max_active_users++; - if(user_data[sockfd-4].sockfd == -1) { + if(user_data[(sockfd-4)/2].sockfd == -1) { printf("reusing memory\n"); - user_index = sockfd - 4; + user_index = (sockfd - 4)/2; } else { printf("making new memory\n"); // have to make more memory -- cgit v1.2.3-70-g09d2 From 186915db036f06a604883b644e40eaf377aedadf Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 18 Sep 2023 18:52:24 -0400 Subject: got it to work, not sure on protocol. --- c | Bin 35150 -> 35150 bytes c.dSYM/Contents/Resources/DWARF/c | Bin 13761 -> 13761 bytes client.c | 2 +- l | Bin 34654 -> 34654 bytes s | Bin 54558 -> 54494 bytes s.dSYM/Contents/Resources/DWARF/s | Bin 21520 -> 21128 bytes snowcast_control | Bin 20992 -> 35165 bytes snowcast_control.dSYM/Contents/Info.plist | 20 +++++++++++++++ .../Contents/Resources/DWARF/snowcast_control | Bin 0 -> 13761 bytes snowcast_server | Bin 25336 -> 35116 bytes snowcast_server.dSYM/Contents/Info.plist | 20 +++++++++++++++ .../Contents/Resources/DWARF/snowcast_server | Bin 0 -> 15573 bytes snowcast_server_concurrent.c | 27 +++++++-------------- 13 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 snowcast_control.dSYM/Contents/Info.plist create mode 100644 snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control create mode 100644 snowcast_server.dSYM/Contents/Info.plist create mode 100644 snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server diff --git a/c b/c index a1f2a86..8e2e138 100755 Binary files a/c and b/c differ diff --git a/c.dSYM/Contents/Resources/DWARF/c b/c.dSYM/Contents/Resources/DWARF/c index c325e9f..7af6442 100644 Binary files a/c.dSYM/Contents/Resources/DWARF/c and b/c.dSYM/Contents/Resources/DWARF/c differ diff --git a/client.c b/client.c index 6e6c95a..5edff63 100644 --- a/client.c +++ b/client.c @@ -156,7 +156,7 @@ void *reply_thread_routine(void* args) { printf("client: replyType: %d, stringSize: %d\n", buf[0], buf[1]); // print the while buffer by char for (int i = 0; i < recvbytes; i++) { - printf("%d", buf[i]); + printf("%c ", buf[i]); } struct Reply reply; diff --git a/l b/l index 265f692..52aca28 100755 Binary files a/l and b/l differ diff --git a/s b/s index 63b39b5..b664e12 100755 Binary files a/s and b/s differ diff --git a/s.dSYM/Contents/Resources/DWARF/s b/s.dSYM/Contents/Resources/DWARF/s index 09cab17..feff9cb 100644 Binary files a/s.dSYM/Contents/Resources/DWARF/s and b/s.dSYM/Contents/Resources/DWARF/s differ diff --git a/snowcast_control b/snowcast_control index 24fe551..1ab5778 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Info.plist b/snowcast_control.dSYM/Contents/Info.plist new file mode 100644 index 0000000..afe5b44 --- /dev/null +++ b/snowcast_control.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.snowcast_control + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control new file mode 100644 index 0000000..76fce35 Binary files /dev/null and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_server b/snowcast_server index 8a4c1cc..444d321 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Info.plist b/snowcast_server.dSYM/Contents/Info.plist new file mode 100644 index 0000000..789e734 --- /dev/null +++ b/snowcast_server.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.snowcast_server + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server new file mode 100644 index 0000000..0123b4a Binary files /dev/null and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 4387407..110792d 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -379,33 +379,24 @@ void *select_thread(void *arg) { // update station of user update_user_station(i, ntohs(command.number)); - const char* song_name = station_data[station_num].filePath; - size_t song_name_size = strlen(song_name); // don't add 1, don't want to include the null terminator - struct Announce *announce = malloc(sizeof *announce + song_name_size); + char* file_path = station_data[station_num].filePath; + int len_file_path = strlen(file_path); - printf("song_name: %s\n", song_name); + char *send_buffer = malloc(len_file_path+2); + send_buffer[0] = 3; + send_buffer[1] = len_file_path; - announce->replyType = 3; - announce->songnameSize = song_name_size; + memcpy(send_buffer + 2, file_path, len_file_path); - announce->songname = malloc(song_name_size); - memcpy(announce->songname, song_name, song_name_size); - - // print out all fields on announce on one line - printf("announce: %d %d %s\n", announce->replyType, announce->songnameSize, announce->songname); - - char* send_buffer[sizeof(struct Announce) + song_name_size]; - memcpy(send_buffer, announce, sizeof(struct Announce)); - memcpy(send_buffer+sizeof(struct Announce), song_name, song_name_size); + printf("buffer: %s\n", send_buffer); int bytessent; - if ((bytessent = send(newfd, send_buffer, sizeof(struct Announce) + song_name_size, 0)) == -1) + if ((bytessent = send(newfd, send_buffer, len_file_path + 2, 0)) == -1) perror("send"); // print the number of bytes sent printf("sent %d bytes\n", bytessent); - free(announce->songname); - free(announce); + free(send_buffer); } else { // send back in invalid command -- cgit v1.2.3-70-g09d2 From 779ce6a6885346257b4d18f1efe205984cfff079 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 18 Sep 2023 19:04:14 -0400 Subject: announce message basics done --- c | Bin 35150 -> 35294 bytes c.dSYM/Contents/Resources/DWARF/c | Bin 13761 -> 13866 bytes client.c | 15 +++++++- l | Bin 34654 -> 34654 bytes s | Bin 54494 -> 54654 bytes s.dSYM/Contents/Resources/DWARF/s | Bin 21128 -> 21196 bytes snowcast_control | Bin 35165 -> 35309 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 13761 -> 13866 bytes snowcast_server | Bin 35116 -> 35116 bytes snowcast_server_concurrent.c | 42 ++++++++++++--------- 10 files changed, 37 insertions(+), 20 deletions(-) diff --git a/c b/c index 8e2e138..e73bb21 100755 Binary files a/c and b/c differ diff --git a/c.dSYM/Contents/Resources/DWARF/c b/c.dSYM/Contents/Resources/DWARF/c index 7af6442..785b2db 100644 Binary files a/c.dSYM/Contents/Resources/DWARF/c and b/c.dSYM/Contents/Resources/DWARF/c differ diff --git a/client.c b/client.c index 5edff63..29aad13 100644 --- a/client.c +++ b/client.c @@ -158,13 +158,24 @@ void *reply_thread_routine(void* args) { for (int i = 0; i < recvbytes; i++) { printf("%c ", buf[i]); } - struct Reply reply; - memcpy(&reply, buf, sizeof(struct Reply)); + memcpy(&reply, buf, 2); + + // print out the fields of reply on one line + printf("\nclient: replyType: %d, stringSize: %d\n", reply.replyType, reply.stringSize); + // print the size of reply if (reply.replyType == 3) { printf("client: received an announce message\n"); + char *song_name = malloc(reply.stringSize); + // printf(sizeof(struct Reply)); + memcpy(song_name, buf + 2, reply.stringSize); + + printf("client: song name: %s\n", song_name); + + free(song_name); + continue; } else if (reply.replyType == 4) { printf("client: received an invalid command message\n"); diff --git a/l b/l index 52aca28..dc80387 100755 Binary files a/l and b/l differ diff --git a/s b/s index b664e12..05b5da5 100755 Binary files a/s and b/s differ diff --git a/s.dSYM/Contents/Resources/DWARF/s b/s.dSYM/Contents/Resources/DWARF/s index feff9cb..74f9ec9 100644 Binary files a/s.dSYM/Contents/Resources/DWARF/s and b/s.dSYM/Contents/Resources/DWARF/s differ diff --git a/snowcast_control b/snowcast_control index 1ab5778..fa08142 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index 76fce35..774ea29 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_server b/snowcast_server index 444d321..c194134 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 110792d..03d6414 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -59,6 +59,8 @@ void *update_user_station(int sockfd, int stationNum); void *print_user_data(int sockfd); void destroy_user(int sockfd); +void send_announce_message(int fd, int station_num); + // void *load_file(void* arg); @@ -379,24 +381,7 @@ void *select_thread(void *arg) { // update station of user update_user_station(i, ntohs(command.number)); - char* file_path = station_data[station_num].filePath; - int len_file_path = strlen(file_path); - - char *send_buffer = malloc(len_file_path+2); - send_buffer[0] = 3; - send_buffer[1] = len_file_path; - - memcpy(send_buffer + 2, file_path, len_file_path); - - printf("buffer: %s\n", send_buffer); - - int bytessent; - if ((bytessent = send(newfd, send_buffer, len_file_path + 2, 0)) == -1) - perror("send"); - // print the number of bytes sent - printf("sent %d bytes\n", bytessent); - - free(send_buffer); + send_announce_message(i, station_num); } else { // send back in invalid command @@ -486,4 +471,25 @@ void *get_in_addr(struct sockaddr *sa) } return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +void send_announce_message(int fd, int station_num) { + char* file_path = station_data[station_num].filePath; + int len_file_path = strlen(file_path); + + char *send_buffer = malloc(len_file_path+2); + send_buffer[0] = 3; + send_buffer[1] = len_file_path; + + memcpy(send_buffer + 2, file_path, len_file_path); + + printf("buffer: %s\n", send_buffer); + + int bytessent; + if ((bytessent = send(fd, send_buffer, len_file_path + 2, 0)) == -1) + perror("send"); + // print the number of bytes sent + printf("sent %d bytes\n", bytessent); + + free(send_buffer); } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 7db333857219362ba14dec132825debc0d940a6c Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 18 Sep 2023 23:58:47 -0400 Subject: cleanup some bugs. you can now listen to the music! good stopping point --- c | Bin 35294 -> 35294 bytes c.dSYM/Contents/Resources/DWARF/c | Bin 13866 -> 13886 bytes client.c | 2 + l | Bin 34654 -> 34638 bytes l.dSYM/Contents/Resources/DWARF/l | Bin 11745 -> 11651 bytes listener.c | 23 +++++--- s | Bin 54654 -> 55198 bytes s.dSYM/Contents/Resources/DWARF/s | Bin 21196 -> 23594 bytes snowcast_server_concurrent.c | 121 +++++++++++++++++++++++++++++++++----- 9 files changed, 124 insertions(+), 22 deletions(-) diff --git a/c b/c index e73bb21..35031be 100755 Binary files a/c and b/c differ diff --git a/c.dSYM/Contents/Resources/DWARF/c b/c.dSYM/Contents/Resources/DWARF/c index 785b2db..4a8f904 100644 Binary files a/c.dSYM/Contents/Resources/DWARF/c and b/c.dSYM/Contents/Resources/DWARF/c differ diff --git a/client.c b/client.c index 29aad13..ecb0be9 100644 --- a/client.c +++ b/client.c @@ -106,6 +106,8 @@ int main(int argc, char *argv[]) perror("send"); exit(1); } + // print the amount of bytes sent + printf("client: sent %d bytes on a hello call \n", numbytessent); pthread_t reply_thread; pthread_create(&reply_thread, NULL, reply_thread_routine, (void*)sockfd); diff --git a/l b/l index dc80387..281f522 100755 Binary files a/l and b/l differ diff --git a/l.dSYM/Contents/Resources/DWARF/l b/l.dSYM/Contents/Resources/DWARF/l index 9843052..c55216a 100644 Binary files a/l.dSYM/Contents/Resources/DWARF/l and b/l.dSYM/Contents/Resources/DWARF/l differ diff --git a/listener.c b/listener.c index 2d46307..d5b4799 100644 --- a/listener.c +++ b/listener.c @@ -83,7 +83,7 @@ int main(int argc, char *argv[]) int count = 0; while(1) { - printf("\nlistener: waiting to recvfrom... %d times\n", count++); + // printf("\nlistener: waiting to recvfrom... %d times\n", count++); addr_len = sizeof their_addr; if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN , 0, @@ -91,14 +91,21 @@ int main(int argc, char *argv[]) perror("recvfrom"); exit(1); } + // buf[numbytes] = '\0'; - printf("listener: got packet from %s\n", - inet_ntop(their_addr.ss_family, - get_in_addr((struct sockaddr *)&their_addr), - s, sizeof s)); - printf("listener: packet is %d bytes long\n", numbytes); - buf[numbytes] = '\0'; - printf("listener: packet contains \"%s\"\n", buf); + //printf("listener: got packet from %s\n", + // inet_ntop(their_addr.ss_family, + // get_in_addr((struct sockaddr *)&their_addr), + // s, sizeof s)); + //printf("listener: packet is %d bytes long\n", numbytes); + //buf[numbytes] = '\0'; + //printf("listener: packet contains \"%s\"\n", buf); + + // print the size + + write(STDOUT_FILENO, buf, numbytes); + + memset(buf, 0, MAXBUFLEN); } close(sockfd); diff --git a/s b/s index 05b5da5..10bc785 100755 Binary files a/s and b/s differ diff --git a/s.dSYM/Contents/Resources/DWARF/s b/s.dSYM/Contents/Resources/DWARF/s index 74f9ec9..4db3832 100644 Binary files a/s.dSYM/Contents/Resources/DWARF/s and b/s.dSYM/Contents/Resources/DWARF/s differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 03d6414..3b71156 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -10,13 +10,12 @@ #include "protocol.h" -#define NUM_STATIONS 2 #define LINE_MAX 1024 #define MAX_USERS 1000 #define MAX_PATH 50 typedef struct station { - int currentChunk; + int seekIndex; char* filePath; } station_t; @@ -34,7 +33,10 @@ int count = 0; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t station_mutex = PTHREAD_MUTEX_INITIALIZER; + const char *port; +int num_stations; int start_threads = 0; int max_active_users = 0; @@ -75,6 +77,10 @@ int main(int argc, char *argv[]) } port = argv[1]; + num_stations = argc - 2; + + printf("port: %s\n", port); + printf("num_stations: %d\n", num_stations); // init stations size_t totalSize = 0; @@ -92,7 +98,7 @@ int main(int argc, char *argv[]) } // print all indexes in station data - for (int i = 0; i < NUM_STATIONS; i++) + for (int i = 0; i < num_stations; i++) { printf("station %d: %s\n", i, station_data[i].filePath); } @@ -132,6 +138,27 @@ int main(int argc, char *argv[]) return 0; } +int sendall(int udp_sockfd, char *buf, int *len, struct addrinfo *thread_res) +{ + int MAX_PACKET_SIZE = 512; + int total = 0; // how many bytes we've sent + int bytesleft = *len; // how many we have left to send + int n; + + while(total < *len) { + n = sendto(udp_sockfd, buf+total, MAX_PACKET_SIZE, 0, thread_res->ai_addr, thread_res->ai_addrlen); + // thread_res->ai_addr, thread_res->ai_addrlen)) == -1; + if (n == -1) { break; } + total += n; + bytesleft -= n; + } + + *len = total; // return number actually sent here + + return n==-1?-1:0; // return -1 on failure, 0 on success +} + + /* Make the manager routine */ void *send_udp_packet_routine(void *arg) { // unpack args @@ -198,6 +225,7 @@ void *send_udp_packet_routine(void *arg) { { pthread_cond_wait(&cond, &m); } + int station_num = user_data[user_index].stationNum; if (station_num == -1) { did_work = 1; @@ -207,21 +235,52 @@ void *send_udp_packet_routine(void *arg) { // sendto a random string of data to the user int station_num = user_data[user_index].stationNum; char *data = station_data[station_num].filePath; - printf("load data: thread %d \n", user_index); - int numbytes; - if ((numbytes = sendto(udp_sockfd, data, strlen(data), 0, - thread_res->ai_addr, thread_res->ai_addrlen)) == -1) { - perror("talker: sendto"); + // printf("load data: thread %d \n", user_index); + + // get file path + char* file_path = station_data[station_num].filePath; + // get current seek chunk + int current_chunk = station_data[station_num].seekIndex; + FILE* file_stream = fopen(file_path, "r"); + if (fseek(file_stream, current_chunk, SEEK_SET) == -1) { + perror("fseek"); return (NULL); } - printf("send data: thread %d \n", user_index); + size_t BYTES_PER_SECOND = 16*1024; + // read 1000 bytes of the file + char file_buffer[BYTES_PER_SECOND]; + if (fread(file_buffer, BYTES_PER_SECOND, 1, file_stream) == -1) { + perror("fread"); + return (NULL); + } + // printf("send data: thread %d \n", user_index); + // int numbytes; + // if ((numbytes = sendto(udp_sockfd, data, strlen(data), 0, + // thread_res->ai_addr, thread_res->ai_addrlen)) == -1) { + // perror("talker: sendto"); + // return (NULL); + // } + // print the size of the file_buffer + // printf("size of file_buffer: %lu\n", sizeof(file_buffer)); + + int bytes_sent = sizeof(file_buffer); + if (sendall(udp_sockfd, file_buffer, &bytes_sent, thread_res) == -1) + { + perror("sendall"); + printf("We only sent %d bytes because of the error!\n", bytes_sent); + } + // printf("We sent all %d bytes!\n", bytes_sent); did_work = 1; + + close(file_stream); + + usleep(400000); } pthread_mutex_unlock(&m); - usleep(500000); + usleep(100000); } return NULL; } @@ -231,11 +290,39 @@ void *synchronization_thread(void *arg) { while (1) { start_threads = 1; - printf("\nbroadcast %d\n", c++); + // printf("\nbroadcast %d\n", c++); pthread_cond_broadcast(&cond); usleep(2000); start_threads = 0; - usleep(1000000-2000); + // printf("before loop"); + // update file seek index for each station + size_t BYTES_PER_SECOND = 16*1024; + // print num_stations + // printf("num_stations: %d\n", num_stations); + for (int i = 0; i < num_stations; i++) + { + // printf("checking station %d\n", i); + // get size of file + FILE* fp = fopen(station_data[i].filePath, "r"); + fseek(fp, 0L, SEEK_END); + size_t size = ftell(fp); + if (size == -1) { + perror("ftell"); + return (NULL); + } + station_data[i].seekIndex += BYTES_PER_SECOND; + // if the seek index is greater than the size of the file, reset it + if (station_data[i].seekIndex >= size) + { + // printf("resetting seek index for station %d\n", i); + station_data[i].seekIndex = 0; + } + fclose(fp); + } + + + usleep(2000); + usleep(1000000-4000); } } @@ -348,9 +435,15 @@ void *select_thread(void *arg) { // send the welcome message to client struct Welcome welcome; welcome.replyType = 2; - welcome.numStations = htons(NUM_STATIONS); - if ((send(newfd, &welcome, sizeof(struct Welcome), 0)) == -1) + welcome.numStations = htons(num_stations); + int numbytes; + if ((numbytes=send(newfd, &welcome, sizeof(struct Welcome), 0)) == -1) perror("send"); + + //print the num bytes + // print the size of the struct welcome + printf("size of welcome struct: %lu\n", sizeof(struct Welcome)); + printf("sent %d bytes\n", numbytes); } } else { // handle data from a client -- cgit v1.2.3-70-g09d2 From c36846a96fd45e57f37ce73e49af8275a305d4b4 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Tue, 19 Sep 2023 00:44:40 -0400 Subject: fix file descriptor leak --- c | Bin 35294 -> 35294 bytes l | Bin 34638 -> 34638 bytes l.dSYM/Contents/Resources/DWARF/l | Bin 11651 -> 11651 bytes listener.c | 1 - mp3/chipOffTheBlock.mp3 | Bin 0 -> 4477733 bytes s | Bin 55198 -> 55198 bytes s.dSYM/Contents/Resources/DWARF/s | Bin 23594 -> 23649 bytes snowcast_server_concurrent.c | 25 +++++++++++++++++-------- 8 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 mp3/chipOffTheBlock.mp3 diff --git a/c b/c index 35031be..20b2474 100755 Binary files a/c and b/c differ diff --git a/l b/l index 281f522..d6eec69 100755 Binary files a/l and b/l differ diff --git a/l.dSYM/Contents/Resources/DWARF/l b/l.dSYM/Contents/Resources/DWARF/l index c55216a..283ecc9 100644 Binary files a/l.dSYM/Contents/Resources/DWARF/l and b/l.dSYM/Contents/Resources/DWARF/l differ diff --git a/listener.c b/listener.c index d5b4799..7bb8afe 100644 --- a/listener.c +++ b/listener.c @@ -102,7 +102,6 @@ int main(int argc, char *argv[]) //printf("listener: packet contains \"%s\"\n", buf); // print the size - write(STDOUT_FILENO, buf, numbytes); memset(buf, 0, MAXBUFLEN); diff --git a/mp3/chipOffTheBlock.mp3 b/mp3/chipOffTheBlock.mp3 new file mode 100644 index 0000000..c06c05f Binary files /dev/null and b/mp3/chipOffTheBlock.mp3 differ diff --git a/s b/s index 10bc785..9f86c9b 100755 Binary files a/s and b/s differ diff --git a/s.dSYM/Contents/Resources/DWARF/s b/s.dSYM/Contents/Resources/DWARF/s index 4db3832..489e060 100644 Binary files a/s.dSYM/Contents/Resources/DWARF/s and b/s.dSYM/Contents/Resources/DWARF/s differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 3b71156..47b112a 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -240,8 +240,8 @@ void *send_udp_packet_routine(void *arg) { // get file path char* file_path = station_data[station_num].filePath; // get current seek chunk - int current_chunk = station_data[station_num].seekIndex; FILE* file_stream = fopen(file_path, "r"); + int current_chunk = station_data[station_num].seekIndex; if (fseek(file_stream, current_chunk, SEEK_SET) == -1) { perror("fseek"); return (NULL); @@ -253,6 +253,7 @@ void *send_udp_packet_routine(void *arg) { perror("fread"); return (NULL); } + fclose(file_stream); // printf("send data: thread %d \n", user_index); // int numbytes; // if ((numbytes = sendto(udp_sockfd, data, strlen(data), 0, @@ -273,7 +274,6 @@ void *send_udp_packet_routine(void *arg) { did_work = 1; - close(file_stream); usleep(400000); } @@ -507,16 +507,24 @@ void *init_user(int sockfd) { // this is to save memory space. // in general, the displacement of 4 is where a user "used to be" int user_index = max_active_users++; - if(user_data[(sockfd-4)/2].sockfd == -1) { - printf("reusing memory\n"); - user_index = (sockfd - 4)/2; - } else { - printf("making new memory\n"); - // have to make more memory + int running_index = 0; + while(running_index++ < max_active_users) + { + if (user_data[running_index].sockfd == -1) + { + user_index = running_index; + break; + } + // printf("reusing memory\n"); + } + // have to make more memory + if (user_index == max_active_users) { + ///printf("making new memory\n"); user_t *more_users = realloc(user_data, sizeof(user_t) * max_active_users); if (!more_users) { perror("realloc"); exit(1); } user_data = more_users; } + // map TCP sockfd to this user index user_data[user_index] = (user_t){-1, -1, sockfd, -1}; sockfd_to_user[sockfd] = user_index; @@ -585,4 +593,5 @@ void send_announce_message(int fd, int station_num) { printf("sent %d bytes\n", bytessent); free(send_buffer); + } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From d338a726a6ce2ede71c6887959ce0ef31a9e5d38 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Tue, 19 Sep 2023 10:06:15 -0400 Subject: update makefile --- Makefile | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index d48b036..064971c 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,23 @@ CC = gcc # CFLAGS = -std=c99 -target x86_64-apple-darwin20 -g CFLAGS = -g -I. -std=gnu99 -Wall -pthread +RM = rm -f default: all all: server client server: server.c - $(CC) $(CFLAGS) -o snowcast_server snowcast_server.c + $(CC) $(CFLAGS) -o snowcast_server snowcast_server_concurrent.c client: client.c $(CC) $(CFLAGS) -o snowcast_control client.c + $(CC) $(CFLAGS) -o snowcast_listener listener.c -new: - $(CC) $(CFLAGS) -o s snowcast_server_concurrent.c - $(CC) $(CFLAGS) -o l listener.c - $(CC) $(CFLAGS) -o c client.c \ No newline at end of file +# new: +# $(CC) $(CFLAGS) -o s snowcast_server_concurrent.c +# $(CC) $(CFLAGS) -o l listener.c +# $(CC) $(CFLAGS) -o c client.c + +clean: + $(RM) snowcast_server snowcast_control snowcast_listener \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 8ab91f9c3e206b4a97f4e96998e58447a6110174 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Tue, 19 Sep 2023 10:09:49 -0400 Subject: update MAKEFILE again --- Makefile | 5 +---- c | Bin 35294 -> 0 bytes client | Bin 34344 -> 0 bytes l | Bin 34638 -> 0 bytes s | Bin 55198 -> 0 bytes server | Bin 34616 -> 0 bytes snowcast_control | Bin 35309 -> 35309 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 13866 -> 13886 bytes snowcast_listener | Bin 0 -> 34654 bytes snowcast_listener.dSYM/Contents/Info.plist | 20 ++++++++++++++++++++ .../Contents/Resources/DWARF/snowcast_listener | Bin 0 -> 11651 bytes snowcast_server | Bin 35116 -> 55212 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 15573 -> 23649 bytes 13 files changed, 21 insertions(+), 4 deletions(-) delete mode 100755 c delete mode 100755 client delete mode 100755 l delete mode 100755 s delete mode 100755 server create mode 100755 snowcast_listener create mode 100644 snowcast_listener.dSYM/Contents/Info.plist create mode 100644 snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener diff --git a/Makefile b/Makefile index 064971c..a5f9ec9 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,6 @@ CC = gcc # CFLAGS = -std=c99 -target x86_64-apple-darwin20 -g CFLAGS = -g -I. -std=gnu99 -Wall -pthread -RM = rm -f - -default: all all: server client @@ -20,4 +17,4 @@ client: client.c # $(CC) $(CFLAGS) -o c client.c clean: - $(RM) snowcast_server snowcast_control snowcast_listener \ No newline at end of file + rm -fv snowcast_server snowcast_control snowcast_listener \ No newline at end of file diff --git a/c b/c deleted file mode 100755 index 20b2474..0000000 Binary files a/c and /dev/null differ diff --git a/client b/client deleted file mode 100755 index be376f0..0000000 Binary files a/client and /dev/null differ diff --git a/l b/l deleted file mode 100755 index d6eec69..0000000 Binary files a/l and /dev/null differ diff --git a/s b/s deleted file mode 100755 index 9f86c9b..0000000 Binary files a/s and /dev/null differ diff --git a/server b/server deleted file mode 100755 index 1ef6cd4..0000000 Binary files a/server and /dev/null differ diff --git a/snowcast_control b/snowcast_control index fa08142..cd01917 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index 774ea29..7406e42 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener new file mode 100755 index 0000000..1ed31fc Binary files /dev/null and b/snowcast_listener differ diff --git a/snowcast_listener.dSYM/Contents/Info.plist b/snowcast_listener.dSYM/Contents/Info.plist new file mode 100644 index 0000000..0af79e1 --- /dev/null +++ b/snowcast_listener.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.snowcast_listener + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener b/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener new file mode 100644 index 0000000..b6206fa Binary files /dev/null and b/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index c194134..cf52441 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 0123b4a..779877b 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 80229ddf87ca847fa73420187b3db19c500957de Mon Sep 17 00:00:00 2001 From: sotech117 Date: Tue, 19 Sep 2023 10:17:42 -0400 Subject: start broadcasting right away --- snowcast_control | Bin 35309 -> 21328 bytes snowcast_listener | Bin 34654 -> 19128 bytes snowcast_server | Bin 55212 -> 37208 bytes snowcast_server_concurrent.c | 7 ++++--- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/snowcast_control b/snowcast_control index cd01917..0d1ee4f 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 1ed31fc..9f75571 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index cf52441..d9c7013 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 47b112a..d0e6aa5 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -112,6 +112,10 @@ int main(int argc, char *argv[]) pthread_t s_thread; pthread_create(&s_thread, NULL, select_thread, NULL); + // start syncchronization thread to broadcast stations + pthread_t sync_thread; +pthread_create(&sync_thread, NULL, synchronization_thread, NULL); + // command line interface char input[LINE_MAX]; while (1) { @@ -129,9 +133,6 @@ int main(int argc, char *argv[]) print_user_data(i); } } else if (strncmp("s\n", input, LINE_MAX) == 0) { - // start the streaming threads - pthread_t sync_thread; - pthread_create(&sync_thread, NULL, synchronization_thread, NULL); } } -- cgit v1.2.3-70-g09d2 From 5eb24f6063515e86e3e87e6fb91e6672dc14de34 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Tue, 19 Sep 2023 22:55:08 -0400 Subject: make file testing --- snowcast_control | Bin 21328 -> 35309 bytes snowcast_listener | Bin 19128 -> 34654 bytes snowcast_server | Bin 37208 -> 55212 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 23649 -> 23632 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/snowcast_control b/snowcast_control index 0d1ee4f..56af544 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 9f75571..de66f23 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index d9c7013..78be793 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 779877b..d27ad67 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 1263cbdbb6cf3ebbb157286b2bb2e488e4b931c8 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 04:04:22 +0000 Subject: fix handshake protocol --- Makefile | 4 +- broadcast.c | 67 ------ client.c | 27 ++- htable.c | 78 ------- htable.h | 45 ---- list.h | 137 ------------ server.c | 153 -------------- snowcast_control | Bin 35309 -> 21440 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 13886 -> 13854 bytes snowcast_listener | Bin 34654 -> 19128 bytes snowcast_server | Bin 55212 -> 37128 bytes snowcast_server.c | 234 --------------------- .../Contents/Resources/DWARF/snowcast_server | Bin 23632 -> 23723 bytes snowcast_server_concurrent.c | 57 +++-- talker.c | 67 ------ test | Bin 52753 -> 0 bytes 16 files changed, 49 insertions(+), 820 deletions(-) delete mode 100644 broadcast.c delete mode 100644 htable.c delete mode 100644 htable.h delete mode 100644 list.h delete mode 100644 server.c delete mode 100644 snowcast_server.c delete mode 100644 talker.c delete mode 100755 test diff --git a/Makefile b/Makefile index a5f9ec9..277de9a 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,10 @@ CFLAGS = -g -I. -std=gnu99 -Wall -pthread all: server client -server: server.c +server: $(CC) $(CFLAGS) -o snowcast_server snowcast_server_concurrent.c -client: client.c +client: $(CC) $(CFLAGS) -o snowcast_control client.c $(CC) $(CFLAGS) -o snowcast_listener listener.c diff --git a/broadcast.c b/broadcast.c deleted file mode 100644 index b10e633..0000000 --- a/broadcast.c +++ /dev/null @@ -1,67 +0,0 @@ -/* -** broadcaster.c -- a datagram "client" like talker.c, except -** this one can broadcast -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SERVERPORT 4950 // the port users will be connecting to - -int main(int argc, char *argv[]) -{ - int sockfd; - struct sockaddr_in their_addr; // connector's address information - struct hostent *he; - int numbytes; - int broadcast = 1; - //char broadcast = '1'; // if that doesn't work, try this - - if (argc != 3) { - fprintf(stderr,"usage: broadcaster hostname message\n"); - exit(1); - } - - if ((he=gethostbyname(argv[1])) == NULL) { // get the host info - perror("gethostbyname"); - exit(1); - } - - if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - perror("socket"); - exit(1); - } - - // this call is what allows broadcast packets to be sent: - if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, - sizeof broadcast) == -1) { - perror("setsockopt (SO_BROADCAST)"); - exit(1); - } - - their_addr.sin_family = AF_INET; // host byte order - their_addr.sin_port = htons(SERVERPORT); // short, network byte order - their_addr.sin_addr = *((struct in_addr *)he->h_addr); - memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero); - - if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0, - (struct sockaddr *)&their_addr, sizeof their_addr)) == -1) { - perror("sendto"); - exit(1); - } - - printf("sent %d bytes to %s\n", numbytes, - inet_ntoa(their_addr.sin_addr)); - - close(sockfd); - - return 0; -} \ No newline at end of file diff --git a/client.c b/client.c index ecb0be9..a989919 100644 --- a/client.c +++ b/client.c @@ -88,15 +88,11 @@ int main(int argc, char *argv[]) freeaddrinfo(servinfo); // all done with this structure - struct Welcome msg; - // recv the message, check for errors too - if ((recvbytes = recv(sockfd, (char*)&msg, sizeof(struct Welcome), 0)) == -1) { - perror("recv"); - exit(1); - } - msg.numStations = ntohs(msg.numStations); - printf("Welcome to Snowcast! The server has %d stations.\n", msg.numStations); - + pthread_t reply_thread; + pthread_create(&reply_thread, NULL, reply_thread_routine, (void*)sockfd); + + usleep(1000); + struct Hello hello; hello.commandType = 0; // convert updPort to an int @@ -106,11 +102,6 @@ int main(int argc, char *argv[]) perror("send"); exit(1); } - // print the amount of bytes sent - printf("client: sent %d bytes on a hello call \n", numbytessent); - - pthread_t reply_thread; - pthread_create(&reply_thread, NULL, reply_thread_routine, (void*)sockfd); char input[LINE_MAX]; printf("Enter a number to change to it's station. Click q to end stream.\n"); @@ -166,6 +157,14 @@ void *reply_thread_routine(void* args) { // print out the fields of reply on one line printf("\nclient: replyType: %d, stringSize: %d\n", reply.replyType, reply.stringSize); + if (reply.replyType == 2) { + struct Welcome msg; + // recv the message, check for errors too + memcpy(&msg, buf, sizeof(struct Welcome)); + msg.numStations = ntohs(msg.numStations); + printf("Welcome to Snowcast! The server has %d stations.\n", msg.numStations); + } + // print the size of reply if (reply.replyType == 3) { printf("client: received an announce message\n"); diff --git a/htable.c b/htable.c deleted file mode 100644 index a39c3c6..0000000 --- a/htable.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include -#include - -#include "htable.h" - -static htable_node_t *__htable_lookup( htable_t *ht, unsigned int id ); - -void htable_init( htable_t *ht, unsigned int cap ) { - unsigned int i; - - ht->ht_hash = (list_t*) malloc( sizeof( list_t ) * cap ); - ht->ht_cap = cap; - ht->ht_size = 0; - - for( i = 0; i < cap; i++ ) - list_init( &ht->ht_hash[ i ] ); -} - -void htable_destroy( htable_t *ht ) { - unsigned int i; - htable_node_t *hn; - - for( i = 0; i < ht->ht_cap; i++ ) { - list_iterate_begin( &ht->ht_hash[ i ], hn, htable_node_t, hn_link ) { - free( hn ); - } list_iterate_end(); - } - - free( ht->ht_hash ); -} - -void *htable_get( htable_t *ht, unsigned int id ) { - htable_node_t *hn; - - if( ( hn = __htable_lookup( ht, id ) ) ) return hn->hn_data; - else return NULL; -} - -void *htable_put( htable_t *ht, unsigned int id, void *data ) { - htable_node_t *hn; - void *old = NULL; - - if( !( hn = __htable_lookup( ht, id ) ) ) { - hn = (htable_node_t*) malloc( sizeof( htable_node_t ) ); - hn->hn_id = id; - list_insert_head( &ht->ht_hash[ id % ht->ht_cap ], &hn->hn_link ); - ht->ht_size++; - } else old = hn->hn_data; - - hn->hn_data = data; - - return old; -} - -void *htable_remove( htable_t *ht, unsigned int id ) { - htable_node_t *hn; - - if( ( hn = __htable_lookup( ht, id ) ) ) { - void *data = hn->hn_data; - list_remove( &hn->hn_link ); - free( hn ); - ht->ht_size--; - return data; - } else return NULL; -} - -htable_node_t *__htable_lookup( htable_t *ht, unsigned int id ) { - htable_node_t *hn; - - list_iterate_begin( &ht->ht_hash[ id % ht->ht_cap ], hn, htable_node_t, hn_link ) { - if( hn->hn_id == id ) return hn; - } list_iterate_end(); - - return NULL; -} \ No newline at end of file diff --git a/htable.h b/htable.h deleted file mode 100644 index 65eac58..0000000 --- a/htable.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __HASHTABLE_H__ -#define __HASHTABLE_H__ - -#include - -#include "list.h" - -/* FIXME make this a doubly-hashed, dynamically groweable hashtable */ - -typedef struct htable { - list_t *ht_hash; /* table entries */ - unsigned int ht_size; /* table size */ - unsigned int ht_cap; /* table capacity */ -} htable_t; - -typedef struct htable_node { - list_t hn_link; /* link */ - unsigned int hn_id; /* hash id */ - void *hn_data; /* data */ -} htable_node_t; - -void htable_init( htable_t *ht, unsigned int cap ); -void htable_destroy( htable_t *ht ); -void *htable_get( htable_t *ht, unsigned int id ); -void *htable_put( htable_t *ht, unsigned int id, void *data ); -void *htable_remove( htable_t *ht, unsigned int id ); - -#define htable_iterate_begin( ht, key, var, type ) \ -do { \ - unsigned int ___i; \ - htable_t *__ht = (ht); \ - htable_node_t *__hnode; \ - for(___i = 0;___i < __ht->ht_cap;___i++ ) { \ - list_iterate_begin( &__ht->ht_hash[___i ], __hnode, htable_node_t, hn_link ) { \ - (var) = (type*) __hnode->hn_data; \ - (key) = __hnode->hn_id; \ - do - -#define htable_iterate_end() \ - while( 0 ); \ - } list_iterate_end(); \ - } \ -} while( 0 ) - -#endif /* __HASHTABLE_H__ */ \ No newline at end of file diff --git a/list.h b/list.h deleted file mode 100644 index 03fcdc5..0000000 --- a/list.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef __LIST_H__ -#define __LIST_H__ - -#include - -/* -** Generic circular doubly linked list implementation. -** -** list_t is the head of the list. -** list_link_t should be included in structures which want to be -** linked on a list_t. -** -** All of the list functions take pointers to list_t and list_link_t -** types, unless otherwise specified. -** -** list_init(list) initializes a list_t to an empty list. -** -** list_empty(list) returns 1 iff the list is empty. -** -** Insertion functions. -** list_insert_head(list, link) inserts at the front of the list. -** list_insert_tail(list, link) inserts at the end of the list. -** list_insert_before(olink, nlink) inserts nlink before olink in list. -** -** Removal functions. -** Head is list->l_next. Tail is list->l_prev. -** The following functions should only be called on non-empty lists. -** list_remove(link) removes a specific element from the list. -** list_remove_head(list) removes the first element. -** list_remove_tail(list) removes the last element. -** -** Item accessors. -** list_item(link, type, member) given a list_link_t* and the name -** of the type of structure which contains the list_link_t and -** the name of the member corresponding to the list_link_t, -** returns a pointer (of type "type*") to the item. -** -** To iterate over a list, -** -** list_link_t *link; -** for (link = list->l_next; -** link != list; link = link->l_next) -** ... -** -** Or, use the macros, which will work even if you list_remove() the -** current link: -** -** type iterator; -** list_iterate_begin(list, iterator, type, member) { -** ... use iterator ... -** } list_iterate_end; -*/ - -typedef struct llist { - struct llist *l_next; - struct llist *l_prev; -} list_t, list_link_t; - -#define list_init(list) \ - (list)->l_next = (list)->l_prev = (list); - -#define list_link_init(link) \ - (link)->l_next = (link)->l_prev = NULL; - -#define list_empty(list) \ - ((list)->l_next == (list)) - -#define list_insert_before(old, new) \ - do { \ - list_link_t *prev = (new); \ - list_link_t *next = (old); \ - prev->l_next = next; \ - prev->l_prev = next->l_prev; \ - next->l_prev->l_next = prev; \ - next->l_prev = prev; \ - } while(0) - -#define list_insert_head(list, link) \ - list_insert_before((list)->l_next, link) - -#define list_insert_tail(list, link) \ - list_insert_before(list, link) - -#define list_remove(link) \ - do { \ - list_link_t *ll = (link); \ - list_link_t *prev = ll->l_prev; \ - list_link_t *next = ll->l_next; \ - prev->l_next = next; \ - next->l_prev = prev; \ - ll->l_next = ll->l_prev = 0; \ - } while(0) - -#define list_remove_head(list) \ - list_remove((list)->l_next) - -#define list_remove_tail(list) \ - list_remove((list)->l_prev) - -#define list_item(link, type, member) \ - (type*)((char*)(link) - offsetof(type, member)) - -#define list_head(list, type, member) \ - list_item((list)->l_next, type, member) - -#define list_tail(list, type, member) \ - list_item((list)->l_prev, type, member) - -#define list_iterate_begin(list, var, type, member) \ - do { \ - list_link_t *__link; \ - list_link_t *__next; \ - for (__link = (list)->l_next; \ - __link != (list); \ - __link = __next) { \ - var = list_item(__link, type, member); \ - __next = __link->l_next; - -#define list_iterate_end() \ - } \ - } while(0) - -#define list_iterate_reverse_begin(list, var, type, member) \ - do { \ - list_link_t *__link; \ - list_link_t *__prev; \ - for (__link = (list)->l_prev; \ - __link != (list); \ - __link = __prev) { \ - var = list_item(__link, type, member); \ - __prev = __link->l_prev; - -#define list_iterate_reverse_end() \ - } \ - } while(0) - -#endif /* __LIST_H__ */ \ No newline at end of file diff --git a/server.c b/server.c deleted file mode 100644 index be9f603..0000000 --- a/server.c +++ /dev/null @@ -1,153 +0,0 @@ -/* -** server.c -- a stream socket server demo -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "protocol.h" - -#define BACKLOG 10 // how many pending connections queue will hold - -#define MAXDATASIZE 100 // max number of bytes we can get at once - - -void sigchld_handler(int s) -{ - // waitpid() might overwrite errno, so we save and restore it: - int saved_errno = errno; - - while(waitpid(-1, NULL, WNOHANG) > 0); - - errno = saved_errno; -} - - -// get sockaddr, IPv4 or IPv6: -void *get_in_addr(struct sockaddr *sa) -{ - if (sa->sa_family == AF_INET) { - return &(((struct sockaddr_in*)sa)->sin_addr); - } - - return &(((struct sockaddr_in6*)sa)->sin6_addr); -} - -int main(int argc, char *argv[]) -{ - int sockfd, new_fd, numbytes, b; // listen on sock_fd, new connection on new_fd - char buf[MAXDATASIZE]; - struct addrinfo hints, *servinfo, *p; - struct sockaddr_storage their_addr; // connector's address information - socklen_t sin_size; - struct sigaction sa; - int yes=1; - char s[INET6_ADDRSTRLEN]; - int rv; - - if (argc < 3) { - fprintf(stderr,"usage: [file 1] [file 2] ... \n"); - exit(1); - } - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; // only IPv4 - hints.ai_socktype = SOCK_STREAM; // TCP connection - hints.ai_flags = AI_PASSIVE; // use my IP - - const char* port = argv[1]; // the port users will be connecting to - - if ((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); - return 1; - } - - // loop through all the results and bind to the first we can - for(p = servinfo; p != NULL; p = p->ai_next) { - if ((sockfd = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) { - perror("server: socket"); - continue; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, - sizeof(int)) == -1) { - perror("setsockopt"); - exit(1); - } - - if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { - close(sockfd); - perror("server: bind"); - continue; - } - - break; - } - - freeaddrinfo(servinfo); // all done with this structure - - if (p == NULL) { - fprintf(stderr, "server: failed to bind\n"); - exit(1); - } - - if (listen(sockfd, BACKLOG) == -1) { - perror("listen"); - exit(1); - } - - sa.sa_handler = sigchld_handler; // reap all dead processes - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - if (sigaction(SIGCHLD, &sa, NULL) == -1) { - perror("sigaction"); - exit(1); - } - - printf("server: waiting for connections...\n"); - - - - while(1) { // main accept() loop - sin_size = sizeof their_addr; - new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); - if (new_fd == -1) { - perror("accept"); - continue; - } - - inet_ntop(their_addr.ss_family, - get_in_addr((struct sockaddr *)&their_addr), - s, sizeof s); - printf("server: got connection from %s\n", s); - - if (!fork()) { // this is the child process - - close(sockfd); // child doesn't need the listener - - // make a struct for the message, number is the number of stations - struct Welcome welcome; - welcome.replyType = 2; - welcome.numStations = htons(argc - 2); - if ((send(new_fd, &welcome, sizeof(struct Welcome), 0)) == -1) - perror("send"); - close(new_fd); - exit(0); - } - // close(new_fd); // parent doesn't need this - } - - return 0; -} \ No newline at end of file diff --git a/snowcast_control b/snowcast_control index 56af544..711e770 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index 7406e42..4cd75ec 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index de66f23..9f75571 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 78be793..8ef32a4 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.c b/snowcast_server.c deleted file mode 100644 index 6043157..0000000 --- a/snowcast_server.c +++ /dev/null @@ -1,234 +0,0 @@ -/* -** server.c -- a stream socket server demo -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "protocol.h" - -// get sockaddr, IPv4 or IPv6: -void *get_in_addr(struct sockaddr *sa) -{ - if (sa->sa_family == AF_INET) { - return &(((struct sockaddr_in*)sa)->sin_addr); - } - - return &(((struct sockaddr_in6*)sa)->sin6_addr); -} - -int main(int argc, char *argv[]) -{ - fd_set master; // master file descriptor list - fd_set read_fds; // temp file descriptor list for select() - int fdmax; // maximum file descriptor number - - int listener; // listening socket descriptor - int newfd; // newly accept()ed socket descriptor - struct sockaddr_storage remoteaddr; // client address - socklen_t addrlen; - - char buf[256]; // buffer for client data - int nbytes; - - char remoteIP[INET6_ADDRSTRLEN]; - - int yes=1; // for setsockopt() SO_REUSEADDR, below - int i, j, rv; - - struct addrinfo hints, *ai, *p; - - // check and assign arguments - if (argc < 3) { - fprintf(stderr,"usage: [file 1] [file 2] ... \n"); - exit(1); - } - - const char* port = argv[1]; - - FD_ZERO(&master); // clear the master and temp sets - FD_ZERO(&read_fds); - - // LISTENER: get us a socket and bind it - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) { - fprintf(stderr, "snowcast_server: %s\n", gai_strerror(rv)); - exit(1); - } - - for(p = ai; p != NULL; p = p->ai_next) { - listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (listener < 0) { - continue; - } - - // lose the pesky "address already in use" error message - setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); - - if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) { - close(listener); - continue; - } - - break; - } - - // if we got here, it means we didn't get bound - if (p == NULL) { - fprintf(stderr, "snowcast_server: failed to bind\n"); - exit(2); - } - - freeaddrinfo(ai); // all done with this - - // listen - if (listen(listener, 10) == -1) { - perror("listen"); - exit(3); - } - - // add the listener to the master set - FD_SET(listener, &master); - - // keep track of the biggest file descriptor - fdmax = listener; // so far, it's this one - - // main loop - while(1==1) { - read_fds = master; // copy it - if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { - perror("select"); - exit(4); - } - - // run through the existing connections looking for data to read - for(i = 0; i <= fdmax; i++) { - if (FD_ISSET(i, &read_fds)) { // we got one!! - if (i == listener) { - // handle new connections - addrlen = sizeof remoteaddr; - newfd = accept(listener, - (struct sockaddr *)&remoteaddr, - &addrlen); - - if (newfd == -1) { - perror("accept"); - } else { - FD_SET(newfd, &master); // add to master set - if (newfd > fdmax) { // keep track of the max - fdmax = newfd; - } - printf("selectserver: new connection from %s on " - "socket %d\n.", - inet_ntop(remoteaddr.ss_family, - get_in_addr((struct sockaddr*)&remoteaddr), - remoteIP, INET6_ADDRSTRLEN), - newfd); - - // send the welcome message to client - struct Welcome welcome; - welcome.replyType = 2; - welcome.numStations = htons(argc - 2); - if ((send(newfd, &welcome, sizeof(struct Welcome), 0)) == -1) - perror("send"); - } - } else { - // handle data from a client - struct Command command; - if ((nbytes = recv(i, (char*)&command, sizeof(struct Command), 0)) <= 0) { - // got error or connection closed by client - if (nbytes == 0) { - // connection closed - printf("selectserver: socket %d hung up\n", i); - } else { - perror("recv"); - } - close(i); // bye! - FD_CLR(i, &master); // remove from master set - } else { - // we got some data from a client - if (command.commandType == 0) { - // hello message with udpPort - printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); - - // TALKER: get us a udp socket and bind it - struct addrinfo hintsUdp, *servinfoUdp, *pUdp; - int rvUdp, sockfdUdp, numbytesUdp; - memset(&hintsUdp, 0, sizeof hintsUdp); - hintsUdp.ai_family = AF_INET; // IPv4 - hintsUdp.ai_socktype = SOCK_DGRAM; // UDP - if ((rvUdp = getaddrinfo(argv[1], command.number, &hints, &servinfoUdp)) != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rvUdp)); - return 1; - } - - // loop through all the results and make a socket - for(p = servinfoUdp; p != NULL; p = p->ai_next) { - if ((sockfdUdp = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) { - perror("talker: socket"); - continue; - } - break; - } - - if (p == NULL) { - fprintf(stderr, "talker: failed to create socket\n"); - return 2; - } - - - if ((numbytesUdp = sendto(sockfdUdp, "test", strlen("test"), 0, - p->ai_addr, p->ai_addrlen)) == -1) { - perror("talker: sendto"); - exit(1); - } - - freeaddrinfo(servinfoUdp); - - printf("talker: sent %d bytes to %d\n", numbytesUdp, sockfdUdp); - // close(sockfdUdp); - } - if (command.commandType == 1) { - // setStation command for the user - printf("TODO: set station to %d\n", ntohs(command.number)); - } - else { - // send back in invalid command - struct InvalidCommand invalid; - invalid.replyType = 4; - invalid.replyStringSize = 21; - // make a string with the command.commmandType type in it - invalid.replyString = "Invalid command type"; - if ((send(i, &invalid, sizeof(struct InvalidCommand), 0)) == -1) - perror("send"); - - // drop connection upon invalid command - close(i); - FD_CLR(i, &master); - } - } - } // END handle data from client - } // END got new incoming connection - } // END looping through file descriptors - - // broadcast the new files over the udp socket list for each use - - } // END for(;;)--and you thought it would never end! - - return 0; -} \ No newline at end of file diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index d27ad67..a3f5493 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index d0e6aa5..d855bab 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) // start syncchronization thread to broadcast stations pthread_t sync_thread; -pthread_create(&sync_thread, NULL, synchronization_thread, NULL); + pthread_create(&sync_thread, NULL, synchronization_thread, NULL); // command line interface char input[LINE_MAX]; @@ -307,6 +307,7 @@ void *synchronization_thread(void *arg) { FILE* fp = fopen(station_data[i].filePath, "r"); fseek(fp, 0L, SEEK_END); size_t size = ftell(fp); + fclose(fp); if (size == -1) { perror("ftell"); return (NULL); @@ -315,10 +316,25 @@ void *synchronization_thread(void *arg) { // if the seek index is greater than the size of the file, reset it if (station_data[i].seekIndex >= size) { - // printf("resetting seek index for station %d\n", i); station_data[i].seekIndex = 0; + + + // send the announce messages + for (int i = 0; i < max_active_users; i++) + { + // if (user_data[i].streamThread == NULL) { + // break; + // } + if (user_data[i].sockfd == -1) + continue; + // print_user_data(i); + // update the station of each user + if (user_data[i].stationNum == i) + { + send_announce_message(user_data[i].sockfd, i); + } + } } - fclose(fp); } @@ -424,27 +440,14 @@ void *select_thread(void *arg) { if (newfd > fdmax) { // keep track of the max fdmax = newfd; } - printf("selectserver: new connection from %s on " - "socket %d\n.", - inet_ntop(remoteaddr.ss_family, - get_in_addr((struct sockaddr*)&remoteaddr), - remoteIP, INET6_ADDRSTRLEN), - newfd); + // printf("selectserver: new connection from %s on " + // "socket %d\n.", + // inet_ntop(remoteaddr.ss_family, + // get_in_addr((struct sockaddr*)&remoteaddr), + // remoteIP, INET6_ADDRSTRLEN), + // newfd); // init user with this newfd init_user(newfd); - - // send the welcome message to client - struct Welcome welcome; - welcome.replyType = 2; - welcome.numStations = htons(num_stations); - int numbytes; - if ((numbytes=send(newfd, &welcome, sizeof(struct Welcome), 0)) == -1) - perror("send"); - - //print the num bytes - // print the size of the struct welcome - printf("size of welcome struct: %lu\n", sizeof(struct Welcome)); - printf("sent %d bytes\n", numbytes); } } else { // handle data from a client @@ -468,6 +471,14 @@ void *select_thread(void *arg) { printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); // update udp port of user update_user_udpPort(i, ntohs(command.number)); + + // send the welcome message to client + struct Welcome welcome; + welcome.replyType = 2; + welcome.numStations = htons(num_stations); + int numbytes; + if ((numbytes=send(i, &welcome, sizeof(struct Welcome), 0)) == -1) + perror("send"); } else if (command.commandType == 1) { int station_num = ntohs(command.number); @@ -490,6 +501,7 @@ void *select_thread(void *arg) { // drop connection upon invalid command close(i); FD_CLR(i, &master); + destroy_user(i); } } } // END handle data from client @@ -594,5 +606,4 @@ void send_announce_message(int fd, int station_num) { printf("sent %d bytes\n", bytessent); free(send_buffer); - } \ No newline at end of file diff --git a/talker.c b/talker.c deleted file mode 100644 index bb801e5..0000000 --- a/talker.c +++ /dev/null @@ -1,67 +0,0 @@ -/* -** talker.c -- a datagram "client" demo -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SERVERPORT "4950" // the port users will be connecting to - -int main(int argc, char *argv[]) -{ - int sockfd; - struct addrinfo hints, *servinfo, *p; - int rv; - int numbytes; - - if (argc != 3) { - fprintf(stderr,"usage: talker hostname message\n"); - exit(1); - } - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET6; // set to AF_INET to use IPv4 - hints.ai_socktype = SOCK_DGRAM; - - if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); - return 1; - } - - // loop through all the results and make a socket - for(p = servinfo; p != NULL; p = p->ai_next) { - if ((sockfd = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) { - perror("talker: socket"); - continue; - } - - break; - } - - if (p == NULL) { - fprintf(stderr, "talker: failed to create socket\n"); - return 2; - } - - if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, - p->ai_addr, p->ai_addrlen)) == -1) { - perror("talker: sendto"); - exit(1); - } - - freeaddrinfo(servinfo); - - printf("talker: sent %d bytes to %s\n", numbytes, argv[1]); - close(sockfd); - - return 0; -} \ No newline at end of file diff --git a/test b/test deleted file mode 100755 index a576c5e..0000000 Binary files a/test and /dev/null differ -- cgit v1.2.3-70-g09d2 From ea7aff51be44884e22c8bdabef917c77c291951e Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 01:19:39 -0400 Subject: add better command line interface to server repl. also, add the print function that can go to file. --- client.c | 12 +-- snowcast_control | Bin 21440 -> 35357 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 13854 -> 13773 bytes snowcast_listener | Bin 19128 -> 34654 bytes snowcast_server | Bin 37128 -> 55724 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 23723 -> 25277 bytes snowcast_server_concurrent.c | 117 +++++++++++++++++++-- 7 files changed, 114 insertions(+), 15 deletions(-) diff --git a/client.c b/client.c index a989919..df5ea9b 100644 --- a/client.c +++ b/client.c @@ -144,9 +144,9 @@ void *reply_thread_routine(void* args) { exit(1); } buf[recvbytes] = '\0'; - printf("client: received %d bytes on a reply call \n", recvbytes); + // printf("client: received %d bytes on a reply call \n", recvbytes); // print the two first field of the call - printf("client: replyType: %d, stringSize: %d\n", buf[0], buf[1]); + // printf("client: replyType: %d, stringSize: %d\n", buf[0], buf[1]); // print the while buffer by char for (int i = 0; i < recvbytes; i++) { printf("%c ", buf[i]); @@ -155,8 +155,8 @@ void *reply_thread_routine(void* args) { memcpy(&reply, buf, 2); // print out the fields of reply on one line - printf("\nclient: replyType: %d, stringSize: %d\n", reply.replyType, reply.stringSize); - + // printf("\nclient: replyType: %d, stringSize: %d\n", reply.replyType, reply.stringSize); + if (reply.replyType == 2) { struct Welcome msg; // recv the message, check for errors too @@ -167,13 +167,13 @@ void *reply_thread_routine(void* args) { // print the size of reply if (reply.replyType == 3) { - printf("client: received an announce message\n"); + // printf("client: received an announce message\n"); char *song_name = malloc(reply.stringSize); // printf(sizeof(struct Reply)); memcpy(song_name, buf + 2, reply.stringSize); - printf("client: song name: %s\n", song_name); + printf("New song announced: %s\n", song_name); free(song_name); diff --git a/snowcast_control b/snowcast_control index 711e770..ad92c5e 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index 4cd75ec..9af43c5 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 9f75571..9796cb9 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 8ef32a4..1c3a8fb 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index a3f5493..a4a9da5 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index d855bab..2c74cab 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -8,6 +8,9 @@ #include #include +#include +#include + #include "protocol.h" #define LINE_MAX 1024 @@ -53,6 +56,9 @@ void *send_udp_packet_routine(void* arg); void *select_thread(void* arg); void *synchronization_thread(void* arg); +int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]); +void *print_info_routine(void *arg); + void *get_in_addr(struct sockaddr *sa); void *init_user(int sockfd); @@ -118,27 +124,105 @@ int main(int argc, char *argv[]) // command line interface char input[LINE_MAX]; - while (1) { - char *line = fgets(input, LINE_MAX, stdin); + memset(input, 0, LINE_MAX); - if (line == NULL) { + char *tokens[LINE_MAX / 2]; + while (read(STDIN_FILENO, input, LINE_MAX) > 0) { + // init tokens + memset(tokens, 0, (LINE_MAX / 2) * sizeof(char *)); + + // if 0, all whitespace + if (!parse(input, tokens)) continue; - } else if (strncmp("q\n", input, LINE_MAX) == 0) { - // end code if type in q + + char *command = tokens[0]; + // if q, shutdown! + if (!strcmp(command, "q")) { printf("Exiting.\n"); + // TODO: exit better than break break; - } else if (strncmp("p\n", input, LINE_MAX) == 0) { + } + + // if p, print info + else if (!strcmp(command, "p")) { + // get the file descriptor + int print_fd = 0; + // see if there is a file path + char *output_file_path = tokens[1]; + if (output_file_path != NULL) + { + if ((print_fd = open(output_file_path, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU)) == -1) + { + perror("open"); + continue; + } + } else { + print_fd = STDOUT_FILENO; + } + printf("print_fd: %d\n", print_fd); + pthread_t print_info_thread; + pthread_create(&print_info_thread, NULL, print_info_routine, print_fd); + // note - this file descriptor is closed in the thread + } + else if (strncmp("u\n", input, LINE_MAX) == 0) + { // print all user data - for (int i = 0; i < max_active_users; i++) { + for (int i = 0; i < max_active_users; i++) + { print_user_data(i); } - } else if (strncmp("s\n", input, LINE_MAX) == 0) { } } return 0; } +void write_int_to_fd(int fd, int n) { + int l = snprintf(NULL, 0, "%d", n); + char *num = malloc(l + 1); + if (!num) { perror("malloc"); return; } + + snprintf(num, l + 1, "%d", n); + if (write(fd, num, strlen(num)) == -1) { + perror("write"); + } + + + free(num); +} + +void *print_info_routine(void *arg) { + int print_fd = (int) arg; + // printf("thread print_fd: %d\n", print_fd); + // printf("num_stations: %d\n", num_stations); + for (int i = 0; i < num_stations; i++) { + write_int_to_fd(print_fd, i); + char *comma = ","; + write(print_fd, comma, strlen(comma)); + + // write file path + char* file_path = station_data[i].filePath; + write(print_fd, file_path, strlen(file_path)); + + for (int j = 0; j < max_active_users; j++) { + if (user_data[j].sockfd == -1) + continue; + if (user_data[j].stationNum == i) { + char *localhost_ip = ",127.0.0.1:"; + write(print_fd, localhost_ip, strlen(localhost_ip)); + // write udpPort + write_int_to_fd(print_fd, user_data[j].udpPort); + } + } + // wrtie new line + char *newline = "\n"; + write(print_fd, newline, strlen(newline)); + } + + if (print_fd != STDOUT_FILENO) close(print_fd); + return (NULL); +} + int sendall(int udp_sockfd, char *buf, int *len, struct addrinfo *thread_res) { int MAX_PACKET_SIZE = 512; @@ -606,4 +690,19 @@ void send_announce_message(int fd, int station_num) { printf("sent %d bytes\n", bytessent); free(send_buffer); -} \ No newline at end of file +} + + +// Parses a buffer into tokens, from cs33 :) +int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]) { + const char *regex = " \n\t\f\r"; + char *current_token = strtok(buffer, regex); + if (current_token == NULL) return 0; + + for (int i = 0; current_token != NULL; i++) { + tokens[i] = current_token; + current_token = strtok(NULL, regex); + } + + return 1; +} -- cgit v1.2.3-70-g09d2 From af44220248c7da4c2f66f5bd7ff018acfe623b03 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 01:36:52 -0400 Subject: add code to send invalid messages --- out.txt | 2 + snowcast_control | Bin 35357 -> 35357 bytes snowcast_listener | Bin 34654 -> 34654 bytes snowcast_server | Bin 55724 -> 55852 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 25277 -> 25674 bytes snowcast_server_concurrent.c | 66 ++++++++++++++++----- 6 files changed, 53 insertions(+), 15 deletions(-) create mode 100755 out.txt diff --git a/out.txt b/out.txt new file mode 100755 index 0000000..bb302e4 --- /dev/null +++ b/out.txt @@ -0,0 +1,2 @@ +0,mp3/ManchurianCandidates-Breakin.mp3,127.0.0.1:12345,127.0.0.1:12346 +1,mp3/VanillaIce-IceIceBaby.mp3 diff --git a/snowcast_control b/snowcast_control index ad92c5e..29c20b9 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 9796cb9..2a44805 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 1c3a8fb..c59486d 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index a4a9da5..e65a61d 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 2c74cab..4fa6d40 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -67,7 +67,8 @@ void *update_user_station(int sockfd, int stationNum); void *print_user_data(int sockfd); void destroy_user(int sockfd); -void send_announce_message(int fd, int station_num); +void send_announce_reply(int fd, int station_num); +void send_invalid_command_reply(int fd, size_t message_size, char* message); // void *load_file(void* arg); @@ -164,7 +165,7 @@ int main(int argc, char *argv[]) pthread_create(&print_info_thread, NULL, print_info_routine, print_fd); // note - this file descriptor is closed in the thread } - else if (strncmp("u\n", input, LINE_MAX) == 0) + else if (!strcmp(command, "u")) { // print all user data for (int i = 0; i < max_active_users; i++) @@ -415,7 +416,7 @@ void *synchronization_thread(void *arg) { // update the station of each user if (user_data[i].stationNum == i) { - send_announce_message(user_data[i].sockfd, i); + send_announce_reply(user_data[i].sockfd, i); } } } @@ -552,7 +553,7 @@ void *select_thread(void *arg) { // we got some data from a client if (command.commandType == 0) { // hello message with udpPort - printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); + // printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); // update udp port of user update_user_udpPort(i, ntohs(command.number)); @@ -565,22 +566,37 @@ void *select_thread(void *arg) { perror("send"); } else if (command.commandType == 1) { + // check if user has a udpPort + if (user_data[sockfd_to_user[i]].udpPort == -1) { + // send back in invalid command + char * message = "Must send Hello message first"; + send_invalid_command_reply(i, strlen(message), message); + // drop connection upon invalid command + close(i); + FD_CLR(i, &master); + destroy_user(i); + } + int station_num = ntohs(command.number); - printf("setting station to %d\n", ntohs(command.number)); + if (station_num >= num_stations || station_num < 0) { + // send back in invalid command + char * message = "Station number out of range"; + send_invalid_command_reply(i, strlen(message), message); + // drop connection upon invalid command + close(i); + FD_CLR(i, &master); + destroy_user(i); + } + + // printf("setting station to %d\n", ntohs(command.number)); // update station of user update_user_station(i, ntohs(command.number)); - - send_announce_message(i, station_num); + send_announce_reply(i, station_num); } else { // send back in invalid command - struct InvalidCommand invalid; - invalid.replyType = 4; - invalid.replyStringSize = 21; - // make a string with the command.commmandType type in it - invalid.replyString = "Invalid command type"; - if ((send(i, &invalid, sizeof(struct InvalidCommand), 0)) == -1) - perror("send"); + char * message = "Invalid command"; + send_invalid_command_reply(i, strlen(message), message); // drop connection upon invalid command close(i); @@ -671,7 +687,7 @@ void *get_in_addr(struct sockaddr *sa) return &(((struct sockaddr_in6*)sa)->sin6_addr); } -void send_announce_message(int fd, int station_num) { +void send_announce_reply(int fd, int station_num) { char* file_path = station_data[station_num].filePath; int len_file_path = strlen(file_path); @@ -692,6 +708,26 @@ void send_announce_message(int fd, int station_num) { free(send_buffer); } +void send_invalid_command_reply(int fd, size_t message_size, char* message) { + char *send_buffer = malloc(message_size+2); + + // type and payload size + send_buffer[0] = 4; + send_buffer[1] = message_size; + + memcpy(send_buffer + 2, message, message_size); + + // printf("buffer: %s\n", send_buffer); + + int bytessent; + if ((bytessent = send(fd, send_buffer, message_size + 2, 0)) == -1) + perror("send"); + // print the number of bytes sent + // printf("sent %d bytes\n", bytessent); + + free(send_buffer); +} + // Parses a buffer into tokens, from cs33 :) int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]) { -- cgit v1.2.3-70-g09d2 From 4311db5d742f03080dfa58aeba45dadc175c625c Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 01:55:59 -0400 Subject: more small things to fit assignment spec --- client.c | 28 ++++++++++++--------- snowcast_control | Bin 35357 -> 35357 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 13773 -> 13757 bytes snowcast_listener | Bin 34654 -> 34654 bytes snowcast_server | Bin 55852 -> 55852 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 25674 -> 25692 bytes snowcast_server_concurrent.c | 7 ++++-- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/client.c b/client.c index df5ea9b..735330c 100644 --- a/client.c +++ b/client.c @@ -117,7 +117,7 @@ int main(int argc, char *argv[]) } else { // convert input to an int int inputInt = atoi(input); - printf("Changing to station %d.\n", inputInt); + // printf("Changing to station %d.\n", inputInt); // send the command to change the station struct SetStation setStation; @@ -139,6 +139,7 @@ void *reply_thread_routine(void* args) { char buf[MAX_READ_SIZE]; while (1) { // recv the message, check for errors too + memset(buf, 0, MAX_READ_SIZE); if ((recvbytes = recv(sockfd, &buf, MAX_READ_SIZE, 0)) == -1) { perror("recv"); exit(1); @@ -148,9 +149,9 @@ void *reply_thread_routine(void* args) { // print the two first field of the call // printf("client: replyType: %d, stringSize: %d\n", buf[0], buf[1]); // print the while buffer by char - for (int i = 0; i < recvbytes; i++) { - printf("%c ", buf[i]); - } + // for (int i = 0; i < recvbytes; i++) { + // printf("%c ", buf[i]); + // } struct Reply reply; memcpy(&reply, buf, 2); @@ -163,6 +164,7 @@ void *reply_thread_routine(void* args) { memcpy(&msg, buf, sizeof(struct Welcome)); msg.numStations = ntohs(msg.numStations); printf("Welcome to Snowcast! The server has %d stations.\n", msg.numStations); + continue; } // print the size of reply @@ -172,19 +174,21 @@ void *reply_thread_routine(void* args) { char *song_name = malloc(reply.stringSize); // printf(sizeof(struct Reply)); memcpy(song_name, buf + 2, reply.stringSize); - printf("New song announced: %s\n", song_name); - free(song_name); - continue; } else if (reply.replyType == 4) { - printf("client: received an invalid command message\n"); - - continue; + // print sockfd + char *message = malloc(reply.stringSize); + // printf(sizeof(struct Reply)); + memcpy(message, buf + 2, reply.stringSize); + printf("Exiting. %s\n", message); + close(sockfd); + exit(1); } - printf("client: received an unknown message\n"); - memset(buf, 0, MAX_READ_SIZE); + printf("Exiting. Lost connection to server."); + close(sockfd); + exit(1); } } \ No newline at end of file diff --git a/snowcast_control b/snowcast_control index 29c20b9..38831a0 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index 9af43c5..d16a61e 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 2a44805..fe63fce 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index c59486d..fba1c8b 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index e65a61d..d562204 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 4fa6d40..5a4ff9f 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -569,23 +569,26 @@ void *select_thread(void *arg) { // check if user has a udpPort if (user_data[sockfd_to_user[i]].udpPort == -1) { // send back in invalid command - char * message = "Must send Hello message first"; + char * message = "Must send Hello message first."; send_invalid_command_reply(i, strlen(message), message); // drop connection upon invalid command close(i); FD_CLR(i, &master); destroy_user(i); + continue; } int station_num = ntohs(command.number); + printf("station_num: %d\n", station_num); if (station_num >= num_stations || station_num < 0) { // send back in invalid command - char * message = "Station number out of range"; + char * message = "Station number out of range."; send_invalid_command_reply(i, strlen(message), message); // drop connection upon invalid command close(i); FD_CLR(i, &master); destroy_user(i); + continue; } // printf("setting station to %d\n", ntohs(command.number)); -- cgit v1.2.3-70-g09d2 From b3e7054694b8cac62c7ea2ca07da960b43ac6d24 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 02:13:54 -0400 Subject: more small spec changes --- snowcast_control | Bin 35357 -> 35357 bytes snowcast_listener | Bin 34654 -> 34654 bytes snowcast_server | Bin 55852 -> 55852 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 25692 -> 25447 bytes snowcast_server_concurrent.c | 37 +++++++++++---------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/snowcast_control b/snowcast_control index 38831a0..656ec0f 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index fe63fce..8d29cf9 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index fba1c8b..8ff138a 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index d562204..b91915d 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 5a4ff9f..92b2dee 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -86,15 +86,15 @@ int main(int argc, char *argv[]) port = argv[1]; num_stations = argc - 2; - printf("port: %s\n", port); - printf("num_stations: %d\n", num_stations); + // printf("port: %s\n", port); + // printf("num_stations: %d\n", num_stations); // init stations size_t totalSize = 0; // get size to malloc for (int i = 2; i < argc; i++) { - printf("file: %s\n", argv[i]); + // printf("file: %s\n", argv[i]); totalSize += sizeof(int) + strlen(argv[i]); } station_data = malloc(totalSize); @@ -105,10 +105,10 @@ int main(int argc, char *argv[]) } // print all indexes in station data - for (int i = 0; i < num_stations; i++) - { - printf("station %d: %s\n", i, station_data[i].filePath); - } + // for (int i = 0; i < num_stations; i++) + // { + // printf("station %d: %s\n", i, station_data[i].filePath); + // } // make array of user data user_data = malloc(sizeof(user_t) * max_active_users); @@ -160,7 +160,7 @@ int main(int argc, char *argv[]) } else { print_fd = STDOUT_FILENO; } - printf("print_fd: %d\n", print_fd); + // printf("print_fd: %d\n", print_fd); pthread_t print_info_thread; pthread_create(&print_info_thread, NULL, print_info_routine, print_fd); // note - this file descriptor is closed in the thread @@ -249,9 +249,9 @@ int sendall(int udp_sockfd, char *buf, int *len, struct addrinfo *thread_res) void *send_udp_packet_routine(void *arg) { // unpack args int user_index = (int) arg; - printf("thread : user_index: %d\n", user_index); + // printf("thread : user_index: %d\n", user_index); // print user data - print_user_data(user_index); + // print_user_data(user_index); // declare vairables to be used int did_work = 1; @@ -402,21 +402,22 @@ void *synchronization_thread(void *arg) { if (station_data[i].seekIndex >= size) { station_data[i].seekIndex = 0; - + // printf("resetting station %d\n", i); // send the announce messages - for (int i = 0; i < max_active_users; i++) + for (int j = 0; j < max_active_users; i++) { // if (user_data[i].streamThread == NULL) { // break; // } - if (user_data[i].sockfd == -1) + if (user_data[j].sockfd == -1) continue; // print_user_data(i); // update the station of each user - if (user_data[i].stationNum == i) + if (user_data[j].stationNum == i) { - send_announce_reply(user_data[i].sockfd, i); + // printf("sending announce to user %d\n", i); + send_announce_reply(user_data[j].sockfd, i); } } } @@ -579,7 +580,7 @@ void *select_thread(void *arg) { } int station_num = ntohs(command.number); - printf("station_num: %d\n", station_num); + // printf("station_num: %d\n", station_num); if (station_num >= num_stations || station_num < 0) { // send back in invalid command char * message = "Station number out of range."; @@ -700,13 +701,13 @@ void send_announce_reply(int fd, int station_num) { memcpy(send_buffer + 2, file_path, len_file_path); - printf("buffer: %s\n", send_buffer); + // printf("buffer: %s\n", send_buffer); int bytessent; if ((bytessent = send(fd, send_buffer, len_file_path + 2, 0)) == -1) perror("send"); // print the number of bytes sent - printf("sent %d bytes\n", bytessent); + // printf("sent %d bytes\n", bytessent); free(send_buffer); } -- cgit v1.2.3-70-g09d2 From 005eaf49da54d72e00400c550664dae9469007dc Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 02:19:24 -0400 Subject: fix some other tests i broke. small index bug --- snowcast_control | Bin 35357 -> 21416 bytes snowcast_listener | Bin 34654 -> 19128 bytes snowcast_server | Bin 55852 -> 38776 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 25447 -> 25644 bytes snowcast_server_concurrent.c | 39 ++++++++++++--------- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/snowcast_control b/snowcast_control index 656ec0f..3c874c7 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 8d29cf9..9f75571 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 8ff138a..b40fe10 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index b91915d..faf2f15 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 92b2dee..bb3eee9 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -371,6 +371,27 @@ void *send_udp_packet_routine(void *arg) { return NULL; } +void *send_announce_routine(void *arg) { + // unpack args + int station_num = (int) arg; + // send the announce messages + for (int i = 0; i < max_active_users; i++) + { + // if (user_data[i].streamThread == NULL) { + // break; + // } + if (user_data[i].sockfd == -1) + continue; + // print_user_data(i); + // update the station of each user + if (user_data[i].stationNum == station_num) + { + // printf("sending announce to user %d\n", i); + send_announce_reply(user_data[i].sockfd, i); + } + } +} + void *synchronization_thread(void *arg) { int c = 0; while (1) @@ -404,22 +425,8 @@ void *synchronization_thread(void *arg) { station_data[i].seekIndex = 0; // printf("resetting station %d\n", i); - // send the announce messages - for (int j = 0; j < max_active_users; i++) - { - // if (user_data[i].streamThread == NULL) { - // break; - // } - if (user_data[j].sockfd == -1) - continue; - // print_user_data(i); - // update the station of each user - if (user_data[j].stationNum == i) - { - // printf("sending announce to user %d\n", i); - send_announce_reply(user_data[j].sockfd, i); - } - } + pthread_t send_announce_thread; + pthread_create(&send_announce_thread, NULL, send_announce_routine, (void *)i); } } -- cgit v1.2.3-70-g09d2 From 35e552ad6843c0e149d2389ed0a92de3d114bbbb Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 02:22:44 -0400 Subject: malloc error checking --- snowcast_server_concurrent.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index bb3eee9..d853507 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -274,6 +274,7 @@ void *send_udp_packet_routine(void *arg) { int int_port = user_data[user_index].udpPort; int length = snprintf( NULL, 0, "%d", int_port ); char* port = malloc( length + 1 ); + if (!port) { perror("malloc"); return (NULL); } snprintf( port, length + 1, "%d", int_port ); sprintf(port, "%d", int_port); @@ -703,6 +704,10 @@ void send_announce_reply(int fd, int station_num) { int len_file_path = strlen(file_path); char *send_buffer = malloc(len_file_path+2); + if (!send_buffer) { + perror("malloc"); + return; + } send_buffer[0] = 3; send_buffer[1] = len_file_path; @@ -721,6 +726,10 @@ void send_announce_reply(int fd, int station_num) { void send_invalid_command_reply(int fd, size_t message_size, char* message) { char *send_buffer = malloc(message_size+2); + if (!send_buffer) { + perror("malloc"); + return; + } // type and payload size send_buffer[0] = 4; -- cgit v1.2.3-70-g09d2 From 182df1bda7f8affc3003009c20375e590009838f Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 14:10:45 -0400 Subject: fix memory array --- snowcast_control | Bin 21416 -> 35357 bytes snowcast_listener | Bin 19128 -> 34654 bytes snowcast_server | Bin 38776 -> 55868 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 25644 -> 26640 bytes snowcast_server_concurrent.c | 87 ++++++++++++++------- 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/snowcast_control b/snowcast_control index 3c874c7..4dab14b 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 9f75571..fae3cd2 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index b40fe10..4020da9 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index faf2f15..4d64154 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index d853507..77072fe 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -10,6 +10,8 @@ #include #include +#include + #include "protocol.h" @@ -206,7 +208,7 @@ void *print_info_routine(void *arg) { write(print_fd, file_path, strlen(file_path)); for (int j = 0; j < max_active_users; j++) { - if (user_data[j].sockfd == -1) + if (!user_data[j].sockfd || user_data[j].sockfd == -1) continue; if (user_data[j].stationNum == i) { char *localhost_ip = ",127.0.0.1:"; @@ -327,20 +329,24 @@ void *send_udp_packet_routine(void *arg) { // get file path char* file_path = station_data[station_num].filePath; // get current seek chunk - FILE* file_stream = fopen(file_path, "r"); + int stream_fd = open(file_path, O_RDONLY); + if (stream_fd == -1) { + perror("open"); + return (NULL); + } int current_chunk = station_data[station_num].seekIndex; - if (fseek(file_stream, current_chunk, SEEK_SET) == -1) { + if (lseek(stream_fd, current_chunk, SEEK_SET) == -1) { perror("fseek"); return (NULL); } size_t BYTES_PER_SECOND = 16*1024; // read 1000 bytes of the file char file_buffer[BYTES_PER_SECOND]; - if (fread(file_buffer, BYTES_PER_SECOND, 1, file_stream) == -1) { + if (read(stream_fd, file_buffer, BYTES_PER_SECOND) == -1) { perror("fread"); return (NULL); } - fclose(file_stream); + close(stream_fd); // printf("send data: thread %d \n", user_index); // int numbytes; // if ((numbytes = sendto(udp_sockfd, data, strlen(data), 0, @@ -381,14 +387,15 @@ void *send_announce_routine(void *arg) { // if (user_data[i].streamThread == NULL) { // break; // } - if (user_data[i].sockfd == -1) + if (user_data[i].sockfd == 0 || user_data[i].sockfd == -1) { continue; + } // print_user_data(i); // update the station of each user if (user_data[i].stationNum == station_num) { // printf("sending announce to user %d\n", i); - send_announce_reply(user_data[i].sockfd, i); + send_announce_reply(user_data[i].sockfd, station_num); } } } @@ -411,14 +418,24 @@ void *synchronization_thread(void *arg) { { // printf("checking station %d\n", i); // get size of file - FILE* fp = fopen(station_data[i].filePath, "r"); - fseek(fp, 0L, SEEK_END); - size_t size = ftell(fp); - fclose(fp); - if (size == -1) { - perror("ftell"); + struct stat f_info; + // int file_fd = open(station_data[i].filePath, O_RDONLY); + // if (file_fd == -1) { + // perror("open"); + // return (NULL); + // } + if (stat(station_data[i].filePath, &f_info) == -1) { + perror("fstat"); return (NULL); } + + size_t size = f_info.st_size; + + // fclose(file_fd); + // if (size == -1) { + // perror("ftell"); + // return (NULL); + // } station_data[i].seekIndex += BYTES_PER_SECOND; // if the seek index is greater than the size of the file, reset it if (station_data[i].seekIndex >= size) @@ -550,7 +567,7 @@ void *select_thread(void *arg) { // got error or connection closed by client if (nbytes == 0) { // connection closed - printf("selectserver: socket %d hung up\n", i); + // printf("selectserver: socket %d hung up\n", i); } else { perror("recv"); } @@ -620,39 +637,46 @@ void *select_thread(void *arg) { } // END got new incoming connection } // END looping through file descriptors - // broadcast the new files over the udp socket list for each use - } // END for(;;)--and you thought it would never end! } void *init_user(int sockfd) { // add the user to the list of user data pthread_mutex_lock(&mutex_user_data); - // this is to save memory space. // in general, the displacement of 4 is where a user "used to be" - int user_index = max_active_users++; + // int user_index = max_active_users++; + // int running_index = 0; + // while(running_index < max_active_users) + // { + // if (user_data[running_index++].sockfd == -1) + // { + // user_index = running_index; + // break; + // } + // // printf("reusing memory\n"); + // } int running_index = 0; - while(running_index++ < max_active_users) - { - if (user_data[running_index].sockfd == -1) - { - user_index = running_index; + while(running_index < max_active_users) { + if (user_data[running_index].sockfd == -1) { break; } - // printf("reusing memory\n"); + running_index++; } - // have to make more memory - if (user_index == max_active_users) { - ///printf("making new memory\n"); + if (running_index == max_active_users) { + // printf("reached max active users\n"); + printf("making new memory\n"); + max_active_users++; + // TODO: FIX SO THAT IT USES CURRENT USERS, NOT MAX_ACTIVE_USERS FOT THE RESIZE user_t *more_users = realloc(user_data, sizeof(user_t) * max_active_users); if (!more_users) { perror("realloc"); exit(1); } user_data = more_users; } + // map TCP sockfd to this user index - user_data[user_index] = (user_t){-1, -1, sockfd, -1}; - sockfd_to_user[sockfd] = user_index; + user_data[running_index] = (user_t){-1, -1, sockfd, -1}; + sockfd_to_user[sockfd] = running_index; // free(user_stream_threads); pthread_mutex_unlock(&mutex_user_data); } @@ -675,16 +699,19 @@ void *print_user_data(int index) { printf("udpPort: %d, stationNum: %d, sockfd: %d, threadId:%d\n", user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd, user_data[index].streamThread); } + void destroy_user(int sockfd) { pthread_mutex_lock(&mutex_user_data); - // stop the thread streaming to the user + // TODO: close the FD in the stream thread pthread_cancel(user_data[sockfd_to_user[sockfd]].streamThread); + // close(user_data[sockfd_to_user[sockfd]].udpPort); // pthread_kill(user_data[sockfd_to_user[sockfd]].streamThread, SIGINT); // "remove" the user from the list of user data user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1, -1}; // map sockfd to -1 sockfd_to_user[sockfd] = -1; + // close(sockfd); pthread_mutex_unlock(&mutex_user_data); } -- cgit v1.2.3-70-g09d2 From c01ec434d71446cee0ea78a0db9817a9a7cfdba2 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 14:18:49 -0400 Subject: add design doc for submission --- milestone.pdf | Bin 0 -> 3619195 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 milestone.pdf diff --git a/milestone.pdf b/milestone.pdf new file mode 100644 index 0000000..2525a23 Binary files /dev/null and b/milestone.pdf differ -- cgit v1.2.3-70-g09d2 From d184119c14a2f9c764b176b529ad9e6920f5d505 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 19:12:03 +0000 Subject: remove extraneous lines --- snowcast_control | Bin 35357 -> 35357 bytes snowcast_listener | Bin 34654 -> 34654 bytes snowcast_server | Bin 55868 -> 55868 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 26640 -> 26569 bytes snowcast_server_concurrent.c | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) diff --git a/snowcast_control b/snowcast_control index 4dab14b..2081b59 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index fae3cd2..c5beeff 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 4020da9..58f5b20 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 4d64154..d18b1e8 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c index 77072fe..e0552cf 100644 --- a/snowcast_server_concurrent.c +++ b/snowcast_server_concurrent.c @@ -665,7 +665,7 @@ void *init_user(int sockfd) { } if (running_index == max_active_users) { // printf("reached max active users\n"); - printf("making new memory\n"); + // printf("making new memory\n"); max_active_users++; // TODO: FIX SO THAT IT USES CURRENT USERS, NOT MAX_ACTIVE_USERS FOT THE RESIZE user_t *more_users = realloc(user_data, sizeof(user_t) * max_active_users); -- cgit v1.2.3-70-g09d2 From 362250d1cb923d9ced8ea51508ace50b76050b06 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 15:41:14 -0400 Subject: try fixes --- snowcast_control | Bin 35357 -> 35357 bytes snowcast_listener | Bin 34654 -> 34654 bytes snowcast_server | Bin 55868 -> 55868 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/snowcast_control b/snowcast_control index 2081b59..d4a3ba1 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index c5beeff..414117f 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 58f5b20..3434c81 100755 Binary files a/snowcast_server and b/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 3d9c7d4c5ae135ace068ba50f6b3ae971d8e276b Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 23:24:05 -0400 Subject: implement collecting all bits, if they don't come in one message --- Makefile | 2 +- client.c | 90 ++- protocol.c | 40 + protocol.h | 8 +- server.c | 831 +++++++++++++++++++++ snowcast_control | Bin 35357 -> 35565 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 13757 -> 14770 bytes snowcast_listener | Bin 34654 -> 34654 bytes snowcast_server | Bin 55868 -> 56124 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 26569 -> 27185 bytes snowcast_server_concurrent.c | 791 -------------------- 11 files changed, 927 insertions(+), 835 deletions(-) create mode 100644 protocol.c create mode 100644 server.c delete mode 100644 snowcast_server_concurrent.c diff --git a/Makefile b/Makefile index 277de9a..3aae1ce 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS = -g -I. -std=gnu99 -Wall -pthread all: server client server: - $(CC) $(CFLAGS) -o snowcast_server snowcast_server_concurrent.c + $(CC) $(CFLAGS) -o snowcast_server server.c client: $(CC) $(CFLAGS) -o snowcast_control client.c diff --git a/client.c b/client.c index 735330c..852e7ff 100644 --- a/client.c +++ b/client.c @@ -16,7 +16,7 @@ #include -#include "protocol.h" +#include "protocol.c" #define MAXDATASIZE 100 // max number of bytes we can get at once @@ -103,6 +103,9 @@ int main(int argc, char *argv[]) exit(1); } + // CONSIDER: could recieve the welcome message here + + char input[LINE_MAX]; printf("Enter a number to change to it's station. Click q to end stream.\n"); while (1) { @@ -123,8 +126,9 @@ int main(int argc, char *argv[]) struct SetStation setStation; setStation.commandType = 1; setStation.stationNumber = htons(inputInt); - if ((numbytessent = send(sockfd, &setStation, sizeof(struct SetStation), 0)) == -1) { - perror("send"); + int bytes_to_send = sizeof(struct SetStation); + if (send_all(sockfd, &setStation, &bytes_to_send) == -1) { + perror("send_all"); exit(1); } } @@ -135,59 +139,65 @@ int main(int argc, char *argv[]) void *reply_thread_routine(void* args) { int sockfd = (int)args; - int recvbytes; - char buf[MAX_READ_SIZE]; + // int recvbytes; while (1) { - // recv the message, check for errors too - memset(buf, 0, MAX_READ_SIZE); - if ((recvbytes = recv(sockfd, &buf, MAX_READ_SIZE, 0)) == -1) { + // recv the first byte of the message to get it's type + uint8_t reply_type = -1; + // print size of utin8 + if (recv(sockfd, &reply_type, 1, 0) == -1) { perror("recv"); exit(1); } - buf[recvbytes] = '\0'; - // printf("client: received %d bytes on a reply call \n", recvbytes); - // print the two first field of the call - // printf("client: replyType: %d, stringSize: %d\n", buf[0], buf[1]); - // print the while buffer by char - // for (int i = 0; i < recvbytes; i++) { - // printf("%c ", buf[i]); - // } - struct Reply reply; - memcpy(&reply, buf, 2); - - // print out the fields of reply on one line - // printf("\nclient: replyType: %d, stringSize: %d\n", reply.replyType, reply.stringSize); - if (reply.replyType == 2) { - struct Welcome msg; + if (reply_type == 2) { // we have a welcome message // recv the message, check for errors too - memcpy(&msg, buf, sizeof(struct Welcome)); - msg.numStations = ntohs(msg.numStations); - printf("Welcome to Snowcast! The server has %d stations.\n", msg.numStations); + int16_t num_stations = -1; + int bytes_to_read = sizeof(uint16_t); + if (recv_all(sockfd, &num_stations, &bytes_to_read) == -1) { + perror("recv_all"); + exit(1); + } + num_stations = ntohs(num_stations); + printf("Welcome to Snowcast! The server has %d stations.\n", num_stations); continue; } - // print the size of reply - if (reply.replyType == 3) { - // printf("client: received an announce message\n"); - - char *song_name = malloc(reply.stringSize); - // printf(sizeof(struct Reply)); - memcpy(song_name, buf + 2, reply.stringSize); + if (reply_type == 3) { // we have an announce message + // get the string size + u_int8_t string_size = -1; + if (recv(sockfd, &string_size, 1, 0) == -1) { + perror("recv"); + exit(1); + } + char *song_name = malloc(string_size); + int bytes_to_read = string_size; + if (recv_all(sockfd, song_name, &bytes_to_read) == -1) { + perror("recv_all"); + exit(1); + } printf("New song announced: %s\n", song_name); free(song_name); continue; - } else if (reply.replyType == 4) { - // print sockfd - char *message = malloc(reply.stringSize); - // printf(sizeof(struct Reply)); - memcpy(message, buf + 2, reply.stringSize); - printf("Exiting. %s\n", message); + } else if (reply_type == 4) { // we have an invalid command message + // get the string size + u_int8_t string_size = -1; + if (recv(sockfd, &string_size, 1, 0) == -1) { + perror("recv"); + exit(1); + } + char *message = malloc(string_size); + int bytes_to_read = string_size; + if (recv_all(sockfd, message, &bytes_to_read) == -1) { + perror("recv_all"); + exit(1); + } + printf("Invalid protocol: %s. Exiting.\n", message); + free(message); close(sockfd); exit(1); } - printf("Exiting. Lost connection to server."); + printf("Lost connection to server. Exiting."); close(sockfd); exit(1); } diff --git a/protocol.c b/protocol.c new file mode 100644 index 0000000..864afd8 --- /dev/null +++ b/protocol.c @@ -0,0 +1,40 @@ +#include +#include + +#include "protocol.h" + +int send_all(int sock, char *buf, int *len) +{ + int total = 0; // how many bytes we've sent + int bytesleft = *len; // how many we have left to send + int n; + + while(total < *len) { + n = send(sock, buf+total, bytesleft, 0); + if (n == -1) { break; } + total += n; + bytesleft -= n; + } + + *len = total; // return number actually sent here + + return n==-1?-1:0; // return -1 on failure, 0 on success +} + +int recv_all(int sock, char *buf, int *len) +{ + int total = 0; // how many bytes we've sent + int bytesleft = *len; // how many we have left to send + int n; + + while(total < *len) { + n = recv(sock, buf+total, bytesleft, 0); + if (n == -1) { break; } + total += n; + bytesleft -= n; + } + + *len = total; // return number actually sent here + + return n==-1?-1:0; // return -1 on failure, 0 on success +} diff --git a/protocol.h b/protocol.h index 39f26e6..aeeaa54 100644 --- a/protocol.h +++ b/protocol.h @@ -25,8 +25,7 @@ struct Welcome { struct Reply { uint8_t replyType; uint8_t stringSize; - char *string; -} __attribute__((packed)); +} reply_t __attribute__((packed)); struct Announce { uint8_t replyType; uint8_t songnameSize; @@ -36,4 +35,7 @@ struct InvalidCommand { uint8_t replyType; uint8_t replyStringSize; char *replyString; -} __attribute__((packed)); \ No newline at end of file +} __attribute__((packed)); + +int send_all(int sock, char *buf, int *len); +int recv_all(int sock, char *buf, int *len); diff --git a/server.c b/server.c new file mode 100644 index 0000000..837432a --- /dev/null +++ b/server.c @@ -0,0 +1,831 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "protocol.c" + +#define LINE_MAX 1024 +#define MAX_USERS 1000 +#define MAX_PATH 50 + +typedef struct station { + int seekIndex; + char* filePath; +} station_t; + +typedef struct user { + int udpPort; + int stationNum; + int sockfd; + pthread_t streamThread; +} user_t; + + +/* For safe condition variable usage, must use a boolean predicate and */ +/* a mutex with the condition. */ +int count = 0; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +pthread_mutex_t station_mutex = PTHREAD_MUTEX_INITIALIZER; + +const char *port; +int num_stations; + +int start_threads = 0; +int max_active_users = 0; + +pthread_mutex_t mutex_user_data = PTHREAD_MUTEX_INITIALIZER; +// array from index to user_data +user_t *user_data; +int sockfd_to_user[MAX_USERS]; + +// stations array pointer +station_t *station_data; + +void *send_udp_packet_routine(void* arg); +void *select_thread(void* arg); +void *synchronization_thread(void* arg); + +int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]); +void *print_info_routine(void *arg); + +void *get_in_addr(struct sockaddr *sa); + +void *init_user(int sockfd); +void *update_user_udpPort(int sockfd, int udpPort); +void *update_user_station(int sockfd, int stationNum); +void *print_user_data(int sockfd); +void destroy_user(int sockfd); + +void send_announce_reply(int fd, int station_num); +void send_invalid_command_reply(int fd, size_t message_size, char* message); + +// void *load_file(void* arg); + +int main(int argc, char *argv[]) +{ + // threads to control reading files at chunks while the other threads sleep + // station_data = malloc(sizeof(station_t) * NUM_STATIONS); + // check and assign arguments + if (argc < 3) { + fprintf(stderr,"usage: ./snowcast_server [file 1] [file 2] ... \n"); + exit(1); + } + + port = argv[1]; + num_stations = argc - 2; + + // printf("port: %s\n", port); + // printf("num_stations: %d\n", num_stations); + + // init stations + size_t totalSize = 0; + // get size to malloc + for (int i = 2; i < argc; i++) + { + // printf("file: %s\n", argv[i]); + totalSize += sizeof(int) + strlen(argv[i]); + } + station_data = malloc(totalSize); + // assign the stations + for (int i = 2; i < argc; i++) + { + station_data[i - 2] = (station_t) { 0, argv[i]}; + } + + // print all indexes in station data + // for (int i = 0; i < num_stations; i++) + // { + // printf("station %d: %s\n", i, station_data[i].filePath); + // } + + // make array of user data + user_data = malloc(sizeof(user_t) * max_active_users); + if (!user_data) { perror("malloc"); return 1; } + + // make and start "select" thread that manages: + // 1) new connections, 2) requests from current connections, 3)cloing connections + pthread_t s_thread; + pthread_create(&s_thread, NULL, select_thread, NULL); + + // start syncchronization thread to broadcast stations + pthread_t sync_thread; + pthread_create(&sync_thread, NULL, synchronization_thread, NULL); + + // command line interface + char input[LINE_MAX]; + memset(input, 0, LINE_MAX); + + char *tokens[LINE_MAX / 2]; + while (read(STDIN_FILENO, input, LINE_MAX) > 0) { + // init tokens + memset(tokens, 0, (LINE_MAX / 2) * sizeof(char *)); + + // if 0, all whitespace + if (!parse(input, tokens)) + continue; + + char *command = tokens[0]; + // if q, shutdown! + if (!strcmp(command, "q")) { + printf("Exiting.\n"); + // TODO: exit better than break + break; + } + + // if p, print info + else if (!strcmp(command, "p")) { + // get the file descriptor + int print_fd = 0; + // see if there is a file path + char *output_file_path = tokens[1]; + if (output_file_path != NULL) + { + if ((print_fd = open(output_file_path, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU)) == -1) + { + perror("open"); + continue; + } + } else { + print_fd = STDOUT_FILENO; + } + // printf("print_fd: %d\n", print_fd); + pthread_t print_info_thread; + pthread_create(&print_info_thread, NULL, print_info_routine, print_fd); + // note - this file descriptor is closed in the thread + } + else if (!strcmp(command, "u")) + { + // print all user data + for (int i = 0; i < max_active_users; i++) + { + print_user_data(i); + } + } + } + + return 0; +} + +void write_int_to_fd(int fd, int n) { + int l = snprintf(NULL, 0, "%d", n); + char *num = malloc(l + 1); + if (!num) { perror("malloc"); return; } + + snprintf(num, l + 1, "%d", n); + if (write(fd, num, strlen(num)) == -1) { + perror("write"); + } + + + free(num); +} + +void *print_info_routine(void *arg) { + int print_fd = (int) arg; + // printf("thread print_fd: %d\n", print_fd); + // printf("num_stations: %d\n", num_stations); + for (int i = 0; i < num_stations; i++) { + write_int_to_fd(print_fd, i); + char *comma = ","; + write(print_fd, comma, strlen(comma)); + + // write file path + char* file_path = station_data[i].filePath; + write(print_fd, file_path, strlen(file_path)); + + for (int j = 0; j < max_active_users; j++) { + if (!user_data[j].sockfd || user_data[j].sockfd == -1) + continue; + if (user_data[j].stationNum == i) { + char *localhost_ip = ",127.0.0.1:"; + write(print_fd, localhost_ip, strlen(localhost_ip)); + // write udpPort + write_int_to_fd(print_fd, user_data[j].udpPort); + } + } + // wrtie new line + char *newline = "\n"; + write(print_fd, newline, strlen(newline)); + } + + if (print_fd != STDOUT_FILENO) close(print_fd); + return (NULL); +} + +int send_all_udp(int udp_sockfd, char *buf, int *len, struct addrinfo *thread_res) +{ + int MAX_PACKET_SIZE = 512; + int total = 0; // how many bytes we've sent + int bytesleft = *len; // how many we have left to send + int n; + + while(total < *len) { + n = sendto(udp_sockfd, buf+total, MAX_PACKET_SIZE, 0, thread_res->ai_addr, thread_res->ai_addrlen); + // thread_res->ai_addr, thread_res->ai_addrlen)) == -1; + if (n == -1) { break; } + total += n; + bytesleft -= n; + } + + *len = total; // return number actually sent here + + return n==-1?-1:0; // return -1 on failure, 0 on success +} + + +/* Make the manager routine */ +void *send_udp_packet_routine(void *arg) { + // unpack args + int user_index = (int) arg; + // printf("thread : user_index: %d\n", user_index); + // print user data + // print_user_data(user_index); + + // declare vairables to be used + int did_work = 1; + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + int s; + int udp_sockfd; + struct addrinfo thread_hints, *thread_res, *thread_servinfo; + int error_code; + + // TODO: add error checking on these calls*** + + // setup hints + memset(&thread_hints, 0, sizeof thread_hints); + thread_hints.ai_family = AF_INET; // use IPv4 only + thread_hints.ai_socktype = SOCK_DGRAM; + thread_hints.ai_flags = AI_PASSIVE; // fill in my IP for me + + // setup the socket for client listener DATAGRAM (udp) + // cover the port integer to a string + int int_port = user_data[user_index].udpPort; + int length = snprintf( NULL, 0, "%d", int_port ); + char* port = malloc( length + 1 ); + if (!port) { perror("malloc"); return (NULL); } + snprintf( port, length + 1, "%d", int_port ); + sprintf(port, "%d", int_port); + + if (error_code = getaddrinfo(NULL, port, &thread_hints, &thread_servinfo) != 0) + { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error_code)); + return (NULL); + } + free(port); + + // loop through all the results and make a socket + for(thread_res = thread_servinfo; thread_res != NULL; thread_res = thread_res->ai_next) { + if ((udp_sockfd = socket(thread_res->ai_family, thread_res->ai_socktype, + thread_res->ai_protocol)) == -1) { + perror("talker: socket"); + continue; + } + break; + } + if (udp_sockfd == NULL) { + fprintf(stderr, "talker: failed to create socket\n"); + return (NULL); + } + + // bind(udp_sockfd, thread_res->ai_addr, thread_res->ai_addrlen); + + + // freeaddrinfo(thread_servinfo); + + while (1) { + // wait for + pthread_mutex_lock(&m); + did_work = 0; + while (!start_threads) + { + pthread_cond_wait(&cond, &m); + } + + int station_num = user_data[user_index].stationNum; + if (station_num == -1) { + did_work = 1; + } + + if (!did_work) { + // sendto a random string of data to the user + int station_num = user_data[user_index].stationNum; + char *data = station_data[station_num].filePath; + // printf("load data: thread %d \n", user_index); + + // get file path + char* file_path = station_data[station_num].filePath; + // get current seek chunk + int stream_fd = open(file_path, O_RDONLY); + if (stream_fd == -1) { + perror("open"); + return (NULL); + } + int current_chunk = station_data[station_num].seekIndex; + if (lseek(stream_fd, current_chunk, SEEK_SET) == -1) { + perror("fseek"); + return (NULL); + } + size_t BYTES_PER_SECOND = 16*1024; + // read 1000 bytes of the file + char file_buffer[BYTES_PER_SECOND]; + if (read(stream_fd, file_buffer, BYTES_PER_SECOND) == -1) { + perror("fread"); + return (NULL); + } + close(stream_fd); + // printf("send data: thread %d \n", user_index); + // int numbytes; + // if ((numbytes = sendto(udp_sockfd, data, strlen(data), 0, + // thread_res->ai_addr, thread_res->ai_addrlen)) == -1) { + // perror("talker: sendto"); + // return (NULL); + // } + // print the size of the file_buffer + // printf("size of file_buffer: %lu\n", sizeof(file_buffer)); + + int bytes_sent = sizeof(file_buffer); + if (send_all_udp(udp_sockfd, file_buffer, &bytes_sent, thread_res) == -1) + { + perror("send_all_udp"); + printf("We only sent %d bytes because of the error!\n", bytes_sent); + } + // printf("We sent all %d bytes!\n", bytes_sent); + + did_work = 1; + + + usleep(400000); + } + + pthread_mutex_unlock(&m); + + usleep(100000); + } + return NULL; +} + +void *send_announce_routine(void *arg) { + // unpack args + int station_num = (int) arg; + // send the announce messages + for (int i = 0; i < max_active_users; i++) + { + // if (user_data[i].streamThread == NULL) { + // break; + // } + if (user_data[i].sockfd == 0 || user_data[i].sockfd == -1) { + continue; + } + // print_user_data(i); + // update the station of each user + if (user_data[i].stationNum == station_num) + { + // printf("sending announce to user %d\n", i); + send_announce_reply(user_data[i].sockfd, station_num); + } + } +} + +void *synchronization_thread(void *arg) { + int c = 0; + while (1) + { + start_threads = 1; + // printf("\nbroadcast %d\n", c++); + pthread_cond_broadcast(&cond); + usleep(2000); + start_threads = 0; + // printf("before loop"); + // update file seek index for each station + size_t BYTES_PER_SECOND = 16*1024; + // print num_stations + // printf("num_stations: %d\n", num_stations); + for (int i = 0; i < num_stations; i++) + { + // printf("checking station %d\n", i); + // get size of file + struct stat f_info; + // int file_fd = open(station_data[i].filePath, O_RDONLY); + // if (file_fd == -1) { + // perror("open"); + // return (NULL); + // } + if (stat(station_data[i].filePath, &f_info) == -1) { + perror("fstat"); + return (NULL); + } + + size_t size = f_info.st_size; + + // fclose(file_fd); + // if (size == -1) { + // perror("ftell"); + // return (NULL); + // } + station_data[i].seekIndex += BYTES_PER_SECOND; + // if the seek index is greater than the size of the file, reset it + if (station_data[i].seekIndex >= size) + { + station_data[i].seekIndex = 0; + // printf("resetting station %d\n", i); + + pthread_t send_announce_thread; + pthread_create(&send_announce_thread, NULL, send_announce_routine, (void *)i); + } + } + + + usleep(2000); + usleep(1000000-4000); + } +} + +void *select_thread(void *arg) { + fd_set master; // master file descriptor list + fd_set read_fds; // temp file descriptor list for select() + int fdmax; // maximum file descriptor number + + int listener; // listening socket descriptor + int newfd; // newly accept()ed socket descriptor + struct sockaddr_storage remoteaddr; // client address + socklen_t addrlen; + + char buf[256]; // buffer for client data + int nbytes; + + + char remoteIP[INET6_ADDRSTRLEN]; + + int yes=1; // for setsockopt() SO_REUSEADDR, below + int i, j, rv; + + struct addrinfo hints, *ai, *p; + + // const char* port = argv[1]; + + FD_ZERO(&master); // clear the master and temp sets + FD_ZERO(&read_fds); + + // LISTENER: get us a socket and bind it + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) { + fprintf(stderr, "snowcast_server: %s\n", gai_strerror(rv)); + exit(1); + } + + for(p = ai; p != NULL; p = p->ai_next) { + listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (listener < 0) { + continue; + } + + // lose the pesky "address already in use" error message + setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + + if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) { + close(listener); + continue; + } + + break; + } + + // if we got here, it means we didn't get bound + if (p == NULL) { + fprintf(stderr, "snowcast_server: failed to bind\n"); + exit(2); + } + + freeaddrinfo(ai); // all done with this + + // listen + if (listen(listener, 10) == -1) { + perror("listen"); + exit(3); + } + + // add the listener to the master set + FD_SET(listener, &master); + + // keep track of the biggest file descriptor + fdmax = listener; // so far, it's this one + + while(1) { + read_fds = master; // copy it + if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { + perror("select"); + exit(4); + } + + // run through the existing connections looking for data to read + for(i = 0; i <= fdmax; i++) { + if (FD_ISSET(i, &read_fds)) { // we got one!! + if (i == listener) { + // handle new connections + addrlen = sizeof remoteaddr; + newfd = accept(listener, + (struct sockaddr *)&remoteaddr, + &addrlen); + + if (newfd == -1) { + perror("accept"); + } else { + FD_SET(newfd, &master); // add to master set + if (newfd > fdmax) { // keep track of the max + fdmax = newfd; + } + // printf("selectserver: new connection from %s on " + // "socket %d\n.", + // inet_ntop(remoteaddr.ss_family, + // get_in_addr((struct sockaddr*)&remoteaddr), + // remoteIP, INET6_ADDRSTRLEN), + // newfd); + // init user with this newfd + init_user(newfd); + } + } else { + // handle data from a client + struct Command command; + if ((nbytes = recv(i, (char*)&command, sizeof(struct Command), 0)) <= 0) { + // got error or connection closed by client + if (nbytes == 0) { + // connection closed + // printf("selectserver: socket %d hung up\n", i); + } else { + perror("recv"); + } + close(i); // bye! + FD_CLR(i, &master); // remove from master set + // remove user from data structures + destroy_user(i); + } else { + // we got some data from a client + if (command.commandType == 0) { + // hello message with udpPort + // printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); + // update udp port of user + update_user_udpPort(i, ntohs(command.number)); + + // send the welcome message to client + struct Welcome welcome; + welcome.replyType = 2; + welcome.numStations = htons(num_stations); + int bytes_to_send = sizeof(struct Welcome); + if (send_all(i, &welcome, &bytes_to_send) == -1) + perror("send_all"); + } + else if (command.commandType == 1) { + // check if user has a udpPort + if (user_data[sockfd_to_user[i]].udpPort == -1) { + // send back in invalid command + char * message = "Must send Hello message first."; + send_invalid_command_reply(i, strlen(message), message); + // drop connection upon invalid command + close(i); + FD_CLR(i, &master); + destroy_user(i); + continue; + } + + int station_num = ntohs(command.number); + // printf("station_num: %d\n", station_num); + if (station_num >= num_stations || station_num < 0) { + // send back in invalid command + char * message = "Station number out of range."; + send_invalid_command_reply(i, strlen(message), message); + // drop connection upon invalid command + close(i); + FD_CLR(i, &master); + destroy_user(i); + continue; + } + + // printf("setting station to %d\n", ntohs(command.number)); + // update station of user + update_user_station(i, ntohs(command.number)); + send_announce_reply(i, station_num); + } + else { + // send back in invalid command + char * message = "Invalid command"; + send_invalid_command_reply(i, strlen(message), message); + + // drop connection upon invalid command + close(i); + FD_CLR(i, &master); + destroy_user(i); + } + } + } // END handle data from client + } // END got new incoming connection + } // END looping through file descriptors + + } // END for(;;)--and you thought it would never end! +} + +void *init_user(int sockfd) { + // add the user to the list of user data + pthread_mutex_lock(&mutex_user_data); + // this is to save memory space. + // in general, the displacement of 4 is where a user "used to be" + // int user_index = max_active_users++; + // int running_index = 0; + // while(running_index < max_active_users) + // { + // if (user_data[running_index++].sockfd == -1) + // { + // user_index = running_index; + // break; + // } + // // printf("reusing memory\n"); + // } + int running_index = 0; + while(running_index < max_active_users) { + if (user_data[running_index].sockfd == -1) { + break; + } + running_index++; + } + if (running_index == max_active_users) { + // printf("reached max active users\n"); + // printf("making new memory\n"); + max_active_users++; + // TODO: FIX SO THAT IT USES CURRENT USERS, NOT MAX_ACTIVE_USERS FOT THE RESIZE + user_t *more_users = realloc(user_data, sizeof(user_t) * max_active_users); + if (!more_users) { perror("realloc"); exit(1); } + user_data = more_users; + } + + + // map TCP sockfd to this user index + user_data[running_index] = (user_t){-1, -1, sockfd, -1}; + sockfd_to_user[sockfd] = running_index; + // free(user_stream_threads); + pthread_mutex_unlock(&mutex_user_data); +} +void *update_user_udpPort(int sockfd, int udpPort) { + pthread_mutex_lock(&mutex_user_data); + // get the user + user_t *user = &user_data[sockfd_to_user[sockfd]]; + // set the udpPort + user->udpPort = udpPort; + // start the stream thread, now that we have the udpPort + pthread_create(&user->streamThread, NULL, send_udp_packet_routine, (void *)sockfd_to_user[sockfd]); + pthread_mutex_unlock(&mutex_user_data); +} +void *update_user_station(int sockfd, int stationNum) { + pthread_mutex_lock(&mutex_user_data); + user_data[sockfd_to_user[sockfd]].stationNum = stationNum; + pthread_mutex_unlock(&mutex_user_data); +} +void *print_user_data(int index) { + printf("udpPort: %d, stationNum: %d, sockfd: %d, threadId:%d\n", + user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd, user_data[index].streamThread); +} + +void destroy_user(int sockfd) { + pthread_mutex_lock(&mutex_user_data); + // stop the thread streaming to the user + // TODO: close the FD in the stream thread + pthread_cancel(user_data[sockfd_to_user[sockfd]].streamThread); + // close(user_data[sockfd_to_user[sockfd]].udpPort); + // pthread_kill(user_data[sockfd_to_user[sockfd]].streamThread, SIGINT); + // "remove" the user from the list of user data + user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1, -1}; + // map sockfd to -1 + sockfd_to_user[sockfd] = -1; + // close(sockfd); + + pthread_mutex_unlock(&mutex_user_data); +} + + +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +void send_announce_reply(int fd, int station_num) { + char* file_path = station_data[station_num].filePath; + int len_file_path = strlen(file_path); + + char *send_buffer = malloc(len_file_path+2); + if (!send_buffer) { + perror("malloc"); + return; + } + send_buffer[0] = 3; + send_buffer[1] = len_file_path; + + memcpy(send_buffer + 2, file_path, len_file_path); + + // printf("buffer: %s\n", send_buffer); + + size_t bytes_to_send = len_file_path + 2; + if (send_all(fd, send_buffer, &bytes_to_send) == -1) + perror("send_all"); + // print the number of bytes sent + // printf("sent %d bytes\n", bytes_to_send); + + free(send_buffer); +} + +void send_invalid_command_reply(int fd, size_t message_size, char* message) { + char *send_buffer = malloc(message_size+2); + if (!send_buffer) { + perror("malloc"); + return; + } + + // type and payload size + send_buffer[0] = 4; + send_buffer[1] = message_size; + + memcpy(send_buffer + 2, message, message_size); + + // printf("buffer: %s\n", send_buffer); + + int bytes_to_send = message_size + 2; + if (send_all(fd, send_buffer, &bytes_to_send) == -1) + perror("send"); + // print the number of bytes sent + // printf("sent %d bytes\n", bytessent); + + free(send_buffer); +} + + +// Parses a buffer into tokens, from cs33 :) +int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]) { + const char *regex = " \n\t\f\r"; + char *current_token = strtok(buffer, regex); + if (current_token == NULL) return 0; + + for (int i = 0; current_token != NULL; i++) { + tokens[i] = current_token; + current_token = strtok(NULL, regex); + } + + return 1; +} + +// int send_all(int s, char *buf, int *len) +// { +// int total = 0; // how many bytes we've sent +// int bytesleft = *len; // how many we have left to send +// int n; + +// while(total < *len) { +// n = send(s, buf+total, bytesleft, 0); +// if (n == -1) { break; } +// total += n; +// bytesleft -= n; +// } + +// *len = total; // return number actually sent here + +// return n==-1?-1:0; // return -1 on failure, 0 on success +// } + +// int recv_all(int sock, char *buffer, int total_size) +// { +// int total_bytes_read = 0; +// int to_read = total_size; + +// char *ptr = buffer; + +// while (to_read > 0) { +// int bytes_read = recv(sock, ptr, to_read, 0); +// if (bytes_read <= 0) { +// if (bytes_read != 0) { +// perror("recv"); +// } +// return -1; +// } + +// to_read -= bytes_read; +// ptr += bytes_read; +// total_bytes_read += bytes_read; +// } + +// return total_bytes_read; +// } diff --git a/snowcast_control b/snowcast_control index d4a3ba1..df78cdb 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index d16a61e..c9e1f06 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 414117f..7f0e6a4 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 3434c81..918f71e 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index d18b1e8..3f0a8c4 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ diff --git a/snowcast_server_concurrent.c b/snowcast_server_concurrent.c deleted file mode 100644 index e0552cf..0000000 --- a/snowcast_server_concurrent.c +++ /dev/null @@ -1,791 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -#include "protocol.h" - -#define LINE_MAX 1024 -#define MAX_USERS 1000 -#define MAX_PATH 50 - -typedef struct station { - int seekIndex; - char* filePath; -} station_t; - -typedef struct user { - int udpPort; - int stationNum; - int sockfd; - pthread_t streamThread; -} user_t; - - -/* For safe condition variable usage, must use a boolean predicate and */ -/* a mutex with the condition. */ -int count = 0; -pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -pthread_mutex_t station_mutex = PTHREAD_MUTEX_INITIALIZER; - -const char *port; -int num_stations; - -int start_threads = 0; -int max_active_users = 0; - -pthread_mutex_t mutex_user_data = PTHREAD_MUTEX_INITIALIZER; -// array from index to user_data -user_t *user_data; -int sockfd_to_user[MAX_USERS]; - -// stations array pointer -station_t *station_data; - -void *send_udp_packet_routine(void* arg); -void *select_thread(void* arg); -void *synchronization_thread(void* arg); - -int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]); -void *print_info_routine(void *arg); - -void *get_in_addr(struct sockaddr *sa); - -void *init_user(int sockfd); -void *update_user_udpPort(int sockfd, int udpPort); -void *update_user_station(int sockfd, int stationNum); -void *print_user_data(int sockfd); -void destroy_user(int sockfd); - -void send_announce_reply(int fd, int station_num); -void send_invalid_command_reply(int fd, size_t message_size, char* message); - - -// void *load_file(void* arg); - -int main(int argc, char *argv[]) -{ - // threads to control reading files at chunks while the other threads sleep - // station_data = malloc(sizeof(station_t) * NUM_STATIONS); - // check and assign arguments - if (argc < 3) { - fprintf(stderr,"usage: ./snowcast_server [file 1] [file 2] ... \n"); - exit(1); - } - - port = argv[1]; - num_stations = argc - 2; - - // printf("port: %s\n", port); - // printf("num_stations: %d\n", num_stations); - - // init stations - size_t totalSize = 0; - // get size to malloc - for (int i = 2; i < argc; i++) - { - // printf("file: %s\n", argv[i]); - totalSize += sizeof(int) + strlen(argv[i]); - } - station_data = malloc(totalSize); - // assign the stations - for (int i = 2; i < argc; i++) - { - station_data[i - 2] = (station_t) { 0, argv[i]}; - } - - // print all indexes in station data - // for (int i = 0; i < num_stations; i++) - // { - // printf("station %d: %s\n", i, station_data[i].filePath); - // } - - // make array of user data - user_data = malloc(sizeof(user_t) * max_active_users); - if (!user_data) { perror("malloc"); return 1; } - - // make and start "select" thread that manages: - // 1) new connections, 2) requests from current connections, 3)cloing connections - pthread_t s_thread; - pthread_create(&s_thread, NULL, select_thread, NULL); - - // start syncchronization thread to broadcast stations - pthread_t sync_thread; - pthread_create(&sync_thread, NULL, synchronization_thread, NULL); - - // command line interface - char input[LINE_MAX]; - memset(input, 0, LINE_MAX); - - char *tokens[LINE_MAX / 2]; - while (read(STDIN_FILENO, input, LINE_MAX) > 0) { - // init tokens - memset(tokens, 0, (LINE_MAX / 2) * sizeof(char *)); - - // if 0, all whitespace - if (!parse(input, tokens)) - continue; - - char *command = tokens[0]; - // if q, shutdown! - if (!strcmp(command, "q")) { - printf("Exiting.\n"); - // TODO: exit better than break - break; - } - - // if p, print info - else if (!strcmp(command, "p")) { - // get the file descriptor - int print_fd = 0; - // see if there is a file path - char *output_file_path = tokens[1]; - if (output_file_path != NULL) - { - if ((print_fd = open(output_file_path, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU)) == -1) - { - perror("open"); - continue; - } - } else { - print_fd = STDOUT_FILENO; - } - // printf("print_fd: %d\n", print_fd); - pthread_t print_info_thread; - pthread_create(&print_info_thread, NULL, print_info_routine, print_fd); - // note - this file descriptor is closed in the thread - } - else if (!strcmp(command, "u")) - { - // print all user data - for (int i = 0; i < max_active_users; i++) - { - print_user_data(i); - } - } - } - - return 0; -} - -void write_int_to_fd(int fd, int n) { - int l = snprintf(NULL, 0, "%d", n); - char *num = malloc(l + 1); - if (!num) { perror("malloc"); return; } - - snprintf(num, l + 1, "%d", n); - if (write(fd, num, strlen(num)) == -1) { - perror("write"); - } - - - free(num); -} - -void *print_info_routine(void *arg) { - int print_fd = (int) arg; - // printf("thread print_fd: %d\n", print_fd); - // printf("num_stations: %d\n", num_stations); - for (int i = 0; i < num_stations; i++) { - write_int_to_fd(print_fd, i); - char *comma = ","; - write(print_fd, comma, strlen(comma)); - - // write file path - char* file_path = station_data[i].filePath; - write(print_fd, file_path, strlen(file_path)); - - for (int j = 0; j < max_active_users; j++) { - if (!user_data[j].sockfd || user_data[j].sockfd == -1) - continue; - if (user_data[j].stationNum == i) { - char *localhost_ip = ",127.0.0.1:"; - write(print_fd, localhost_ip, strlen(localhost_ip)); - // write udpPort - write_int_to_fd(print_fd, user_data[j].udpPort); - } - } - // wrtie new line - char *newline = "\n"; - write(print_fd, newline, strlen(newline)); - } - - if (print_fd != STDOUT_FILENO) close(print_fd); - return (NULL); -} - -int sendall(int udp_sockfd, char *buf, int *len, struct addrinfo *thread_res) -{ - int MAX_PACKET_SIZE = 512; - int total = 0; // how many bytes we've sent - int bytesleft = *len; // how many we have left to send - int n; - - while(total < *len) { - n = sendto(udp_sockfd, buf+total, MAX_PACKET_SIZE, 0, thread_res->ai_addr, thread_res->ai_addrlen); - // thread_res->ai_addr, thread_res->ai_addrlen)) == -1; - if (n == -1) { break; } - total += n; - bytesleft -= n; - } - - *len = total; // return number actually sent here - - return n==-1?-1:0; // return -1 on failure, 0 on success -} - - -/* Make the manager routine */ -void *send_udp_packet_routine(void *arg) { - // unpack args - int user_index = (int) arg; - // printf("thread : user_index: %d\n", user_index); - // print user data - // print_user_data(user_index); - - // declare vairables to be used - int did_work = 1; - pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; - int s; - int udp_sockfd; - struct addrinfo thread_hints, *thread_res, *thread_servinfo; - int error_code; - - // TODO: add error checking on these calls*** - - // setup hints - memset(&thread_hints, 0, sizeof thread_hints); - thread_hints.ai_family = AF_INET; // use IPv4 only - thread_hints.ai_socktype = SOCK_DGRAM; - thread_hints.ai_flags = AI_PASSIVE; // fill in my IP for me - - // setup the socket for client listener DATAGRAM (udp) - // cover the port integer to a string - int int_port = user_data[user_index].udpPort; - int length = snprintf( NULL, 0, "%d", int_port ); - char* port = malloc( length + 1 ); - if (!port) { perror("malloc"); return (NULL); } - snprintf( port, length + 1, "%d", int_port ); - sprintf(port, "%d", int_port); - - if (error_code = getaddrinfo(NULL, port, &thread_hints, &thread_servinfo) != 0) - { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error_code)); - return (NULL); - } - free(port); - - // loop through all the results and make a socket - for(thread_res = thread_servinfo; thread_res != NULL; thread_res = thread_res->ai_next) { - if ((udp_sockfd = socket(thread_res->ai_family, thread_res->ai_socktype, - thread_res->ai_protocol)) == -1) { - perror("talker: socket"); - continue; - } - break; - } - if (udp_sockfd == NULL) { - fprintf(stderr, "talker: failed to create socket\n"); - return (NULL); - } - - // bind(udp_sockfd, thread_res->ai_addr, thread_res->ai_addrlen); - - - // freeaddrinfo(thread_servinfo); - - while (1) { - // wait for - pthread_mutex_lock(&m); - did_work = 0; - while (!start_threads) - { - pthread_cond_wait(&cond, &m); - } - - int station_num = user_data[user_index].stationNum; - if (station_num == -1) { - did_work = 1; - } - - if (!did_work) { - // sendto a random string of data to the user - int station_num = user_data[user_index].stationNum; - char *data = station_data[station_num].filePath; - // printf("load data: thread %d \n", user_index); - - // get file path - char* file_path = station_data[station_num].filePath; - // get current seek chunk - int stream_fd = open(file_path, O_RDONLY); - if (stream_fd == -1) { - perror("open"); - return (NULL); - } - int current_chunk = station_data[station_num].seekIndex; - if (lseek(stream_fd, current_chunk, SEEK_SET) == -1) { - perror("fseek"); - return (NULL); - } - size_t BYTES_PER_SECOND = 16*1024; - // read 1000 bytes of the file - char file_buffer[BYTES_PER_SECOND]; - if (read(stream_fd, file_buffer, BYTES_PER_SECOND) == -1) { - perror("fread"); - return (NULL); - } - close(stream_fd); - // printf("send data: thread %d \n", user_index); - // int numbytes; - // if ((numbytes = sendto(udp_sockfd, data, strlen(data), 0, - // thread_res->ai_addr, thread_res->ai_addrlen)) == -1) { - // perror("talker: sendto"); - // return (NULL); - // } - // print the size of the file_buffer - // printf("size of file_buffer: %lu\n", sizeof(file_buffer)); - - int bytes_sent = sizeof(file_buffer); - if (sendall(udp_sockfd, file_buffer, &bytes_sent, thread_res) == -1) - { - perror("sendall"); - printf("We only sent %d bytes because of the error!\n", bytes_sent); - } - // printf("We sent all %d bytes!\n", bytes_sent); - - did_work = 1; - - - usleep(400000); - } - - pthread_mutex_unlock(&m); - - usleep(100000); - } - return NULL; -} - -void *send_announce_routine(void *arg) { - // unpack args - int station_num = (int) arg; - // send the announce messages - for (int i = 0; i < max_active_users; i++) - { - // if (user_data[i].streamThread == NULL) { - // break; - // } - if (user_data[i].sockfd == 0 || user_data[i].sockfd == -1) { - continue; - } - // print_user_data(i); - // update the station of each user - if (user_data[i].stationNum == station_num) - { - // printf("sending announce to user %d\n", i); - send_announce_reply(user_data[i].sockfd, station_num); - } - } -} - -void *synchronization_thread(void *arg) { - int c = 0; - while (1) - { - start_threads = 1; - // printf("\nbroadcast %d\n", c++); - pthread_cond_broadcast(&cond); - usleep(2000); - start_threads = 0; - // printf("before loop"); - // update file seek index for each station - size_t BYTES_PER_SECOND = 16*1024; - // print num_stations - // printf("num_stations: %d\n", num_stations); - for (int i = 0; i < num_stations; i++) - { - // printf("checking station %d\n", i); - // get size of file - struct stat f_info; - // int file_fd = open(station_data[i].filePath, O_RDONLY); - // if (file_fd == -1) { - // perror("open"); - // return (NULL); - // } - if (stat(station_data[i].filePath, &f_info) == -1) { - perror("fstat"); - return (NULL); - } - - size_t size = f_info.st_size; - - // fclose(file_fd); - // if (size == -1) { - // perror("ftell"); - // return (NULL); - // } - station_data[i].seekIndex += BYTES_PER_SECOND; - // if the seek index is greater than the size of the file, reset it - if (station_data[i].seekIndex >= size) - { - station_data[i].seekIndex = 0; - // printf("resetting station %d\n", i); - - pthread_t send_announce_thread; - pthread_create(&send_announce_thread, NULL, send_announce_routine, (void *)i); - } - } - - - usleep(2000); - usleep(1000000-4000); - } -} - -void *select_thread(void *arg) { - fd_set master; // master file descriptor list - fd_set read_fds; // temp file descriptor list for select() - int fdmax; // maximum file descriptor number - - int listener; // listening socket descriptor - int newfd; // newly accept()ed socket descriptor - struct sockaddr_storage remoteaddr; // client address - socklen_t addrlen; - - char buf[256]; // buffer for client data - int nbytes; - - - char remoteIP[INET6_ADDRSTRLEN]; - - int yes=1; // for setsockopt() SO_REUSEADDR, below - int i, j, rv; - - struct addrinfo hints, *ai, *p; - - // const char* port = argv[1]; - - FD_ZERO(&master); // clear the master and temp sets - FD_ZERO(&read_fds); - - // LISTENER: get us a socket and bind it - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) { - fprintf(stderr, "snowcast_server: %s\n", gai_strerror(rv)); - exit(1); - } - - for(p = ai; p != NULL; p = p->ai_next) { - listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (listener < 0) { - continue; - } - - // lose the pesky "address already in use" error message - setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); - - if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) { - close(listener); - continue; - } - - break; - } - - // if we got here, it means we didn't get bound - if (p == NULL) { - fprintf(stderr, "snowcast_server: failed to bind\n"); - exit(2); - } - - freeaddrinfo(ai); // all done with this - - // listen - if (listen(listener, 10) == -1) { - perror("listen"); - exit(3); - } - - // add the listener to the master set - FD_SET(listener, &master); - - // keep track of the biggest file descriptor - fdmax = listener; // so far, it's this one - - while(1) { - read_fds = master; // copy it - if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { - perror("select"); - exit(4); - } - - // run through the existing connections looking for data to read - for(i = 0; i <= fdmax; i++) { - if (FD_ISSET(i, &read_fds)) { // we got one!! - if (i == listener) { - // handle new connections - addrlen = sizeof remoteaddr; - newfd = accept(listener, - (struct sockaddr *)&remoteaddr, - &addrlen); - - if (newfd == -1) { - perror("accept"); - } else { - FD_SET(newfd, &master); // add to master set - if (newfd > fdmax) { // keep track of the max - fdmax = newfd; - } - // printf("selectserver: new connection from %s on " - // "socket %d\n.", - // inet_ntop(remoteaddr.ss_family, - // get_in_addr((struct sockaddr*)&remoteaddr), - // remoteIP, INET6_ADDRSTRLEN), - // newfd); - // init user with this newfd - init_user(newfd); - } - } else { - // handle data from a client - struct Command command; - if ((nbytes = recv(i, (char*)&command, sizeof(struct Command), 0)) <= 0) { - // got error or connection closed by client - if (nbytes == 0) { - // connection closed - // printf("selectserver: socket %d hung up\n", i); - } else { - perror("recv"); - } - close(i); // bye! - FD_CLR(i, &master); // remove from master set - // remove user from data structures - destroy_user(i); - } else { - // we got some data from a client - if (command.commandType == 0) { - // hello message with udpPort - // printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); - // update udp port of user - update_user_udpPort(i, ntohs(command.number)); - - // send the welcome message to client - struct Welcome welcome; - welcome.replyType = 2; - welcome.numStations = htons(num_stations); - int numbytes; - if ((numbytes=send(i, &welcome, sizeof(struct Welcome), 0)) == -1) - perror("send"); - } - else if (command.commandType == 1) { - // check if user has a udpPort - if (user_data[sockfd_to_user[i]].udpPort == -1) { - // send back in invalid command - char * message = "Must send Hello message first."; - send_invalid_command_reply(i, strlen(message), message); - // drop connection upon invalid command - close(i); - FD_CLR(i, &master); - destroy_user(i); - continue; - } - - int station_num = ntohs(command.number); - // printf("station_num: %d\n", station_num); - if (station_num >= num_stations || station_num < 0) { - // send back in invalid command - char * message = "Station number out of range."; - send_invalid_command_reply(i, strlen(message), message); - // drop connection upon invalid command - close(i); - FD_CLR(i, &master); - destroy_user(i); - continue; - } - - // printf("setting station to %d\n", ntohs(command.number)); - // update station of user - update_user_station(i, ntohs(command.number)); - send_announce_reply(i, station_num); - } - else { - // send back in invalid command - char * message = "Invalid command"; - send_invalid_command_reply(i, strlen(message), message); - - // drop connection upon invalid command - close(i); - FD_CLR(i, &master); - destroy_user(i); - } - } - } // END handle data from client - } // END got new incoming connection - } // END looping through file descriptors - - } // END for(;;)--and you thought it would never end! -} - -void *init_user(int sockfd) { - // add the user to the list of user data - pthread_mutex_lock(&mutex_user_data); - // this is to save memory space. - // in general, the displacement of 4 is where a user "used to be" - // int user_index = max_active_users++; - // int running_index = 0; - // while(running_index < max_active_users) - // { - // if (user_data[running_index++].sockfd == -1) - // { - // user_index = running_index; - // break; - // } - // // printf("reusing memory\n"); - // } - int running_index = 0; - while(running_index < max_active_users) { - if (user_data[running_index].sockfd == -1) { - break; - } - running_index++; - } - if (running_index == max_active_users) { - // printf("reached max active users\n"); - // printf("making new memory\n"); - max_active_users++; - // TODO: FIX SO THAT IT USES CURRENT USERS, NOT MAX_ACTIVE_USERS FOT THE RESIZE - user_t *more_users = realloc(user_data, sizeof(user_t) * max_active_users); - if (!more_users) { perror("realloc"); exit(1); } - user_data = more_users; - } - - - // map TCP sockfd to this user index - user_data[running_index] = (user_t){-1, -1, sockfd, -1}; - sockfd_to_user[sockfd] = running_index; - // free(user_stream_threads); - pthread_mutex_unlock(&mutex_user_data); -} -void *update_user_udpPort(int sockfd, int udpPort) { - pthread_mutex_lock(&mutex_user_data); - // get the user - user_t *user = &user_data[sockfd_to_user[sockfd]]; - // set the udpPort - user->udpPort = udpPort; - // start the stream thread, now that we have the udpPort - pthread_create(&user->streamThread, NULL, send_udp_packet_routine, (void *)sockfd_to_user[sockfd]); - pthread_mutex_unlock(&mutex_user_data); -} -void *update_user_station(int sockfd, int stationNum) { - pthread_mutex_lock(&mutex_user_data); - user_data[sockfd_to_user[sockfd]].stationNum = stationNum; - pthread_mutex_unlock(&mutex_user_data); -} -void *print_user_data(int index) { - printf("udpPort: %d, stationNum: %d, sockfd: %d, threadId:%d\n", - user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd, user_data[index].streamThread); -} - -void destroy_user(int sockfd) { - pthread_mutex_lock(&mutex_user_data); - // stop the thread streaming to the user - // TODO: close the FD in the stream thread - pthread_cancel(user_data[sockfd_to_user[sockfd]].streamThread); - // close(user_data[sockfd_to_user[sockfd]].udpPort); - // pthread_kill(user_data[sockfd_to_user[sockfd]].streamThread, SIGINT); - // "remove" the user from the list of user data - user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1, -1}; - // map sockfd to -1 - sockfd_to_user[sockfd] = -1; - // close(sockfd); - - pthread_mutex_unlock(&mutex_user_data); -} - - -void *get_in_addr(struct sockaddr *sa) -{ - if (sa->sa_family == AF_INET) { - return &(((struct sockaddr_in*)sa)->sin_addr); - } - - return &(((struct sockaddr_in6*)sa)->sin6_addr); -} - -void send_announce_reply(int fd, int station_num) { - char* file_path = station_data[station_num].filePath; - int len_file_path = strlen(file_path); - - char *send_buffer = malloc(len_file_path+2); - if (!send_buffer) { - perror("malloc"); - return; - } - send_buffer[0] = 3; - send_buffer[1] = len_file_path; - - memcpy(send_buffer + 2, file_path, len_file_path); - - // printf("buffer: %s\n", send_buffer); - - int bytessent; - if ((bytessent = send(fd, send_buffer, len_file_path + 2, 0)) == -1) - perror("send"); - // print the number of bytes sent - // printf("sent %d bytes\n", bytessent); - - free(send_buffer); -} - -void send_invalid_command_reply(int fd, size_t message_size, char* message) { - char *send_buffer = malloc(message_size+2); - if (!send_buffer) { - perror("malloc"); - return; - } - - // type and payload size - send_buffer[0] = 4; - send_buffer[1] = message_size; - - memcpy(send_buffer + 2, message, message_size); - - // printf("buffer: %s\n", send_buffer); - - int bytessent; - if ((bytessent = send(fd, send_buffer, message_size + 2, 0)) == -1) - perror("send"); - // print the number of bytes sent - // printf("sent %d bytes\n", bytessent); - - free(send_buffer); -} - - -// Parses a buffer into tokens, from cs33 :) -int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]) { - const char *regex = " \n\t\f\r"; - char *current_token = strtok(buffer, regex); - if (current_token == NULL) return 0; - - for (int i = 0; current_token != NULL; i++) { - tokens[i] = current_token; - current_token = strtok(NULL, regex); - } - - return 1; -} -- cgit v1.2.3-70-g09d2 From dc5d15064b90f9c25b1b47503e4074dba063db70 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Wed, 20 Sep 2023 23:49:07 -0400 Subject: fix the set station byte reading --- server.c | 50 ++++++++++++++------- snowcast_control | Bin 35565 -> 35565 bytes snowcast_listener | Bin 34654 -> 34654 bytes snowcast_server | Bin 56124 -> 56124 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 27185 -> 27319 bytes 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/server.c b/server.c index 837432a..59cd4e7 100644 --- a/server.c +++ b/server.c @@ -560,8 +560,9 @@ void *select_thread(void *arg) { } } else { // handle data from a client - struct Command command; - if ((nbytes = recv(i, (char*)&command, sizeof(struct Command), 0)) <= 0) { + uint8_t command_type = -1; + if ((nbytes = recv(i, &command_type, 1, 0)) <= 0) + { // got error or connection closed by client if (nbytes == 0) { // connection closed @@ -573,13 +574,24 @@ void *select_thread(void *arg) { FD_CLR(i, &master); // remove from master set // remove user from data structures destroy_user(i); - } else { + } + else + { // we got some data from a client - if (command.commandType == 0) { - // hello message with udpPort - // printf("udpPort (from Hello) for new connection is %d.\n", ntohs(command.number)); + if (command_type == 0) { // we got a hello message + + // get the udp port + uint16_t udp_port = -1; + int bytes_to_read = sizeof(uint16_t); + if (recv_all(i, &udp_port, &bytes_to_read) == -1) { + perror("recv_all"); + exit(1); + } + udp_port = ntohs(udp_port); + + printf("udpPort (from Hello) for new connection is %d.\n", udp_port); // update udp port of user - update_user_udpPort(i, ntohs(command.number)); + update_user_udpPort(i, udp_port); // send the welcome message to client struct Welcome welcome; @@ -589,11 +601,11 @@ void *select_thread(void *arg) { if (send_all(i, &welcome, &bytes_to_send) == -1) perror("send_all"); } - else if (command.commandType == 1) { + else if (command_type == 1) { // we got a setStation command // check if user has a udpPort if (user_data[sockfd_to_user[i]].udpPort == -1) { // send back in invalid command - char * message = "Must send Hello message first."; + char * message = "must send Hello message first"; send_invalid_command_reply(i, strlen(message), message); // drop connection upon invalid command close(i); @@ -602,11 +614,19 @@ void *select_thread(void *arg) { continue; } - int station_num = ntohs(command.number); + // get the station number + uint16_t station_number = -1; + int bytes_to_read = sizeof(uint16_t); + if (recv_all(i, &station_number, &bytes_to_read) == -1) { + perror("recv_all"); + exit(1); + } + station_number = ntohs(station_number); + // printf("station_num: %d\n", station_num); - if (station_num >= num_stations || station_num < 0) { + if (station_number >= num_stations || station_number < 0) { // send back in invalid command - char * message = "Station number out of range."; + char * message = "station number out of range"; send_invalid_command_reply(i, strlen(message), message); // drop connection upon invalid command close(i); @@ -617,12 +637,12 @@ void *select_thread(void *arg) { // printf("setting station to %d\n", ntohs(command.number)); // update station of user - update_user_station(i, ntohs(command.number)); - send_announce_reply(i, station_num); + update_user_station(i, station_number); + send_announce_reply(i, station_number); } else { // send back in invalid command - char * message = "Invalid command"; + char * message = "invalid command"; send_invalid_command_reply(i, strlen(message), message); // drop connection upon invalid command diff --git a/snowcast_control b/snowcast_control index df78cdb..ebf8c93 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 7f0e6a4..b8357dd 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 918f71e..6c3f2dc 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 3f0a8c4..6f668a7 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 433f6eb3a54881913286aa620db93c003c436c16 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Thu, 21 Sep 2023 00:00:13 -0400 Subject: good stopping point. added some more edge cases. --- server.c | 40 +++++++++++++-------- snowcast_control | Bin 35565 -> 35565 bytes snowcast_listener | Bin 34654 -> 34654 bytes snowcast_server | Bin 56124 -> 56124 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 27319 -> 27644 bytes 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/server.c b/server.c index 59cd4e7..f7697a3 100644 --- a/server.c +++ b/server.c @@ -578,7 +578,7 @@ void *select_thread(void *arg) { else { // we got some data from a client - if (command_type == 0) { // we got a hello message + if (command_type == 0) { // we got a Hello commmand // get the udp port uint16_t udp_port = -1; @@ -589,7 +589,19 @@ void *select_thread(void *arg) { } udp_port = ntohs(udp_port); - printf("udpPort (from Hello) for new connection is %d.\n", udp_port); + // check if user has a udpPort, if so, close connection + if (user_data[sockfd_to_user[i]].udpPort != -1) { + // send back in invalid command + char * message = "must not sent more than one Hello message"; + send_invalid_command_reply(i, strlen(message), message); + // drop connection upon invalid command + close(i); + FD_CLR(i, &master); + destroy_user(i); + continue; + } + + // printf("udpPort (from Hello) for new connection is %d.\n", udp_port); // update udp port of user update_user_udpPort(i, udp_port); @@ -601,8 +613,17 @@ void *select_thread(void *arg) { if (send_all(i, &welcome, &bytes_to_send) == -1) perror("send_all"); } - else if (command_type == 1) { // we got a setStation command - // check if user has a udpPort + else if (command_type == 1) { // we got a SetStation command + // get the station number + uint16_t station_number = -1; + int bytes_to_read = sizeof(uint16_t); + if (recv_all(i, &station_number, &bytes_to_read) == -1) { + perror("recv_all"); + exit(1); + } + station_number = ntohs(station_number); + + // check if user has a udpPort to stream to if (user_data[sockfd_to_user[i]].udpPort == -1) { // send back in invalid command char * message = "must send Hello message first"; @@ -614,16 +635,7 @@ void *select_thread(void *arg) { continue; } - // get the station number - uint16_t station_number = -1; - int bytes_to_read = sizeof(uint16_t); - if (recv_all(i, &station_number, &bytes_to_read) == -1) { - perror("recv_all"); - exit(1); - } - station_number = ntohs(station_number); - - // printf("station_num: %d\n", station_num); + // check if station num is in range if (station_number >= num_stations || station_number < 0) { // send back in invalid command char * message = "station number out of range"; diff --git a/snowcast_control b/snowcast_control index ebf8c93..4369180 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index b8357dd..c8765c2 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 6c3f2dc..f3e7928 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 6f668a7..79dd8f6 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 9ba49f755e152d0996a43e8da7d146b8d2069051 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Thu, 21 Sep 2023 07:06:14 +0000 Subject: add timeout --- client.c | 3 ++ listener.c | 11 +------ protocol.c | 26 +++++++++++++++++ server.c | 32 ++++++++++++++------- snowcast_control | Bin 35565 -> 22384 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 14770 -> 15157 bytes snowcast_listener | Bin 34654 -> 19120 bytes snowcast_server | Bin 56124 -> 44360 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 27644 -> 28332 bytes 9 files changed, 51 insertions(+), 21 deletions(-) diff --git a/client.c b/client.c index 852e7ff..760b494 100644 --- a/client.c +++ b/client.c @@ -170,6 +170,8 @@ void *reply_thread_routine(void* args) { exit(1); } char *song_name = malloc(string_size); + if(song_name == NULL) { perror("malloc in song name"); } + int bytes_to_read = string_size; if (recv_all(sockfd, song_name, &bytes_to_read) == -1) { perror("recv_all"); @@ -186,6 +188,7 @@ void *reply_thread_routine(void* args) { exit(1); } char *message = malloc(string_size); + if(message == NULL) { perror("malloc in message"); } int bytes_to_read = string_size; if (recv_all(sockfd, message, &bytes_to_read) == -1) { perror("recv_all"); diff --git a/listener.c b/listener.c index 7bb8afe..9cf1c00 100644 --- a/listener.c +++ b/listener.c @@ -34,7 +34,6 @@ int main(int argc, char *argv[]) int rv; int numbytes; struct sockaddr_storage their_addr; - char buf[MAXBUFLEN]; socklen_t addr_len; char s[INET6_ADDRSTRLEN]; @@ -82,6 +81,7 @@ int main(int argc, char *argv[]) int count = 0; + char buf[MAXBUFLEN]; while(1) { // printf("\nlistener: waiting to recvfrom... %d times\n", count++); @@ -91,15 +91,6 @@ int main(int argc, char *argv[]) perror("recvfrom"); exit(1); } - // buf[numbytes] = '\0'; - - //printf("listener: got packet from %s\n", - // inet_ntop(their_addr.ss_family, - // get_in_addr((struct sockaddr *)&their_addr), - // s, sizeof s)); - //printf("listener: packet is %d bytes long\n", numbytes); - //buf[numbytes] = '\0'; - //printf("listener: packet contains \"%s\"\n", buf); // print the size write(STDOUT_FILENO, buf, numbytes); diff --git a/protocol.c b/protocol.c index 864afd8..d350221 100644 --- a/protocol.c +++ b/protocol.c @@ -3,8 +3,17 @@ #include "protocol.h" +#define TIMEOUT 100000 // 100ms in microseconds + int send_all(int sock, char *buf, int *len) { + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + // if (setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, + // sizeof timeout) < 0) + // perror("setsockopt failed\n"); + int total = 0; // how many bytes we've sent int bytesleft = *len; // how many we have left to send int n; @@ -23,17 +32,34 @@ int send_all(int sock, char *buf, int *len) int recv_all(int sock, char *buf, int *len) { + // setup the timeout on the socket + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = TIMEOUT; + if (setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof timeout) < 0) + perror("setsockopt failed\n"); + + // printf("start: %ld\n", start); int total = 0; // how many bytes we've sent int bytesleft = *len; // how many we have left to send int n; while(total < *len) { n = recv(sock, buf+total, bytesleft, 0); + // start = time(NULL); if (n == -1) { break; } total += n; bytesleft -= n; } + timeout.tv_sec = 0; + timeout.tv_usec = 0; + if (setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof timeout) < 0) + perror("setsockopt failed\n"); + + *len = total; // return number actually sent here return n==-1?-1:0; // return -1 on failure, 0 on success diff --git a/server.c b/server.c index f7697a3..c2d8208 100644 --- a/server.c +++ b/server.c @@ -73,7 +73,7 @@ void send_invalid_command_reply(int fd, size_t message_size, char* message); // void *load_file(void* arg); -int main(int argc, char *argv[]) +main(int argc, char *argv[]) { // threads to control reading files at chunks while the other threads sleep // station_data = malloc(sizeof(station_t) * NUM_STATIONS); @@ -98,6 +98,7 @@ int main(int argc, char *argv[]) totalSize += sizeof(int) + strlen(argv[i]); } station_data = malloc(totalSize); + if (!station_data) { perror("malloc station data"); return 1; } // assign the stations for (int i = 2; i < argc; i++) { @@ -112,7 +113,7 @@ int main(int argc, char *argv[]) // make array of user data user_data = malloc(sizeof(user_t) * max_active_users); - if (!user_data) { perror("malloc"); return 1; } + if (!user_data) { perror("malloc userdata"); return 1; } // make and start "select" thread that manages: // 1) new connections, 2) requests from current connections, 3)cloing connections @@ -181,7 +182,7 @@ int main(int argc, char *argv[]) void write_int_to_fd(int fd, int n) { int l = snprintf(NULL, 0, "%d", n); char *num = malloc(l + 1); - if (!num) { perror("malloc"); return; } + if (!num) { perror("malloc write to fd"); return; } snprintf(num, l + 1, "%d", n); if (write(fd, num, strlen(num)) == -1) { @@ -274,8 +275,8 @@ void *send_udp_packet_routine(void *arg) { int int_port = user_data[user_index].udpPort; int length = snprintf( NULL, 0, "%d", int_port ); char* port = malloc( length + 1 ); - if (!port) { perror("malloc"); return (NULL); } - snprintf( port, length + 1, "%d", int_port ); + if (!port) { perror("malloc on port"); return (NULL); } + snprintf(port, length + 1, "%d", int_port); sprintf(port, "%d", int_port); if (error_code = getaddrinfo(NULL, port, &thread_hints, &thread_servinfo) != 0) @@ -585,7 +586,10 @@ void *select_thread(void *arg) { int bytes_to_read = sizeof(uint16_t); if (recv_all(i, &udp_port, &bytes_to_read) == -1) { perror("recv_all"); - exit(1); + close(i); + FD_CLR(i, &master); + destroy_user(i); + continue; } udp_port = ntohs(udp_port); @@ -615,11 +619,15 @@ void *select_thread(void *arg) { } else if (command_type == 1) { // we got a SetStation command // get the station number + uint16_t station_number = -1; int bytes_to_read = sizeof(uint16_t); if (recv_all(i, &station_number, &bytes_to_read) == -1) { perror("recv_all"); - exit(1); + close(i); + FD_CLR(i, &master); + destroy_user(i); + continue; } station_number = ntohs(station_number); @@ -703,7 +711,6 @@ void *init_user(int sockfd) { user_data = more_users; } - // map TCP sockfd to this user index user_data[running_index] = (user_t){-1, -1, sockfd, -1}; sockfd_to_user[sockfd] = running_index; @@ -734,7 +741,10 @@ void destroy_user(int sockfd) { pthread_mutex_lock(&mutex_user_data); // stop the thread streaming to the user // TODO: close the FD in the stream thread - pthread_cancel(user_data[sockfd_to_user[sockfd]].streamThread); + pthread_t thread = user_data[sockfd_to_user[sockfd]].streamThread; + if (thread != -1) { + pthread_cancel(thread); + } // close(user_data[sockfd_to_user[sockfd]].udpPort); // pthread_kill(user_data[sockfd_to_user[sockfd]].streamThread, SIGINT); // "remove" the user from the list of user data @@ -762,7 +772,7 @@ void send_announce_reply(int fd, int station_num) { char *send_buffer = malloc(len_file_path+2); if (!send_buffer) { - perror("malloc"); + perror("malloc in send announce"); return; } send_buffer[0] = 3; @@ -784,7 +794,7 @@ void send_announce_reply(int fd, int station_num) { void send_invalid_command_reply(int fd, size_t message_size, char* message) { char *send_buffer = malloc(message_size+2); if (!send_buffer) { - perror("malloc"); + perror("malloc in send ancalid command"); return; } diff --git a/snowcast_control b/snowcast_control index 4369180..2b99cdb 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index c9e1f06..3a596f0 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index c8765c2..7accc61 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index f3e7928..f829e64 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 79dd8f6..2428c04 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From ebac9a74847dfbffa85e0fb2c184abfeb4aea06f Mon Sep 17 00:00:00 2001 From: sotech117 Date: Thu, 21 Sep 2023 08:03:14 +0000 Subject: death with handshake first --- client.c | 2 + server.c | 83 ++++++++++++++++----- snowcast_control | Bin 22384 -> 22384 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 15157 -> 15199 bytes .../Contents/Resources/DWARF/snowcast_listener | Bin 11651 -> 11649 bytes snowcast_server | Bin 44360 -> 44576 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 28332 -> 28763 bytes 7 files changed, 67 insertions(+), 18 deletions(-) diff --git a/client.c b/client.c index 760b494..74a3f5d 100644 --- a/client.c +++ b/client.c @@ -93,6 +93,8 @@ int main(int argc, char *argv[]) usleep(1000); + // sleep(1); + struct Hello hello; hello.commandType = 0; // convert updPort to an int diff --git a/server.c b/server.c index c2d8208..ed92486 100644 --- a/server.c +++ b/server.c @@ -546,10 +546,36 @@ void *select_thread(void *arg) { if (newfd == -1) { perror("accept"); } else { - FD_SET(newfd, &master); // add to master set - if (newfd > fdmax) { // keep track of the max - fdmax = newfd; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = TIMEOUT; + if (setsockopt(newfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + perror("setsockopt"); } + + uint8_t command_type = -1; + if ((nbytes = recv(newfd, &command_type, 1, 0)) <= 0) + { + // got error or connection closed by client + if (nbytes == 0) { + // connection closed + // printf("selectserver: socket %d hung up\n", i); + } else { + perror("recv"); + } + // remove user from data structures + close(newfd); + // destroy_user(i); + continue; + } + + if (command_type != 0) { + char * message = "must send a Hello message first"; + send_invalid_command_reply(newfd, strlen(message), message); + close(newfd); + continue; + } + // printf("selectserver: new connection from %s on " // "socket %d\n.", // inet_ntop(remoteaddr.ss_family, @@ -557,8 +583,43 @@ void *select_thread(void *arg) { // remoteIP, INET6_ADDRSTRLEN), // newfd); // init user with this newfd + + // get the udp port + uint16_t udp_port = -1; + int bytes_to_read = sizeof(uint16_t); + if (recv_all(newfd, &udp_port, &bytes_to_read) == -1) { + perror("recv_all"); + close(newfd); + // destroy_user(i); + continue; + } + udp_port = ntohs(udp_port); + + // printf("udpPort (from Hello) for new connection is %d.\n", udp_port); + // update udp port of user + + // add a timeout to the socket + // struct timeval tv; + // tv.tv_sec = 0; + // tv.tv_usec = 0; + // if (setsockopt(newfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + // perror("setsockopt"); + // } + FD_SET(newfd, &master); // add to master set + if (newfd > fdmax) { // keep track of the max + fdmax = newfd; + } init_user(newfd); - } + update_user_udpPort(newfd, udp_port); + + // send the welcome message to client + struct Welcome welcome; + welcome.replyType = 2; + welcome.numStations = htons(num_stations); + int bytes_to_send = sizeof(struct Welcome); + if (send_all(newfd, &welcome, &bytes_to_send) == -1) + perror("send_all"); + } } else { // handle data from a client uint8_t command_type = -1; @@ -591,9 +652,7 @@ void *select_thread(void *arg) { destroy_user(i); continue; } - udp_port = ntohs(udp_port); - // check if user has a udpPort, if so, close connection if (user_data[sockfd_to_user[i]].udpPort != -1) { // send back in invalid command char * message = "must not sent more than one Hello message"; @@ -604,18 +663,6 @@ void *select_thread(void *arg) { destroy_user(i); continue; } - - // printf("udpPort (from Hello) for new connection is %d.\n", udp_port); - // update udp port of user - update_user_udpPort(i, udp_port); - - // send the welcome message to client - struct Welcome welcome; - welcome.replyType = 2; - welcome.numStations = htons(num_stations); - int bytes_to_send = sizeof(struct Welcome); - if (send_all(i, &welcome, &bytes_to_send) == -1) - perror("send_all"); } else if (command_type == 1) { // we got a SetStation command // get the station number diff --git a/snowcast_control b/snowcast_control index 2b99cdb..e8e8ad0 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index 3a596f0..43f119b 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener b/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener index b6206fa..f811857 100644 Binary files a/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener and b/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index f829e64..2c41418 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 2428c04..df5780d 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From dc5fd35fc23e79edd8a972e8c60f54190eaba4af Mon Sep 17 00:00:00 2001 From: sotech117 Date: Thu, 21 Sep 2023 04:25:54 -0400 Subject: optimizations and cleanup function --- server.c | 29 +++++++++++++++++---- snowcast_control | Bin 22384 -> 35613 bytes snowcast_listener | Bin 19120 -> 34654 bytes snowcast_server | Bin 44576 -> 56428 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 28763 -> 29417 bytes 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/server.c b/server.c index ed92486..63edf36 100644 --- a/server.c +++ b/server.c @@ -44,11 +44,12 @@ int num_stations; int start_threads = 0; int max_active_users = 0; +int max_sockfd = 0; pthread_mutex_t mutex_user_data = PTHREAD_MUTEX_INITIALIZER; // array from index to user_data user_t *user_data; -int sockfd_to_user[MAX_USERS]; +int *sockfd_to_user; // stations array pointer station_t *station_data; @@ -114,6 +115,8 @@ main(int argc, char *argv[]) // make array of user data user_data = malloc(sizeof(user_t) * max_active_users); if (!user_data) { perror("malloc userdata"); return 1; } + sockfd_to_user = malloc(sizeof(int) * max_active_users); + if (!sockfd_to_user) { perror("malloc sockfd to user"); return 1; } // make and start "select" thread that manages: // 1) new connections, 2) requests from current connections, 3)cloing connections @@ -245,6 +248,12 @@ int send_all_udp(int udp_sockfd, char *buf, int *len, struct addrinfo *thread_re return n==-1?-1:0; // return -1 on failure, 0 on success } +void udp_port_cleanup_handler(void *arg) +{ + int sockfd = (int) arg; + printf("Called clean-up handler, closing socket %d\n", sockfd); + close(sockfd); +} /* Make the manager routine */ void *send_udp_packet_routine(void *arg) { @@ -303,9 +312,10 @@ void *send_udp_packet_routine(void *arg) { // bind(udp_sockfd, thread_res->ai_addr, thread_res->ai_addrlen); - // freeaddrinfo(thread_servinfo); - - while (1) { + // freeaddrinfo(thread_servinfo) + pthread_cleanup_push(udp_port_cleanup_handler, (void *)udp_sockfd); + while (1) + { // wait for pthread_mutex_lock(&m); did_work = 0; @@ -374,6 +384,8 @@ void *send_udp_packet_routine(void *arg) { usleep(100000); } + + pthread_cleanup_pop(1); return NULL; } @@ -741,6 +753,14 @@ void *init_user(int sockfd) { // } // // printf("reusing memory\n"); // } + if(sockfd > max_sockfd) { + max_sockfd = sockfd; + int * more_sockfd_to_user = realloc(sockfd_to_user, sizeof(int) * (max_sockfd + 1)); + if (!more_sockfd_to_user) { perror("realloc"); exit(1); } + sockfd_to_user = more_sockfd_to_user; + } + + int running_index = 0; while(running_index < max_active_users) { if (user_data[running_index].sockfd == -1) { @@ -752,7 +772,6 @@ void *init_user(int sockfd) { // printf("reached max active users\n"); // printf("making new memory\n"); max_active_users++; - // TODO: FIX SO THAT IT USES CURRENT USERS, NOT MAX_ACTIVE_USERS FOT THE RESIZE user_t *more_users = realloc(user_data, sizeof(user_t) * max_active_users); if (!more_users) { perror("realloc"); exit(1); } user_data = more_users; diff --git a/snowcast_control b/snowcast_control index e8e8ad0..2ddfb3a 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 7accc61..ea9929a 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 2c41418..431fa68 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index df5780d..0c8d053 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From c8ea8ec6748e030e00ba8b4a4ee0d58c58a87b1c Mon Sep 17 00:00:00 2001 From: sotech117 Date: Thu, 21 Sep 2023 04:52:03 -0400 Subject: small improvments --- client.c | 4 +- listener.c | 5 +- mp3/chipOffTheBlock.mp3 | Bin 4477733 -> 0 bytes mp3/test.mp3 | Bin 0 -> 3152665 bytes server.c | 157 ++------------------- snowcast_control | Bin 35613 -> 35613 bytes .../Contents/Resources/DWARF/snowcast_control | Bin 15199 -> 15199 bytes snowcast_listener | Bin 34654 -> 34654 bytes .../Contents/Resources/DWARF/snowcast_listener | Bin 11649 -> 11649 bytes snowcast_server | Bin 56428 -> 56428 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 29417 -> 29386 bytes 11 files changed, 12 insertions(+), 154 deletions(-) delete mode 100644 mp3/chipOffTheBlock.mp3 create mode 100644 mp3/test.mp3 diff --git a/client.c b/client.c index 74a3f5d..083526f 100644 --- a/client.c +++ b/client.c @@ -84,7 +84,6 @@ int main(int argc, char *argv[]) inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s); - // printf("client: connecting to %s\n", s); freeaddrinfo(servinfo); // all done with this structure @@ -107,7 +106,6 @@ int main(int argc, char *argv[]) // CONSIDER: could recieve the welcome message here - char input[LINE_MAX]; printf("Enter a number to change to it's station. Click q to end stream.\n"); while (1) { @@ -202,7 +200,7 @@ void *reply_thread_routine(void* args) { exit(1); } - printf("Lost connection to server. Exiting."); + printf("Lost connection to server. Exiting.\n"); close(sockfd); exit(1); } diff --git a/listener.c b/listener.c index 9cf1c00..04e3030 100644 --- a/listener.c +++ b/listener.c @@ -83,16 +83,13 @@ int main(int argc, char *argv[]) char buf[MAXBUFLEN]; while(1) { - // printf("\nlistener: waiting to recvfrom... %d times\n", count++); - addr_len = sizeof their_addr; if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN , 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) { perror("recvfrom"); exit(1); } - - // print the size + // print the buffer write(STDOUT_FILENO, buf, numbytes); memset(buf, 0, MAXBUFLEN); diff --git a/mp3/chipOffTheBlock.mp3 b/mp3/chipOffTheBlock.mp3 deleted file mode 100644 index c06c05f..0000000 Binary files a/mp3/chipOffTheBlock.mp3 and /dev/null differ diff --git a/mp3/test.mp3 b/mp3/test.mp3 new file mode 100644 index 0000000..9f4f996 Binary files /dev/null and b/mp3/test.mp3 differ diff --git a/server.c b/server.c index 63edf36..7246885 100644 --- a/server.c +++ b/server.c @@ -76,8 +76,6 @@ void send_invalid_command_reply(int fd, size_t message_size, char* message); main(int argc, char *argv[]) { - // threads to control reading files at chunks while the other threads sleep - // station_data = malloc(sizeof(station_t) * NUM_STATIONS); // check and assign arguments if (argc < 3) { fprintf(stderr,"usage: ./snowcast_server [file 1] [file 2] ... \n"); @@ -87,9 +85,6 @@ main(int argc, char *argv[]) port = argv[1]; num_stations = argc - 2; - // printf("port: %s\n", port); - // printf("num_stations: %d\n", num_stations); - // init stations size_t totalSize = 0; // get size to malloc @@ -106,12 +101,6 @@ main(int argc, char *argv[]) station_data[i - 2] = (station_t) { 0, argv[i]}; } - // print all indexes in station data - // for (int i = 0; i < num_stations; i++) - // { - // printf("station %d: %s\n", i, station_data[i].filePath); - // } - // make array of user data user_data = malloc(sizeof(user_t) * max_active_users); if (!user_data) { perror("malloc userdata"); return 1; } @@ -251,7 +240,6 @@ int send_all_udp(int udp_sockfd, char *buf, int *len, struct addrinfo *thread_re void udp_port_cleanup_handler(void *arg) { int sockfd = (int) arg; - printf("Called clean-up handler, closing socket %d\n", sockfd); close(sockfd); } @@ -259,9 +247,6 @@ void udp_port_cleanup_handler(void *arg) void *send_udp_packet_routine(void *arg) { // unpack args int user_index = (int) arg; - // printf("thread : user_index: %d\n", user_index); - // print user data - // print_user_data(user_index); // declare vairables to be used int did_work = 1; @@ -271,16 +256,12 @@ void *send_udp_packet_routine(void *arg) { struct addrinfo thread_hints, *thread_res, *thread_servinfo; int error_code; - // TODO: add error checking on these calls*** - // setup hints memset(&thread_hints, 0, sizeof thread_hints); thread_hints.ai_family = AF_INET; // use IPv4 only thread_hints.ai_socktype = SOCK_DGRAM; thread_hints.ai_flags = AI_PASSIVE; // fill in my IP for me - // setup the socket for client listener DATAGRAM (udp) - // cover the port integer to a string int int_port = user_data[user_index].udpPort; int length = snprintf( NULL, 0, "%d", int_port ); char* port = malloc( length + 1 ); @@ -309,10 +290,6 @@ void *send_udp_packet_routine(void *arg) { return (NULL); } - // bind(udp_sockfd, thread_res->ai_addr, thread_res->ai_addrlen); - - - // freeaddrinfo(thread_servinfo) pthread_cleanup_push(udp_port_cleanup_handler, (void *)udp_sockfd); while (1) { @@ -350,29 +327,20 @@ void *send_udp_packet_routine(void *arg) { } size_t BYTES_PER_SECOND = 16*1024; // read 1000 bytes of the file + char file_buffer[BYTES_PER_SECOND]; - if (read(stream_fd, file_buffer, BYTES_PER_SECOND) == -1) { + int bytes_read = 0; + if ((bytes_read = read(stream_fd, file_buffer, BYTES_PER_SECOND)) == -1) { perror("fread"); return (NULL); } close(stream_fd); - // printf("send data: thread %d \n", user_index); - // int numbytes; - // if ((numbytes = sendto(udp_sockfd, data, strlen(data), 0, - // thread_res->ai_addr, thread_res->ai_addrlen)) == -1) { - // perror("talker: sendto"); - // return (NULL); - // } - // print the size of the file_buffer - // printf("size of file_buffer: %lu\n", sizeof(file_buffer)); - - int bytes_sent = sizeof(file_buffer); - if (send_all_udp(udp_sockfd, file_buffer, &bytes_sent, thread_res) == -1) + + if (send_all_udp(udp_sockfd, file_buffer, &bytes_read, thread_res) == -1) { perror("send_all_udp"); - printf("We only sent %d bytes because of the error!\n", bytes_sent); + printf("We only sent %d bytes because of the error!\n", bytes_read); } - // printf("We sent all %d bytes!\n", bytes_sent); did_work = 1; @@ -395,17 +363,12 @@ void *send_announce_routine(void *arg) { // send the announce messages for (int i = 0; i < max_active_users; i++) { - // if (user_data[i].streamThread == NULL) { - // break; - // } if (user_data[i].sockfd == 0 || user_data[i].sockfd == -1) { continue; } - // print_user_data(i); // update the station of each user if (user_data[i].stationNum == station_num) { - // printf("sending announce to user %d\n", i); send_announce_reply(user_data[i].sockfd, station_num); } } @@ -416,25 +379,16 @@ void *synchronization_thread(void *arg) { while (1) { start_threads = 1; - // printf("\nbroadcast %d\n", c++); pthread_cond_broadcast(&cond); usleep(2000); + start_threads = 0; - // printf("before loop"); - // update file seek index for each station size_t BYTES_PER_SECOND = 16*1024; - // print num_stations - // printf("num_stations: %d\n", num_stations); + for (int i = 0; i < num_stations; i++) { - // printf("checking station %d\n", i); // get size of file struct stat f_info; - // int file_fd = open(station_data[i].filePath, O_RDONLY); - // if (file_fd == -1) { - // perror("open"); - // return (NULL); - // } if (stat(station_data[i].filePath, &f_info) == -1) { perror("fstat"); return (NULL); @@ -442,17 +396,11 @@ void *synchronization_thread(void *arg) { size_t size = f_info.st_size; - // fclose(file_fd); - // if (size == -1) { - // perror("ftell"); - // return (NULL); - // } station_data[i].seekIndex += BYTES_PER_SECOND; // if the seek index is greater than the size of the file, reset it if (station_data[i].seekIndex >= size) { station_data[i].seekIndex = 0; - // printf("resetting station %d\n", i); pthread_t send_announce_thread; pthread_create(&send_announce_thread, NULL, send_announce_routine, (void *)i); @@ -588,14 +536,6 @@ void *select_thread(void *arg) { continue; } - // printf("selectserver: new connection from %s on " - // "socket %d\n.", - // inet_ntop(remoteaddr.ss_family, - // get_in_addr((struct sockaddr*)&remoteaddr), - // remoteIP, INET6_ADDRSTRLEN), - // newfd); - // init user with this newfd - // get the udp port uint16_t udp_port = -1; int bytes_to_read = sizeof(uint16_t); @@ -607,16 +547,6 @@ void *select_thread(void *arg) { } udp_port = ntohs(udp_port); - // printf("udpPort (from Hello) for new connection is %d.\n", udp_port); - // update udp port of user - - // add a timeout to the socket - // struct timeval tv; - // tv.tv_sec = 0; - // tv.tv_usec = 0; - // if (setsockopt(newfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { - // perror("setsockopt"); - // } FD_SET(newfd, &master); // add to master set if (newfd > fdmax) { // keep track of the max fdmax = newfd; @@ -740,19 +670,7 @@ void *select_thread(void *arg) { void *init_user(int sockfd) { // add the user to the list of user data pthread_mutex_lock(&mutex_user_data); - // this is to save memory space. - // in general, the displacement of 4 is where a user "used to be" - // int user_index = max_active_users++; - // int running_index = 0; - // while(running_index < max_active_users) - // { - // if (user_data[running_index++].sockfd == -1) - // { - // user_index = running_index; - // break; - // } - // // printf("reusing memory\n"); - // } + if(sockfd > max_sockfd) { max_sockfd = sockfd; int * more_sockfd_to_user = realloc(sockfd_to_user, sizeof(int) * (max_sockfd + 1)); @@ -760,7 +678,6 @@ void *init_user(int sockfd) { sockfd_to_user = more_sockfd_to_user; } - int running_index = 0; while(running_index < max_active_users) { if (user_data[running_index].sockfd == -1) { @@ -806,18 +723,14 @@ void *print_user_data(int index) { void destroy_user(int sockfd) { pthread_mutex_lock(&mutex_user_data); // stop the thread streaming to the user - // TODO: close the FD in the stream thread pthread_t thread = user_data[sockfd_to_user[sockfd]].streamThread; if (thread != -1) { pthread_cancel(thread); } - // close(user_data[sockfd_to_user[sockfd]].udpPort); - // pthread_kill(user_data[sockfd_to_user[sockfd]].streamThread, SIGINT); // "remove" the user from the list of user data user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1, -1}; // map sockfd to -1 sockfd_to_user[sockfd] = -1; - // close(sockfd); pthread_mutex_unlock(&mutex_user_data); } @@ -846,13 +759,9 @@ void send_announce_reply(int fd, int station_num) { memcpy(send_buffer + 2, file_path, len_file_path); - // printf("buffer: %s\n", send_buffer); - size_t bytes_to_send = len_file_path + 2; if (send_all(fd, send_buffer, &bytes_to_send) == -1) perror("send_all"); - // print the number of bytes sent - // printf("sent %d bytes\n", bytes_to_send); free(send_buffer); } @@ -870,13 +779,9 @@ void send_invalid_command_reply(int fd, size_t message_size, char* message) { memcpy(send_buffer + 2, message, message_size); - // printf("buffer: %s\n", send_buffer); - int bytes_to_send = message_size + 2; if (send_all(fd, send_buffer, &bytes_to_send) == -1) perror("send"); - // print the number of bytes sent - // printf("sent %d bytes\n", bytessent); free(send_buffer); } @@ -894,46 +799,4 @@ int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]) { } return 1; -} - -// int send_all(int s, char *buf, int *len) -// { -// int total = 0; // how many bytes we've sent -// int bytesleft = *len; // how many we have left to send -// int n; - -// while(total < *len) { -// n = send(s, buf+total, bytesleft, 0); -// if (n == -1) { break; } -// total += n; -// bytesleft -= n; -// } - -// *len = total; // return number actually sent here - -// return n==-1?-1:0; // return -1 on failure, 0 on success -// } - -// int recv_all(int sock, char *buffer, int total_size) -// { -// int total_bytes_read = 0; -// int to_read = total_size; - -// char *ptr = buffer; - -// while (to_read > 0) { -// int bytes_read = recv(sock, ptr, to_read, 0); -// if (bytes_read <= 0) { -// if (bytes_read != 0) { -// perror("recv"); -// } -// return -1; -// } - -// to_read -= bytes_read; -// ptr += bytes_read; -// total_bytes_read += bytes_read; -// } - -// return total_bytes_read; -// } +} \ No newline at end of file diff --git a/snowcast_control b/snowcast_control index 2ddfb3a..c1feb84 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control index 43f119b..1b435c8 100644 Binary files a/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control and b/snowcast_control.dSYM/Contents/Resources/DWARF/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index ea9929a..5d30ec3 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener b/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener index f811857..7be4031 100644 Binary files a/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener and b/snowcast_listener.dSYM/Contents/Resources/DWARF/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index 431fa68..c296476 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 0c8d053..0bc1a97 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 97ff64f344c99f76bbed6b934236ee65eda8a9ef Mon Sep 17 00:00:00 2001 From: sotech117 Date: Thu, 21 Sep 2023 20:42:11 +0000 Subject: change model to seek --- server.c | 134 +++++++++++++-------- snowcast_control | Bin 35613 -> 22384 bytes snowcast_listener | Bin 34654 -> 19120 bytes snowcast_server | Bin 56428 -> 44944 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 29386 -> 27469 bytes 5 files changed, 86 insertions(+), 48 deletions(-) diff --git a/server.c b/server.c index 7246885..333f521 100644 --- a/server.c +++ b/server.c @@ -17,10 +17,13 @@ #define LINE_MAX 1024 #define MAX_USERS 1000 #define MAX_PATH 50 +#define MAX_STREAM_RATE 16*1024 typedef struct station { - int seekIndex; + int streamFd; char* filePath; + int fileBufferSize; + char fileBuffer[MAX_STREAM_RATE]; } station_t; typedef struct user { @@ -58,6 +61,9 @@ void *send_udp_packet_routine(void* arg); void *select_thread(void* arg); void *synchronization_thread(void* arg); +void init_station(int station_num, const char *station_name); +void seek_stations(int station_num); + int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]); void *print_info_routine(void *arg); @@ -85,20 +91,22 @@ main(int argc, char *argv[]) port = argv[1]; num_stations = argc - 2; + // init stations size_t totalSize = 0; // get size to malloc for (int i = 2; i < argc; i++) { // printf("file: %s\n", argv[i]); - totalSize += sizeof(int) + strlen(argv[i]); + // each "station" has a fd (int), filePath (char*), file_buffer_size (int), buffer_size (MAX_STREAM_RATE) + totalSize += sizeof(int) + strlen(argv[i]) + sizeof(int) + MAX_STREAM_RATE; } station_data = malloc(totalSize); if (!station_data) { perror("malloc station data"); return 1; } // assign the stations for (int i = 2; i < argc; i++) { - station_data[i - 2] = (station_t) { 0, argv[i]}; + init_station(i - 2, argv[i]); } // make array of user data @@ -308,35 +316,39 @@ void *send_udp_packet_routine(void *arg) { if (!did_work) { // sendto a random string of data to the user - int station_num = user_data[user_index].stationNum; - char *data = station_data[station_num].filePath; + // int station_num = user_data[user_index].stationNum; + // char *data = station_data[station_num].filePath; // printf("load data: thread %d \n", user_index); // get file path - char* file_path = station_data[station_num].filePath; - // get current seek chunk - int stream_fd = open(file_path, O_RDONLY); - if (stream_fd == -1) { - perror("open"); - return (NULL); - } - int current_chunk = station_data[station_num].seekIndex; - if (lseek(stream_fd, current_chunk, SEEK_SET) == -1) { - perror("fseek"); - return (NULL); - } - size_t BYTES_PER_SECOND = 16*1024; + // char* file_path = station_data[station_num].filePath; + // // get current seek chunk + // int stream_fd = open(file_path, O_RDONLY); + // if (stream_fd == -1) { + // perror("open"); + // return (NULL); + // } + // int current_chunk = station_data[station_num].seekIndex; + // if (lseek(stream_fd, current_chunk, SEEK_SET) == -1) { + // perror("fseek"); + // return (NULL); + // } // read 1000 bytes of the file - char file_buffer[BYTES_PER_SECOND]; - int bytes_read = 0; - if ((bytes_read = read(stream_fd, file_buffer, BYTES_PER_SECOND)) == -1) { - perror("fread"); - return (NULL); - } - close(stream_fd); + // char file_buffer[BYTES_PER_SECOND]; + // int bytes_read = 0; + // if ((bytes_read = read(stream_fd, file_buffer, BYTES_PER_SECOND)) == -1) { + // perror("fread"); + // return (NULL); + // } + // close(stream_fd); + + station_t *station_info = &station_data[station_num]; + int bytes_read = station_info->fileBufferSize; + // potential error here! + // printf("station info - bytes read: %d, station_fd: %d, filePath: %s, buffersize: %d\n", bytes_read, station_info->streamFd, station_info->filePath, station_info->fileBufferSize); - if (send_all_udp(udp_sockfd, file_buffer, &bytes_read, thread_res) == -1) + if (send_all_udp(udp_sockfd, station_info->fileBuffer, &bytes_read, thread_res) == -1) { perror("send_all_udp"); printf("We only sent %d bytes because of the error!\n", bytes_read); @@ -385,31 +397,13 @@ void *synchronization_thread(void *arg) { start_threads = 0; size_t BYTES_PER_SECOND = 16*1024; + // seek each file and read for (int i = 0; i < num_stations; i++) { - // get size of file - struct stat f_info; - if (stat(station_data[i].filePath, &f_info) == -1) { - perror("fstat"); - return (NULL); - } - - size_t size = f_info.st_size; - - station_data[i].seekIndex += BYTES_PER_SECOND; - // if the seek index is greater than the size of the file, reset it - if (station_data[i].seekIndex >= size) - { - station_data[i].seekIndex = 0; - - pthread_t send_announce_thread; - pthread_create(&send_announce_thread, NULL, send_announce_routine, (void *)i); - } + seek_stations(i); } - - usleep(2000); - usleep(1000000-4000); + usleep(1000000-2000); } } @@ -769,7 +763,7 @@ void send_announce_reply(int fd, int station_num) { void send_invalid_command_reply(int fd, size_t message_size, char* message) { char *send_buffer = malloc(message_size+2); if (!send_buffer) { - perror("malloc in send ancalid command"); + perror("malloc in send invalid command"); return; } @@ -786,6 +780,50 @@ void send_invalid_command_reply(int fd, size_t message_size, char* message) { free(send_buffer); } +void init_station(int station_num, const char* station_name) { + station_t *station = &station_data[station_num]; + + // open the file + int stream_fd = open(station_name, O_RDONLY); + if (stream_fd == -1) { + perror("open"); + return; + } + station->streamFd = stream_fd; + station->filePath = station_name; + + // setup file buffer + char stream_buffer[MAX_STREAM_RATE]; + memset(stream_buffer, 0, MAX_STREAM_RATE); + + station->fileBufferSize = MAX_STREAM_RATE; + memcpy(&station->fileBufferSize, stream_buffer, MAX_STREAM_RATE); + + + // load the first buffer into the stations + seek_stations(station_num); +} + +void seek_stations(int station_num) { + station_t *station_info = &station_data[station_num]; + memset(&station_info->fileBuffer, 0, MAX_STREAM_RATE); + int bytes_read = read(station_info->streamFd, &station_info->fileBuffer, MAX_STREAM_RATE); + // printf("station info - bytes read: %d, station_fd: %d, filePath: %s, buffersize: %d\n", bytes_read, station_info->streamFd, station_info->filePath, station_info->fileBufferSize); + + // time to restart the file + if (bytes_read == 0) { + if (lseek(station_info->streamFd, 0, SEEK_SET) == -1) { + perror("fseek"); + } + pthread_t send_announce_thread; + pthread_create(&send_announce_thread, NULL, send_announce_routine, (void *)station_num); + + // load first chunk + bytes_read = read(station_info->streamFd, &station_info->fileBuffer, MAX_STREAM_RATE); + } + station_info->fileBufferSize = bytes_read; +} + // Parses a buffer into tokens, from cs33 :) int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]) { diff --git a/snowcast_control b/snowcast_control index c1feb84..413a63b 100755 Binary files a/snowcast_control and b/snowcast_control differ diff --git a/snowcast_listener b/snowcast_listener index 5d30ec3..3e47e13 100755 Binary files a/snowcast_listener and b/snowcast_listener differ diff --git a/snowcast_server b/snowcast_server index c296476..f549d85 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 0bc1a97..d52de8f 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 2707112ffc0b0eed6af8271d32f94e1622203a80 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Thu, 21 Sep 2023 16:57:51 -0400 Subject: decent stopping point. failing some more tests - may have to redesign my threads --- server.c | 2 +- snowcast_server | Bin 44944 -> 44944 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 27469 -> 27442 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/server.c b/server.c index 333f521..7df1f12 100644 --- a/server.c +++ b/server.c @@ -353,7 +353,6 @@ void *send_udp_packet_routine(void *arg) { perror("send_all_udp"); printf("We only sent %d bytes because of the error!\n", bytes_read); } - did_work = 1; @@ -808,6 +807,7 @@ void seek_stations(int station_num) { station_t *station_info = &station_data[station_num]; memset(&station_info->fileBuffer, 0, MAX_STREAM_RATE); int bytes_read = read(station_info->streamFd, &station_info->fileBuffer, MAX_STREAM_RATE); + lseek(station_info->streamFd, -16, SEEK_SET); // printf("station info - bytes read: %d, station_fd: %d, filePath: %s, buffersize: %d\n", bytes_read, station_info->streamFd, station_info->filePath, station_info->fileBufferSize); // time to restart the file diff --git a/snowcast_server b/snowcast_server index f549d85..cb074ef 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index d52de8f..948984a 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From d93da5af53d6beb9a2339839aa47fbbbbeafc208 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Sat, 23 Sep 2023 07:08:28 -0400 Subject: bitrate still low, but pass the no read from file test --- Makefile | 5 +- new | Bin 0 -> 55440 bytes new.c | 497 +++++++++++++++++++++ new.dSYM/Contents/Info.plist | 20 + new.dSYM/Contents/Resources/DWARF/new | Bin 0 -> 19866 bytes server.c | 407 ++++++++++------- snowcast_server | Bin 44944 -> 45200 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 27442 -> 27865 bytes 8 files changed, 759 insertions(+), 170 deletions(-) create mode 100755 new create mode 100644 new.c create mode 100644 new.dSYM/Contents/Info.plist create mode 100644 new.dSYM/Contents/Resources/DWARF/new diff --git a/Makefile b/Makefile index 3aae1ce..7a0a8e1 100644 --- a/Makefile +++ b/Makefile @@ -17,4 +17,7 @@ client: # $(CC) $(CFLAGS) -o c client.c clean: - rm -fv snowcast_server snowcast_control snowcast_listener \ No newline at end of file + rm -fv snowcast_server snowcast_control snowcast_listener + +new: + $(CC) $(CFLAGS) -o snowcast_server new.c diff --git a/new b/new new file mode 100755 index 0000000..1116fa8 Binary files /dev/null and b/new differ diff --git a/new.c b/new.c new file mode 100644 index 0000000..e180200 --- /dev/null +++ b/new.c @@ -0,0 +1,497 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "protocol.c" + + + +#define LINE_MAX 1024 +#define MAX_RATE_PER_SECOND 16*1024 +#define TCP_TIMEOUT 100000 // 100ms in microseconds + +typedef struct station { + pthread_t thread; + int fd; + char *path; +} station_t; + +int num_stations; +station_t *stations; +setup_stations(int argc, char *argv[]); +*stream_routine(void *arg); + +int setup_listener(int port); +*accept_routine(void *arg); + +// user data structure +typedef struct user { + int tcpfd; + int udpfd; + pthread_t command_thread; + int station; +} user_t; +int num_users = 0; +user_t *users; +int tcpfd_max = 0; +int *fd_to_user; +pthread_mutex_t mutex_users = PTHREAD_MUTEX_INITIALIZER; +*init_user_routine(void *arg); +int init_user(int tcpfd, int udpfd); +void destroy_user(int fd); +*command_routine(void *arg); + +send_invalid_reply(int fd, char *message) { + printf("sending INVALID reply to socket %d\n", fd); + size_t message_size = strlen(message); + char buf[message_size + 2]; + // type and payload size + buf[0] = 4; + buf[1] = message_size; + memcpy(buf + 2, message, message_size); + + int size_buf = message_size + 2; + if (send_all(fd, &buf, &size_buf) == -1) { + perror("send_all (in init_user_routine)"); + return -1; + } + + return 1; +} + +print_users(); + +main(int argc, char *argv[]) { + if (argc < 3) { + printf("usage: ./snowcast_server [file 1] [file 2] ...\n"); + exit(1); + } + + setup_stations(argc, argv); + + users = malloc(0); + fd_to_user = malloc(0); + + int port = atoi(argv[1]); + int listenerfd = setup_listener(port); + pthread_t accept_thread; + pthread_create(&accept_thread, NULL, accept_routine, listenerfd); + + + while(1) + ; +} + +setup_stations(int argc, char *argv[]) { + num_stations = argc - 2; + + // get the size to malloc + int totalSize = 0; + for(int i = 2; i < argc; i++) + { + // printf("file: %s\n", argv[i]); + totalSize += sizeof(pthread_t) + sizeof(int) + strlen(argv[i]); + } + + // malloc the stations array + stations = malloc(totalSize); + if (!stations) { perror("malloc (stations pointer)"); exit(1); } + // assign the stations, and start the threads + for (int i = 0; i < num_stations; i++) { + stations[i].path = argv[i+2]; + stations[i].fd = open(argv[i+2], O_RDONLY); + printf(stations[i].path); + if (stations[i].fd < 0) { perror("read (from station file)"); exit(1); } + pthread_create(&stations[i].thread, NULL, stream_routine, &stations[i].fd); + } + + printf("successfully created %d stations\n", num_stations); +} + +int setup_listener(int port) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { perror("socket (listener)"); return -1; } + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind (listener)"); + return -1; + } + + if (listen(sock, 0) < 0) { perror("listen (listener)"); return -1; } + + return sock; +} + +// THREAD FUNCTIONS + +// helper +int read_file(int fd, char buffer[MAX_RATE_PER_SECOND]) { + int bytes_read = read(fd, buffer, MAX_RATE_PER_SECOND); + if (bytes_read < 0) { perror("read (from station file)"); return -1; } + // printf("bytes read: %d\n", bytes_read); + if (bytes_read == 0) { + // printf("end of file, restarting\n"); + if(lseek(fd, 0, SEEK_SET) == -1) { perror("lseek (in resarting file)"); return -1; } + bytes_read = read(fd, buffer, MAX_RATE_PER_SECOND); + if (bytes_read < 0) { perror("read (from station file, after restart)"); return -1; } + } + + return bytes_read; +} + +*stream_cleanup(void *arg) { + int fd = *(int*)arg; + printf("cleanup/delete station\n"); + return (NULL); +} + +*stream_routine(void *arg) { + int fd = *(int*)arg; + + pthread_cleanup_push(stream_cleanup, fd); + + // make buffer which will be used to stream to children + char buffer[MAX_RATE_PER_SECOND]; + memset(buffer, 0, MAX_RATE_PER_SECOND); + // if (!buffer) { perror("malloc (buffer in station thread)"); exit(1); } + + for (;;) + { + // load bytes into buffer + int bytes_read = read_file(fd, buffer); + if (bytes_read == -1) { exit(1); } + + // TODO: send buffer to children + + sleep(1); + memset(buffer, 0, MAX_RATE_PER_SECOND); + } + + pthread_cleanup_pop(1); + + return (NULL); +} + +*accept_cleanup(void *arg) { + int fd = (int) arg; + printf("cleanup/delete accept\n"); + close(fd); + return (NULL); +} + +*accept_routine(void *arg) { + int listener = (int) arg; + + // pthread_cleanup_push(accept_cleanup, listener); + + while(1) { + printf("accepting %d\n", listener); + int userfd = accept(listener, NULL, NULL); + if (userfd < 0) { perror("accept (in accept thread)"); return(NULL); } + + printf("accepted socket %d\n", userfd); + + pthread_t init_user_thread; + pthread_create(&init_user_thread, NULL, init_user_routine, userfd); + } + + // pthread_cleanup_pop(1); +} + +apply_timeout(int fd) { + // handle handshake + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = TCP_TIMEOUT; + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + perror("setsockopt (in apply_timeout)"); + return -1; + } + + return 1; +} + +remove_timeout(int fd) +{ + // handle handshake + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + perror("setsockopt (in remove_timeout)"); + return -1; + } + + return 1; +} + +int handle_handshake(int userfd) { + if (apply_timeout(userfd) == -1) { return -1; } + + // get the command type + uint8_t command_type = -1; + if ((recv(userfd, &command_type, 1, 0)) < 0) + { + perror("recv (in init_user_routine)"); + return -1; + } + + // check + if (command_type != 0) { + printf("user on socket %d must send a Hello message first", userfd); + return -1; + } + + // get the udp port + uint16_t udp_port = -1; + int bytes_to_read = sizeof(uint16_t); + if (recv_all(userfd, &udp_port, &bytes_to_read) == -1) { + perror("recv_all (in init_user_routine)"); + return -1; + } + // remove timeout + if (remove_timeout(userfd) == -1) { return -1; } + + printf("recieved HELLO command from socket %d\n", userfd); + + + // make udp socket + int udpfd = socket(AF_INET, SOCK_DGRAM, AI_PASSIVE); + if (udpfd < 0) + { + perror("socket (in init_user_routine UDP)"); + return -1; + } + + return udpfd; +} + +send_welcome_reply(int fd) { + printf("sending WELCOME reply to socket %d\n", fd); + + struct Welcome welcome; + welcome.replyType = 2; + printf("num_stations: %d\n", num_stations); + welcome.numStations = htons(num_stations); + int bytes_to_send = sizeof(struct Welcome); + if (send_all(fd, &welcome, &bytes_to_send) == -1) { + perror("send_all (in init_user_routine)"); + return -1; + } + + return 1; +} + +*init_user_cleanup(void *arg) { + int fd = (int) arg; + // printf("cleanup/delete user_maybe?\n"); + close(fd); + return (NULL); +} + +*init_user_routine(void *arg) { + int userfd = (int) arg; + // pthread_cleanup_push(init_user_cleanup, userfd); + + printf("new user on socket %d, waiting for HELLO\n", userfd); + int udpfd = handle_handshake(userfd); + if (udpfd == -1) + { + perror("handle_handshake (in init_user_routine)"); + close(userfd); + return (NULL); + } + + if(send_welcome_reply(userfd) == -1) { + perror("send_welcome_reply (in init_user_routine)"); + close(userfd); + return (NULL); + } + + if (init_user(userfd, udpfd) != 0) { + perror("init_user (in init_user_routine)"); + destroy_user(userfd); + return (NULL); + } + + return (NULL); + + // pthread_cleanup_pop(0); +} + +*command_cleanup(void *arg) { + int fd = (int) arg; + printf("cleanup/delete command\n"); + close(fd); + return (NULL); +} + +handle_setstation_command(int fd, uint16_t station_number) { + printf("received SETSTATION command from socket %d\n", fd); + // check if station number is valid + int station_num = ntohs(station_number); + if (station_num < 0 || station_num >= num_stations) { + printf("station number %d is invalid\n", station_num); + send_invalid_reply(fd, "station number is invalid"); + return -1; + } + + // set the station number + pthread_mutex_lock(&mutex_users); + printf("setting station number of user on socket %d to %d, user! %d\n", fd, station_num, fd_to_user[fd]); + users[fd_to_user[fd]].station = station_num; + pthread_mutex_unlock(&mutex_users); + + print_users(); + + return 1; +} + +*command_routine(void *arg) { + int fd = (int) arg; + + printf("waiting for SETSTATION from socket %d\n", fd); + + while(1) { + // get the command type + uint8_t command_type = -1; + if ((recv(fd, &command_type, 1, 0)) < 0) + { + perror("recv (in command_routine)"); + destroy_user(fd); + return (NULL); + } + + // check if have sent hello before + if (command_type == 0) { + printf("user on socket %d has already sent a HELLO command\n", fd); + send_invalid_reply(fd, "already sent a HELLO command"); + destroy_user(fd); + return (NULL); + } + + else if (command_type == 1) { + // get the station number + uint16_t station_number = -1; + int bytes_to_read = sizeof(uint16_t); + if (recv_all(fd, &station_number, &bytes_to_read) == -1) { + perror("recv_all (in command_routine)"); + destroy_user(fd); + return (NULL); + } + if (handle_setstation_command(fd, station_number) == -1) { + destroy_user(fd); + return (NULL); + } + } + + else if (command_type == 5) { + printf("user on socket %d has requested a LIST\n", fd); + } + + else { + printf("user on socket %d has sent an INVALID command type of %d\n", fd, command_type); + send_invalid_reply(fd, "invalid command type"); + destroy_user(fd); + return (NULL); + } + + + } +} + + +// HELPER FUNCTIONS + +int init_user(int sockfd, int udpfd) { + pthread_mutex_lock(&mutex_users); + printf("initializing user on sockets %d (tcp), %d (udp)\n", sockfd, udpfd); + // update map + if(sockfd > tcpfd_max) { + tcpfd_max = sockfd; + int * more_sockfd_to_user = realloc(fd_to_user, sizeof(int) * (tcpfd_max + 1)); + if (!more_sockfd_to_user) { perror("realloc"); exit(1); } + fd_to_user = more_sockfd_to_user; + } + + int running_index = 0; + while(running_index < num_users) { + if (users[running_index].tcpfd == -1) { + break; + } + running_index++; + } + if (running_index == num_users) { + // printf("reached max active users\n"); + // printf("making new memory\n"); + num_users++; + user_t *more_users = realloc(users, sizeof(user_t) * num_users); + if (!more_users) { perror("realloc"); exit(1); } + users = more_users; + } + + // map TCP sockfd to this user index + users[running_index] = (user_t){sockfd, udpfd, -1, -1}; + pthread_create(&users[running_index].command_thread, NULL, command_routine, sockfd); + fd_to_user[sockfd] = running_index; + // free(user_stream_threads); + + print_users(); + pthread_mutex_unlock(&mutex_users); + + return 0; +} + +void destroy_user(int fd) { + pthread_mutex_lock(&mutex_users); + + printf("destroying user on sockets %d (tcp), %d (udp)\n", users[fd_to_user[fd]].tcpfd, users[fd_to_user[fd]].udpfd); + + // close the sockets + + close(fd); + close(users[fd_to_user[fd]].udpfd); + // stop the thread taking commands to the user + pthread_cancel(&users[fd_to_user[fd]].command_thread); + // "remove" the user from the list of user data + users[fd_to_user[fd]] = (user_t) {-1, -1, -1, -1}; + // map sockfd to -1 + fd_to_user[fd] = -1; + pthread_mutex_unlock(&mutex_users); +} + + +print_users() { + printf("num users: %d\n", num_users); + for (int i = 0; i < num_users; i++) { + printf("tcpfd %d , udpfd %d , station %d |\n", users[i].tcpfd, users[i].udpfd, users[i].station); + } + printf("\n"); +} + +// Parses a buffer into tokens, from cs33 :) +int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]) { + const char *regex = " \n\t\f\r"; + char *current_token = strtok(buffer, regex); + if (current_token == NULL) return 0; + + for (int i = 0; current_token != NULL; i++) { + tokens[i] = current_token; + current_token = strtok(NULL, regex); + } + + return 1; +} \ No newline at end of file diff --git a/new.dSYM/Contents/Info.plist b/new.dSYM/Contents/Info.plist new file mode 100644 index 0000000..ba6d460 --- /dev/null +++ b/new.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.new + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/new.dSYM/Contents/Resources/DWARF/new b/new.dSYM/Contents/Resources/DWARF/new new file mode 100644 index 0000000..3200cf1 Binary files /dev/null and b/new.dSYM/Contents/Resources/DWARF/new differ diff --git a/server.c b/server.c index 7df1f12..324527e 100644 --- a/server.c +++ b/server.c @@ -17,20 +17,29 @@ #define LINE_MAX 1024 #define MAX_USERS 1000 #define MAX_PATH 50 -#define MAX_STREAM_RATE 16*1024 - +#define MAX_RATE_PER_SECOND 16*1024 + +// typedef struct station { +// int streamFd; +// char* filePath; +// int fileBufferSize; +// char fileBuffer[MAX_STREAM_RATE]; +// } station_t; typedef struct station { - int streamFd; - char* filePath; - int fileBufferSize; - char fileBuffer[MAX_STREAM_RATE]; + pthread_t streamThread; + int readfd; + char *filePath; } station_t; +int num_stations; +station_t *stations; +int setup_stations(int argc, char *argv[]); +void *stream_routine(void *arg); + typedef struct user { int udpPort; int stationNum; int sockfd; - pthread_t streamThread; } user_t; @@ -43,7 +52,7 @@ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t station_mutex = PTHREAD_MUTEX_INITIALIZER; const char *port; -int num_stations; +// int num_stations; int start_threads = 0; int max_active_users = 0; @@ -55,14 +64,20 @@ user_t *user_data; int *sockfd_to_user; // stations array pointer -station_t *station_data; +// station_t *station_data; + +struct udp_packet_routine_args { + int user_index; + int buffer_size; + char *file_buffer; +}; void *send_udp_packet_routine(void* arg); -void *select_thread(void* arg); -void *synchronization_thread(void* arg); +void *select_routine(void* arg); +void *sync_routine(void* arg); +void *send_announce_routine(void* arg); void init_station(int station_num, const char *station_name); -void seek_stations(int station_num); int parse(char buffer[LINE_MAX], char *tokens[LINE_MAX / 2]); void *print_info_routine(void *arg); @@ -88,41 +103,30 @@ main(int argc, char *argv[]) exit(1); } + // initizlize the port port = argv[1]; - num_stations = argc - 2; - - // init stations - size_t totalSize = 0; - // get size to malloc - for (int i = 2; i < argc; i++) - { - // printf("file: %s\n", argv[i]); - // each "station" has a fd (int), filePath (char*), file_buffer_size (int), buffer_size (MAX_STREAM_RATE) - totalSize += sizeof(int) + strlen(argv[i]) + sizeof(int) + MAX_STREAM_RATE; - } - station_data = malloc(totalSize); - if (!station_data) { perror("malloc station data"); return 1; } - // assign the stations - for (int i = 2; i < argc; i++) - { - init_station(i - 2, argv[i]); + // initialize the stations & their threads + if (setup_stations(argc, argv) == -1) { + perror("setup_stations"); + exit(1); } // make array of user data + printf("max active users: %d\n", sizeof(user_t) * max_active_users); user_data = malloc(sizeof(user_t) * max_active_users); if (!user_data) { perror("malloc userdata"); return 1; } sockfd_to_user = malloc(sizeof(int) * max_active_users); if (!sockfd_to_user) { perror("malloc sockfd to user"); return 1; } // make and start "select" thread that manages: - // 1) new connections, 2) requests from current connections, 3)cloing connections - pthread_t s_thread; - pthread_create(&s_thread, NULL, select_thread, NULL); + // 1) new connections, 2) requests from current connections, 3) closing connections + pthread_t select_thread; + pthread_create(&select_thread, NULL, select_routine, NULL); // start syncchronization thread to broadcast stations - pthread_t sync_thread; - pthread_create(&sync_thread, NULL, synchronization_thread, NULL); + // pthread_t sync_thread; + // pthread_create(&sync_thread, NULL, sync_routine, NULL); // command line interface char input[LINE_MAX]; @@ -179,6 +183,110 @@ main(int argc, char *argv[]) return 0; } +int read_file(int fd, char buffer[MAX_RATE_PER_SECOND], int station_num) { + int bytes_read = read(fd, buffer, MAX_RATE_PER_SECOND); + if (bytes_read < 0) { perror("read (from station file)"); return -1; } + // printf("bytes read: %d\n", bytes_read); + if (bytes_read == 0) { + // printf("end of file, restarting\n"); + pthread_t send_announce_thread; + pthread_create(&send_announce_thread, NULL, send_announce_routine, station_num); + + if (lseek(fd, 0, SEEK_SET) == -1) + { + perror("lseek (in resarting file)"); + return -1; + } + bytes_read = read(fd, buffer, MAX_RATE_PER_SECOND); + if (bytes_read < 0) { perror("read (from station file, after restart)"); return -1; } + } + + return bytes_read; +} + +void *stream_routine_cleanup(void *arg) { + int read_fd = (int) arg; + close(read_fd); +} + +void *stream_routine(void *arg) { + int station_num = (int) arg; + printf("stream routine %d\n", station_num); + int read_fd = stations[station_num].readfd; + + pthread_cleanup_push(stream_routine_cleanup, read_fd); + + // make buffer which will be used to stream to children + char buffer[MAX_RATE_PER_SECOND]; + memset(buffer, 0, MAX_RATE_PER_SECOND); + // if (!buffer) { perror("malloc (buffer in station thread)"); exit(1); } + + for (;;) + { + // load bytes into buffer + int bytes_read = read_file(read_fd, buffer, station_num); + if (bytes_read == -1) { exit(1); } + + // TODO: send buffer to children + char *send_buffer = malloc(2 + bytes_read); + for (int i = 0; i < max_active_users; i++) + { + if (!user_data[i].sockfd || user_data[i].sockfd == -1) + continue; + if (user_data[i].stationNum == station_num) + { + // send the udp packet + int *send_buffer = malloc(2 + bytes_read); + memset(send_buffer, 0, 2 + bytes_read); + send_buffer[0] = i; + send_buffer[1] = bytes_read; + memcpy(send_buffer+2, buffer, bytes_read); + // printf("sending udp packet to user %d\n", i); + pthread_t t; + pthread_create(&t, NULL, send_udp_packet_routine, send_buffer); + } + } + free(send_buffer); + usleep(1000000-5000); + start_threads = 1; + pthread_cond_broadcast(&cond); + + usleep(5000); + start_threads = 0; + + memset(buffer, 0, MAX_RATE_PER_SECOND); + } + + return (NULL); + + pthread_cleanup_pop(1); +} + +int setup_stations(int argc, char *argv[]) { + num_stations = argc - 2; + + // get the size to malloc + int totalSize = 0; + for(int i = 2; i < argc; i++) + { + totalSize += sizeof(pthread_t) + sizeof(int) + strlen(argv[i]); + } + + // malloc the stations array + stations = malloc(totalSize); + if (!stations) { perror("malloc (stations pointer)"); return -1; } + // assign the stations, and start the threads + for (int i = 0; i < num_stations; i++) { + stations[i].filePath = argv[i+2]; + stations[i].readfd = open(argv[i+2], O_RDONLY); + if (stations[i].readfd < 0) { perror("read (from station file)"); return -1; } + pthread_create(&stations[i].streamThread, NULL, stream_routine, i); + } + + printf("successfully created %d stations\n", num_stations); + return 1; +} + void write_int_to_fd(int fd, int n) { int l = snprintf(NULL, 0, "%d", n); char *num = malloc(l + 1); @@ -203,7 +311,7 @@ void *print_info_routine(void *arg) { write(print_fd, comma, strlen(comma)); // write file path - char* file_path = station_data[i].filePath; + char* file_path = stations[i].filePath; write(print_fd, file_path, strlen(file_path)); for (int j = 0; j < max_active_users; j++) { @@ -253,8 +361,15 @@ void udp_port_cleanup_handler(void *arg) /* Make the manager routine */ void *send_udp_packet_routine(void *arg) { + printf("send udp packet routine\n"); + int *buf = arg; // unpack args - int user_index = (int) arg; + int user_index = buf[0]; + int buffer_size = buf[1]; + char *file_buffer = malloc(buffer_size); + memcpy(file_buffer, buf+2, buffer_size); + + // printf("udp packet routine, user:%d\n size: %d\n", user_index, buffer_size); // declare vairables to be used int did_work = 1; @@ -299,73 +414,34 @@ void *send_udp_packet_routine(void *arg) { } pthread_cleanup_push(udp_port_cleanup_handler, (void *)udp_sockfd); - while (1) - { // wait for - pthread_mutex_lock(&m); - did_work = 0; - while (!start_threads) - { - pthread_cond_wait(&cond, &m); - } - - int station_num = user_data[user_index].stationNum; - if (station_num == -1) { - did_work = 1; - } - - if (!did_work) { - // sendto a random string of data to the user - // int station_num = user_data[user_index].stationNum; - // char *data = station_data[station_num].filePath; - // printf("load data: thread %d \n", user_index); - - // get file path - // char* file_path = station_data[station_num].filePath; - // // get current seek chunk - // int stream_fd = open(file_path, O_RDONLY); - // if (stream_fd == -1) { - // perror("open"); - // return (NULL); - // } - // int current_chunk = station_data[station_num].seekIndex; - // if (lseek(stream_fd, current_chunk, SEEK_SET) == -1) { - // perror("fseek"); - // return (NULL); - // } - // read 1000 bytes of the file - - // char file_buffer[BYTES_PER_SECOND]; - // int bytes_read = 0; - // if ((bytes_read = read(stream_fd, file_buffer, BYTES_PER_SECOND)) == -1) { - // perror("fread"); - // return (NULL); - // } - // close(stream_fd); - - station_t *station_info = &station_data[station_num]; - int bytes_read = station_info->fileBufferSize; - // potential error here! - // printf("station info - bytes read: %d, station_fd: %d, filePath: %s, buffersize: %d\n", bytes_read, station_info->streamFd, station_info->filePath, station_info->fileBufferSize); - - if (send_all_udp(udp_sockfd, station_info->fileBuffer, &bytes_read, thread_res) == -1) - { - perror("send_all_udp"); - printf("We only sent %d bytes because of the error!\n", bytes_read); - } - did_work = 1; + pthread_mutex_lock(&m); + did_work = 0; + while (!start_threads) + { + pthread_cond_wait(&cond, &m); + } + int station_num = user_data[user_index].stationNum; + if (station_num == -1) { + did_work = 1; + } + // potential error here! + // printf("station info - bytes read: %d, station_fd: %d, filePath: %s, buffersize: %d\n", bytes_read, station_info->streamFd, station_info->filePath, station_info->fileBufferSize); - usleep(400000); - } + if (send_all_udp(udp_sockfd, file_buffer, &buffer_size, thread_res) == -1) + { + perror("send_all_udp"); + printf("We only sent %d bytes because of the error!\n", buffer_size); + } - pthread_mutex_unlock(&m); + free(file_buffer); - usleep(100000); - } + pthread_mutex_unlock(&m); pthread_cleanup_pop(1); - return NULL; + + return (NULL); } void *send_announce_routine(void *arg) { @@ -385,28 +461,21 @@ void *send_announce_routine(void *arg) { } } -void *synchronization_thread(void *arg) { - int c = 0; - while (1) - { - start_threads = 1; - pthread_cond_broadcast(&cond); - usleep(2000); - - start_threads = 0; - size_t BYTES_PER_SECOND = 16*1024; +// void *sync_routine(void *arg) { +// int c = 0; +// while (1) +// { +// start_threads = 1; +// pthread_cond_broadcast(&cond); +// usleep(2000); - // seek each file and read - for (int i = 0; i < num_stations; i++) - { - seek_stations(i); - } +// start_threads = 0; - usleep(1000000-2000); - } -} +// usleep(1000000-2000); +// } +// } -void *select_thread(void *arg) { +void *select_routine(void *arg) { fd_set master; // master file descriptor list fd_set read_fds; // temp file descriptor list for select() int fdmax; // maximum file descriptor number @@ -688,7 +757,7 @@ void *init_user(int sockfd) { } // map TCP sockfd to this user index - user_data[running_index] = (user_t){-1, -1, sockfd, -1}; + user_data[running_index] = (user_t){-1, -1, sockfd}; sockfd_to_user[sockfd] = running_index; // free(user_stream_threads); pthread_mutex_unlock(&mutex_user_data); @@ -700,7 +769,7 @@ void *update_user_udpPort(int sockfd, int udpPort) { // set the udpPort user->udpPort = udpPort; // start the stream thread, now that we have the udpPort - pthread_create(&user->streamThread, NULL, send_udp_packet_routine, (void *)sockfd_to_user[sockfd]); + // pthread_create(&user->streamThread, NULL, send_udp_packet_routine, (void *)sockfd_to_user[sockfd]); pthread_mutex_unlock(&mutex_user_data); } void *update_user_station(int sockfd, int stationNum) { @@ -709,19 +778,19 @@ void *update_user_station(int sockfd, int stationNum) { pthread_mutex_unlock(&mutex_user_data); } void *print_user_data(int index) { - printf("udpPort: %d, stationNum: %d, sockfd: %d, threadId:%d\n", - user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd, user_data[index].streamThread); + printf("udpPort: %d, stationNum: %d, sockfd: %d\n", + user_data[index].udpPort, user_data[index].stationNum, user_data[index].sockfd); } void destroy_user(int sockfd) { pthread_mutex_lock(&mutex_user_data); // stop the thread streaming to the user - pthread_t thread = user_data[sockfd_to_user[sockfd]].streamThread; - if (thread != -1) { - pthread_cancel(thread); - } + // pthread_t thread = user_data[sockfd_to_user[sockfd]].streamThread; + // if (thread != -1) { + // pthread_cancel(thread); + // } // "remove" the user from the list of user data - user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1, -1}; + user_data[sockfd_to_user[sockfd]] = (user_t) {-1, -1, -1}; // map sockfd to -1 sockfd_to_user[sockfd] = -1; @@ -739,7 +808,7 @@ void *get_in_addr(struct sockaddr *sa) } void send_announce_reply(int fd, int station_num) { - char* file_path = station_data[station_num].filePath; + char* file_path = stations[station_num].filePath; int len_file_path = strlen(file_path); char *send_buffer = malloc(len_file_path+2); @@ -779,50 +848,50 @@ void send_invalid_command_reply(int fd, size_t message_size, char* message) { free(send_buffer); } -void init_station(int station_num, const char* station_name) { - station_t *station = &station_data[station_num]; - - // open the file - int stream_fd = open(station_name, O_RDONLY); - if (stream_fd == -1) { - perror("open"); - return; - } - station->streamFd = stream_fd; - station->filePath = station_name; - - // setup file buffer - char stream_buffer[MAX_STREAM_RATE]; - memset(stream_buffer, 0, MAX_STREAM_RATE); - - station->fileBufferSize = MAX_STREAM_RATE; - memcpy(&station->fileBufferSize, stream_buffer, MAX_STREAM_RATE); - - - // load the first buffer into the stations - seek_stations(station_num); -} - -void seek_stations(int station_num) { - station_t *station_info = &station_data[station_num]; - memset(&station_info->fileBuffer, 0, MAX_STREAM_RATE); - int bytes_read = read(station_info->streamFd, &station_info->fileBuffer, MAX_STREAM_RATE); - lseek(station_info->streamFd, -16, SEEK_SET); - // printf("station info - bytes read: %d, station_fd: %d, filePath: %s, buffersize: %d\n", bytes_read, station_info->streamFd, station_info->filePath, station_info->fileBufferSize); - - // time to restart the file - if (bytes_read == 0) { - if (lseek(station_info->streamFd, 0, SEEK_SET) == -1) { - perror("fseek"); - } - pthread_t send_announce_thread; - pthread_create(&send_announce_thread, NULL, send_announce_routine, (void *)station_num); - - // load first chunk - bytes_read = read(station_info->streamFd, &station_info->fileBuffer, MAX_STREAM_RATE); - } - station_info->fileBufferSize = bytes_read; -} +// void init_station(int station_num, const char* station_name) { +// station_t *station = &station_data[station_num]; + +// // open the file +// int stream_fd = open(station_name, O_RDONLY); +// if (stream_fd == -1) { +// perror("open"); +// return; +// } +// station->streamFd = stream_fd; +// station->filePath = station_name; + +// // setup file buffer +// char stream_buffer[MAX_STREAM_RATE]; +// memset(stream_buffer, 0, MAX_STREAM_RATE); + +// station->fileBufferSize = MAX_STREAM_RATE; +// memcpy(&station->fileBufferSize, stream_buffer, MAX_STREAM_RATE); + + +// // load the first buffer into the stations +// seek_stations(station_num); +// } + +// void seek_stations(int station_num) { +// station_t *station_info = &station_data[station_num]; +// memset(&station_info->fileBuffer, 0, MAX_STREAM_RATE); +// int bytes_read = read(station_info->streamFd, &station_info->fileBuffer, MAX_STREAM_RATE); +// lseek(station_info->streamFd, -16, SEEK_SET); +// // printf("station info - bytes read: %d, station_fd: %d, filePath: %s, buffersize: %d\n", bytes_read, station_info->streamFd, station_info->filePath, station_info->fileBufferSize); + +// // time to restart the file +// if (bytes_read == 0) { +// if (lseek(station_info->streamFd, 0, SEEK_SET) == -1) { +// perror("fseek"); +// } +// pthread_t send_announce_thread; +// pthread_create(&send_announce_thread, NULL, send_announce_routine, (void *)station_num); + +// // load first chunk +// bytes_read = read(station_info->streamFd, &station_info->fileBuffer, MAX_STREAM_RATE); +// } +// station_info->fileBufferSize = bytes_read; +// } // Parses a buffer into tokens, from cs33 :) diff --git a/snowcast_server b/snowcast_server index cb074ef..89e4cae 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 948984a..667c8c1 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 5b5da5bf9564ad4c0dac692c9d93fc9479667ff0 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Sat, 23 Sep 2023 11:39:25 +0000 Subject: pass one extra test --- server.c | 2 +- snowcast_server | Bin 45200 -> 28720 bytes .../Contents/Resources/DWARF/snowcast_server | Bin 27865 -> 27811 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/server.c b/server.c index 324527e..74ba7fa 100644 --- a/server.c +++ b/server.c @@ -361,7 +361,7 @@ void udp_port_cleanup_handler(void *arg) /* Make the manager routine */ void *send_udp_packet_routine(void *arg) { - printf("send udp packet routine\n"); + // printf("send udp packet routine\n"); int *buf = arg; // unpack args int user_index = buf[0]; diff --git a/snowcast_server b/snowcast_server index 89e4cae..e47db30 100755 Binary files a/snowcast_server and b/snowcast_server differ diff --git a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server index 667c8c1..787e279 100644 Binary files a/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server and b/snowcast_server.dSYM/Contents/Resources/DWARF/snowcast_server differ -- cgit v1.2.3-70-g09d2 From 1e9ac5407ef4f2cddc745f35f33a860446526cea Mon Sep 17 00:00:00 2001 From: sotech117 Date: Sat, 23 Sep 2023 21:22:15 +0000 Subject: PASS ALL TESTS --- Makefile | 5 +---- server.c | 4 ++-- snowcast_server | Bin 28720 -> 45192 bytes 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 7a0a8e1..a60df35 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,4 @@ client: # $(CC) $(CFLAGS) -o c client.c clean: - rm -fv snowcast_server snowcast_control snowcast_listener - -new: - $(CC) $(CFLAGS) -o snowcast_server new.c + rm -fv server client diff --git a/server.c b/server.c index 74ba7fa..c889093 100644 --- a/server.c +++ b/server.c @@ -17,7 +17,7 @@ #define LINE_MAX 1024 #define MAX_USERS 1000 #define MAX_PATH 50 -#define MAX_RATE_PER_SECOND 16*1024 +#define MAX_RATE_PER_SECOND 16*1024 / 2 // typedef struct station { // int streamFd; @@ -247,7 +247,7 @@ void *stream_routine(void *arg) { } } free(send_buffer); - usleep(1000000-5000); + usleep(1000000 / 2 - 5000); start_threads = 1; pthread_cond_broadcast(&cond); diff --git a/snowcast_server b/snowcast_server index e47db30..c495898 100755 Binary files a/snowcast_server and b/snowcast_server differ -- cgit v1.2.3-70-g09d2