/////////////////////////////////////////////////////////////////////////////// // Title: Programming Assignment 2: Routing Protocol // Files: p2/server/server.c // p1/server/Makefile // Semester: Fall 2007 // Author: Cymen Vig (cymen@cs.wisc.edu) // John Goebel (jgoebel@wisc.edu) // Partner: cymen goebel /////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG 1 #define INFINITY 16 #define MAX_UDP 65507 // Max size of UDP packet #define MAX_LENGTH 255 #define USAGE -100 typedef struct { int id; char ip[16]; int port; time_t ttl; // time(&ttl); struct Neighbor *next; } Neighbor; typedef struct { int id; int dest; int cost; struct Route *next; } Route; typedef struct Server { int id; int port; int interval; // how often to send updates Neighbor *neighbor; Route *route; char *tfile; unsigned char *packet; } Server; Server server; void getOpts(int argc, char *argv[]); // get cmd line options void update_handler(int signum); // send scheduled updates void endProgram(int val); int loadData(char *file); void stripNL(char *string); // strip new line int packUpdate(); void idToIp(int id, char *ip); void addNeighbor(Neighbor *new); void addRoute(Route *new); int neighborPresent(int id); int routePresent(int id); int deleteNeighbor(int id); void printRoute(); void printNeighbor(); int commandInput(char *buf); // 40 SUCCESS // Report successful executon of update, step, packets, display or disable command. void success(char *command) { printf("40 %s SUCCESS\n", command); } // 40 // Report error cncountered during executon of command. void errorEncountered(char *command, char *errorMsg) { printf("40 %s %s\n", command, errorMsg); printf("Useage:\n"); printf(" update \n"); printf(" step\n"); printf(" packets\n"); printf(" display\n"); printf(" disable \n"); printf(" crash\n"); } int packUpdate() { int vectorCount = 0; Route *r = server.route; while (r) { vectorCount++; r = (Route *) r->next; } if (vectorCount == 0) return 0; /* calculate size of packet in bytes for malloc * header: * 2 - number of update fields * 2 - padding (0x0) * for each vector: * 4 - ip address of dest server * 2 - server id of dest server * 2 - cost to dest server * Total: * 4 + vectorCount * (8) */ int size = 4 + vectorCount*8; server.packet = malloc(size); bzero(server.packet, size); // pack field count int offset = 0; unsigned short fieldCount = htons(vectorCount); memcpy(server.packet+offset, (char *) &fieldCount, sizeof(fieldCount)); offset += sizeof(fieldCount); // intentional skip (2 bytes) offset += sizeof(fieldCount); r = server.route; while (r) { // pack server ip char ip_addr[16]; idToIp(r->id, ip_addr); struct sockaddr_in ip; inet_aton(ip_addr, &ip.sin_addr); memcpy(server.packet+offset, (char *) &ip.sin_addr, sizeof(ip.sin_addr)); offset += sizeof(ip.sin_addr); // pack server id unsigned short id = htons(r->id); memcpy(server.packet+offset, (char *) &id, sizeof(id)); offset += sizeof(id); // pack cost to server unsigned short cost = htons(r->cost); memcpy(server.packet+offset, (char *) &cost, sizeof(cost)); offset += sizeof(cost); r = (Route *) r->next; } // thought for error checking -- should we verify path to dest. server is valid? return size; } void idToIp(int id, char *ip) { Neighbor *n = server.neighbor; while (n) { if (n->id == id) { memcpy(ip, n->ip, sizeof(n->ip)); return; } n = (Neighbor *) n->next; } ip = NULL; } int main(int argc, char *argv[]) { if (argc != 9) endProgram(USAGE); getOpts(argc, argv); loadData(server.tfile); int quit = 0; int result; char buf[256]; char *token; struct itimerval itime; itime.it_interval.tv_sec = server.interval; itime.it_interval.tv_usec = 0; itime.it_value.tv_sec = server.interval; itime.it_value.tv_usec = 0; fd_set socket_set; int sockfd, clilen; struct sockaddr_in serv_addr, cli_addr; // setup server listening socket sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0 && DEBUG) printf("ERROR with sockfd\n"); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(server.port); if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) if (DEBUG) printf("ERROR on binding\n"); struct sigaction action, oldaction; action.sa_handler = update_handler; action.sa_flags = SA_RESTART; sigemptyset(&action.sa_mask); result = sigaction(SIGALRM, &action, NULL); if (DEBUG) printf("sigaction result: %d\n", result); result = setitimer(ITIMER_REAL, &itime, NULL); if (DEBUG) printf("setitimer result: %d\n", result); while (!quit) { FD_ZERO(&socket_set); FD_SET(0, &socket_set); // add fd of standard input/output FD_SET(sockfd, &socket_set); // add fd of UDP port listening on result = select(FD_SETSIZE, &socket_set, (fd_set *) 0, (fd_set *) 0, NULL); if (result < 0) { if (errno != EINTR) { printf("%m\n", errno); } } else { if (FD_ISSET(0, &socket_set)) { fgets(buf, sizeof(buf), stdin); quit = commandInput(buf); } if (FD_ISSET(sockfd, &socket_set)) { printf("recvfrom(...)\n"); /* while(result) { recv... result--; } */ } } } } int commandInput(char *lineIn){ int servID1, servID2, linkCost, numArgs; int lineLen = 80; char command[lineLen]; // for(;;) { strcpy(command, ""); servID1 = -1; servID2 = -1; linkCost = -1; // gets(lineIn); /* get an entire string from the keyboard. */ numArgs = sscanf(lineIn, "%s %d %d %d", &command, &servID1, &servID2, &linkCost); printf("numArgs = %d\n", numArgs); printf("You typed: %s\n", lineIn); printf("%s - %d - %d - %d\n", command, servID1, servID2, linkCost); if ( strcmp(command, "update") == 0 ) { printf("update entered!\n"); if (numArgs != 4) errorEncountered(command, "Invalid # of arguments!"); else {success(command);} } else if( strcmp(command, "step") == 0 ) { printf("step entered!\n"); if (numArgs != 1) errorEncountered(command, "No arguments required!"); else {success(command);} } else if( strcmp(command, "packets") == 0 ) { printf("packets entered!\n"); if (numArgs != 1) errorEncountered(command, "No arguments required!"); else {success(command);} } else if( strcmp(command, "display") == 0 ) { printf("display entered!\n"); if (numArgs != 1) errorEncountered(command, "No arguments required!"); else {success(command);} } else if( strcmp(command, "disable") == 0 ) { printf("disable entered!\n"); if (numArgs != 2) errorEncountered(command, "Invalid # of arguments!"); else {success(command);} } else if( strcmp(command, "crash") == 0 ) { printf("crash entered!\n"); if (numArgs != 1) { errorEncountered(command, "No arguments required!"); } return 1; }else{ errorEncountered(command, "Invalid command!\n"); } return 0; } } void update_handler(int signum) { //printf("send update now\n"); packUpdate(); } // parse command line options void getOpts (int argc, char *argv[]) { // parse program options with getopt int c; opterr = 0; while ((c = getopt (argc, argv, "p:t:i:d:")) != -1) switch (c) { case 'p': // port server.port = atoi(optarg); break; case 't': // topology filename server.tfile = optarg; break; case 'i': // update interval server.interval = atoi(optarg); break; case 'd': // server id server.id = atoi(optarg); break; case '?': // error on anything else case ':': default: endProgram(USAGE); } } void endProgram(int val) { if (val == USAGE) { printf("server -p -t -i "); printf(" -d \n"); } //freeMem(); exit(val); } int loadData(char *file) { FILE *fd; char tmp[MAX_LENGTH]; char *sep = " "; char *token = NULL; int neighborCount, routeCount, i; fd = fopen(file, "r"); if (fd == 0) { printf("error opening file: %s\n", file); // memory leak exit(-1); } fgets(tmp, MAX_LENGTH, fd); neighborCount = atoi(tmp); fgets(tmp, MAX_LENGTH, fd); routeCount = atoi(tmp); Neighbor *n; for(i = 0; i < neighborCount; i++) { n = (Neighbor *) malloc(sizeof(Neighbor)); fgets(tmp, MAX_LENGTH, fd); n->id = atoi(strtok(tmp, sep)); token = strtok(NULL, sep); strcpy(n->ip, token); n->port = atoi(strtok(NULL, sep)); addNeighbor(n); } if (DEBUG) printNeighbor(); // future error check - always(n->id == server.id) -- not implemented Route *r; for(i = 0; i < routeCount; i++) { r = (Route *) malloc(sizeof(Route)); fgets(tmp, MAX_LENGTH, fd); sscanf(tmp, "%d %d %d", &r->id, &r->dest, &r->cost); if (r->id != server.id) continue; addRoute(r); } if (DEBUG) printRoute(); // loop through servers -- if not in routes, add to routes w/ cost inf n = server.neighbor; while (n) { if (!destPresent(n->id)) { Route *r = (Route *) malloc(sizeof(Route)); r->id = server.id; r->dest = n->id; if (n->id == server.id) r->cost = 0; else r->cost = INFINITY; addRoute(r); } n = n->next; } if (DEBUG) printRoute(); // loop through routes -- if cost INFINITY remove invalid neighbor n = server.neighbor; while (n) { if (destRouteInf(n->id) || n->id == server.id) delNeighbor(n->id); n = n->next; } if (DEBUG) printNeighbor(); } // strip new line from end of char * void stripNL (char *string) { int len = strlen(string); if (len > 0 && string[len-1] == '\n') string[len-1] = '\0'; } void addNeighbor(Neighbor *new) { // add new neighbor to front of list new->next = server.neighbor; server.neighbor = new; } void addRoute(Route *new) { // add new route to front of list new->next = server.route; server.route = new; } int delNeighbor(int id) { Neighbor *n, *nprior; int result = 0; n = server.neighbor; nprior = NULL; while (n) { if (n->id == id) { // is it head of list? if (n == server.neighbor) { server.neighbor = n->next; free(n); result = 1; } else { nprior->next = n->next; free(n); result = 1; } } nprior = n; n = n->next; } return result; } int routePresent(int id) { Route *r = server.route; while(r) { if (r->id == id) return 1; r = r->next; } return 0; } int destPresent(int id) { Route *r = server.route; while(r) { if (r->dest == id) return 1; r = r->next; } return 0; } int destRouteInf(int id) { Route *r = server.route; while (r) { if (r->dest == id && r->cost == INFINITY) return 1; r = r->next; } return 0; } int neighborPresent(int id) { Neighbor *n = server.neighbor; while(n) { if (n->id == id) return 1; n = n->next; } return 0; } void printRoute() { Route *r = server.route; printf("Routes:\n"); while (r) { printf("\t(%d, %d, %d)\n", r->id, r->dest, r->cost); r = r->next; } } void printNeighbor() { Neighbor *n = server.neighbor; printf("Neighbors:\n"); while (n) { printf("\t%d %s\n", n->id, n->ip); n = n->next; } }