diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | broadcast.c | 67 | ||||
-rw-r--r-- | client.c | 33 | ||||
-rw-r--r-- | protocol.h | 35 | ||||
-rw-r--r-- | server.c | 2 | ||||
-rw-r--r-- | snowcast-server.c | 0 | ||||
-rwxr-xr-x | snowcast_control | bin | 13864 -> 34461 bytes | |||
-rwxr-xr-x | snowcast_server | bin | 14176 -> 34476 bytes | |||
-rw-r--r-- | snowcast_server.c | 195 |
9 files changed, 324 insertions, 10 deletions
@@ -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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#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 @@ -11,6 +11,7 @@ #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> +#include <ctype.h> #include <arpa/inet.h> @@ -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 @@ -1,16 +1,39 @@ #include <stdint.h> // 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 @@ -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 --- a/snowcast-server.c +++ /dev/null diff --git a/snowcast_control b/snowcast_control Binary files differindex 5e208f3..d6aaff0 100755 --- a/snowcast_control +++ b/snowcast_control diff --git a/snowcast_server b/snowcast_server Binary files differindex 75713b7..1f61e9d 100755 --- a/snowcast_server +++ b/snowcast_server 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 <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <sys/wait.h> +#include <signal.h> + +#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: <listen port> <file0> [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 |