aboutsummaryrefslogtreecommitdiff
path: root/snowcast_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'snowcast_server.c')
-rw-r--r--snowcast_server.c195
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