diff options
Diffstat (limited to 'snowcast_server.c')
-rw-r--r-- | snowcast_server.c | 195 |
1 files changed, 195 insertions, 0 deletions
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 |