├── project_2.pdf ├── MNC_PROJ2_DOC.pdf ├── makefile ├── README.md └── DistanceVectorRouting.cpp /project_2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/router/Distance-Vector/master/project_2.pdf -------------------------------------------------------------------------------- /MNC_PROJ2_DOC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/router/Distance-Vector/master/MNC_PROJ2_DOC.pdf -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | Proj1: DistanceVectorRouting.cpp 2 | g++ DistanceVectorRouting.cpp -o server 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Distance-Vector 2 | =============== 3 | 4 | A simplified implementation of the Distance Vector Protocol. The protocol runs on top of servers (behaving as routers) using UDP. Each server runs on a machine at a pre-defined port number. The servers are able to output their forwarding tables along with the link costs and are robust to link changes. The current implementation faces the Count-to-infinity problem. 5 | -------------------------------------------------------------------------------- /DistanceVectorRouting.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * DistanceVectorRouting.cpp 3 | * 4 | * Created on: Nov 1, 2013 5 | * Author: subhranil 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #define NODECOUNTMAX 100 26 | #define MAXPACKETSIZE 10000 27 | #define PROMPTVAR "DistanceVectorRouting>>" 28 | #define MAXRETRY 3 29 | 30 | int gTotalNumberOfNodes=0; 31 | int gNumberOfNeighbours=0; 32 | char gTopologyFileName[1024]=""; 33 | int gUpdateInterval=0; 34 | char gLocalIP[50]=""; 35 | int16_t gLocalPort=0; 36 | int32_t gLocalServerId=0; 37 | struct timeval timeout; 38 | int gUpdateCount=0; 39 | typedef struct Node 40 | { 41 | int16_t id; 42 | int32_t IP; 43 | int16_t port; 44 | int16_t nextHopId; 45 | int16_t cost; 46 | bool isActiveNeighbour; 47 | int updateCount; 48 | } Node; 49 | 50 | //typedef struct TimeNode 51 | //{ 52 | // struct timeval lastTime; 53 | // int interval; 54 | //} TimeNode; 55 | 56 | typedef struct sockaddr_in SocketAddressInfo; 57 | //typedef struct DistanceVectorNode 58 | //{ 59 | // Node dest; 60 | // 61 | //} DistanceVectorNode; 62 | 63 | //Node nodeList[NODECOUNTMAX];// also the routing table 64 | Node costList[NODECOUNTMAX]={{-1,0,-1,-1,-1}}; // weight of the connecting edge. contains entries only for the neighbours of this host 65 | Node distanceVector[NODECOUNTMAX];//[NODECOUNTMAX];// this 2d matrix and grow to the N*N size in the worst case. 66 | int16_t costMatrix[NODECOUNTMAX][NODECOUNTMAX]={(int16_t)-1}; 67 | // For the first two lists index 0 must be self and hence the costList[0]=0; 68 | // cost list (id,cost) for each f the neighbours. 69 | // Distance vector is a map betwen (id,minCost) with size gTotalNumberOfNodes( must be allowed room to expand) 70 | // distance vect 71 | 72 | 73 | void init() 74 | { 75 | for(int i=0;isin_family=AF_INET; 100 | socketAddress->sin_port=htons(53); 101 | inet_pton(socketAddress->sin_family,"8.8.8.8",&(socketAddress->sin_addr)); 102 | 103 | //create a socket for connecting to server 104 | int socketId=socket(AF_INET,SOCK_DGRAM,0); 105 | if(socketId==-1) 106 | { 107 | printf("Error in creating socket"); 108 | return ""; 109 | } 110 | int retConnect=connect(socketId,(struct sockaddr*)socketAddress,sizeof(SocketAddressInfo)); 111 | if(retConnect<0) 112 | { 113 | printf("connection with peer failed with error : %d",retConnect); 114 | return ""; 115 | } 116 | 117 | SocketAddressInfo localAddressInfo; 118 | socklen_t len=sizeof(localAddressInfo); 119 | getsockname(socketId,(struct sockaddr*)&localAddressInfo,&len); 120 | char buffer[32]; 121 | inet_ntop(AF_INET,&localAddressInfo.sin_addr,buffer,sizeof(buffer)); 122 | return buffer; 123 | } 124 | 125 | 126 | int indexOfNodeWithId(int32_t id) 127 | { 128 | for(int i=0;i add to cost List (non neighbours dont send Dv's) 204 | can be a newnon neighbour 0--> add directly to distance vector[0]; 205 | */ 206 | //bool newNeighbour,newNode; 207 | if(baseindex<0) // should never happen .this means that the node was not there in the topology file 208 | { 209 | //printf("%hd-->%d\n",tempVar,temp); 210 | printf("Invalid message received.\n"); 211 | fflush(stdout); 212 | return NULL; 213 | } 214 | else 215 | { 216 | 217 | *baseId=costList[baseindex].id; 218 | 219 | 220 | for(int j=0;j%d\n",tempVar,temp); 230 | printf("Invalid message received.\n"); 231 | fflush(stdout); 232 | return NULL; 233 | } 234 | else 235 | { 236 | tempVector[index].IP=temp; 237 | tempVector[index].port=tempVar; 238 | memcpy(&tempVector[index].id,message+numberOfBytesRead,2); 239 | numberOfBytesRead+=2; 240 | // memcpy(&tempVector[index].nextHopId,message+numberOfBytesRead,2); 241 | // numberOfBytesRead+=2; 242 | memcpy(&tempVector[index].cost,message+numberOfBytesRead,2); 243 | numberOfBytesRead+=2; 244 | costList[baseindex].updateCount=MAXRETRY; 245 | costMatrix[baseindex][index]=tempVector[index].cost; 246 | 247 | // if(costList[baseindex].updateCount==0) 248 | // costList[baseindex].updateCount=MAXRETRY; 249 | // else 250 | // costList[baseindex].updateCount++; 251 | // // check if this is a new neighbour 252 | 253 | 254 | //The following code is not needed since the update command will be executed on both ends of the link 255 | 256 | // if(index==0&&costList[0].id==tempVector[index].nextHopId) 257 | // { 258 | // if(costList[baseindex].cost==-1) 259 | // { 260 | // printf("New neighbour added. id:%hd",costList[baseindex].id); 261 | // gNumberOfNeighbours++; 262 | // } 263 | // else if(costList[baseindex].cost!=tempVector[index].cost) 264 | // printf("Edge weight between %hd updated",costList[baseindex].id); 265 | // 266 | // costList[baseindex].cost=tempVector[index].cost; 267 | // //printf("edge weight updated\n"); 268 | // //gNumberOfNeighbours++; 269 | // } 270 | } 271 | 272 | } 273 | gUpdateCount++; 274 | printf("RECEIVED A MESSAGE FROM SERVER %hd\n",*baseId); 275 | fflush(stdout); 276 | } 277 | 278 | 279 | return tempVector; 280 | 281 | } 282 | 283 | // Flushes the distance vector of the host. 284 | void resetDistanceVector() 285 | { 286 | for (int i=1;ij%d-->minCost:%hd---->costMatrix[j][i]:%hd-->baseCost:%hd\n",i,j,minCost,costMatrix[j][i],baseCost); 324 | if(minCost==(int16_t)-1&&costMatrix[j][i]==(int16_t)-1) // you cant help me :( // neither your nor the peer can reach 325 | { 326 | if(i==j) // this new condition is being added since we now have something to reset 327 | { 328 | minCost=baseCost; 329 | minHop=costList[i].id; 330 | } 331 | } 332 | else if(minCost==(int16_t)-1) // you cannot reach but your peer can reach 333 | { 334 | minCost=baseCost+costMatrix[j][i]; 335 | minHop=costList[j].id; 336 | } 337 | else if(costMatrix[j][i]!=(int16_t)-1) 338 | { 339 | int16_t value=baseCost+costMatrix[j][i]; 340 | if(value0) 350 | { 351 | distanceVector[i].cost=minCost; 352 | distanceVector[i].nextHopId=minHop; 353 | costMatrix[0][i]=minCost; 354 | } 355 | 356 | /*int32_t value;=(costList[i].cost==(int16_t)-1||v[i].cost==(int16_t)-1)?-1:(costList[i].cost+v[i].cost) ; 357 | if(distanceVector[i].cost==-1) 358 | distanceVector[i].cost=value; 359 | else if(value<=distanceVector[i].cost) 360 | { 361 | distanceVector[i].cost=value; 362 | distanceVector[i].nextHopId=id; 363 | }*/ 364 | } 365 | } 366 | 367 | // Sends out the distance vector to all active neighbours. Also checks if any of the neighbours have died.(3 misses case) 368 | void broadcastDistanceVectorToNeighbours(int isAuto) 369 | { 370 | int numberOfBytesWritten=0; 371 | char* message=createMessageFormatFromVector(&numberOfBytesWritten); 372 | // structure created successfully for sending. 373 | // send to all the neighbours 374 | for(int i=1;i=(3*gUpdateInterval)) 385 | { 386 | costList[i].cost=-1; 387 | // distanceVector[i].cost=-1; 388 | // costMatrix[0][i]=-1; 389 | resetDistanceVector(); 390 | updateSelfDistanceVectorWithVector(false); 391 | gNumberOfNeighbours--; 392 | printf("Neighbour with id:%hd has gone down.\n",costList[i].id); 393 | costList[i].updateCount=-1; 394 | continue; 395 | } 396 | //int sockId=createUDPSocket(costList[i].IP,costList[i].port); 397 | 398 | SocketAddressInfo *socketAddress; // this structure basically stores info about the socket address 399 | socketAddress=(SocketAddressInfo*)malloc(sizeof(SocketAddressInfo)); 400 | socketAddress->sin_family=AF_INET; 401 | socketAddress->sin_port=htons(costList[i].port); 402 | socketAddress->sin_addr.s_addr=costList[i].IP; 403 | //inet_pton(socketAddress->sin_family,ip,&(socketAddress->sin_addr)); 404 | 405 | //create a socket for connecting to server 406 | int socketId=socket(AF_INET,SOCK_DGRAM,0); 407 | int slen=sizeof(SocketAddressInfo); 408 | int retV=sendto(socketId,message,numberOfBytesWritten,0,(struct sockaddr*)socketAddress,(socklen_t)slen); 409 | //printf("err:%d-->ret:%d",errno,retV); 410 | fflush(stdout); 411 | close(socketId); 412 | 413 | } 414 | } 415 | free(message); 416 | } 417 | 418 | int compare(const void* a, const void* b) 419 | { 420 | return (int)(((Node*)a)->id-((Node*)b)->id); 421 | } 422 | 423 | // prints the routing table in the specified format. 424 | void displayRoutingTable() 425 | { 426 | //printf("gTotalNumberOfNodes:%hd",gTotalNumberOfNodes); 427 | Node* tempDV=(Node*)malloc(sizeof(Node)*gTotalNumberOfNodes); 428 | memcpy(tempDV,distanceVector,sizeof(Node)*gTotalNumberOfNodes); 429 | qsort(tempDV,gTotalNumberOfNodes,sizeof(Node),&compare); 430 | for(int i=0;i0) 454 | { 455 | if(str[index]=='\n') 456 | break; 457 | index--; 458 | } 459 | //char *ptr=strrchr(str,'\n'); 460 | //ptr++; 461 | return (str[index+1]-'0'); 462 | 463 | } 464 | 465 | // Read the topology file and setup the costList[] and distanceVector[] arrays. 466 | void initialiseLists() 467 | { 468 | try 469 | { 470 | int fd=open(gTopologyFileName,O_RDONLY); 471 | //printf("%d",errno); 472 | //cgange remove hardbound by calc filesize by stat 473 | char buffer[5000]; 474 | read(fd,buffer,5000); 475 | int baseId=parseStringAndGetLocaLServerId(buffer); 476 | char line[200],*saveptr1,*saveptr2; 477 | //strcpy(line,strtok_r(buffer,"\n",&saveptr1)); 478 | strcpy(line,strtok(buffer,"\n")); 479 | 480 | gTotalNumberOfNodes=atoi(line); 481 | //strcpy(line,strtok_r(NULL,"\n",&saveptr1)); 482 | strcpy(line,strtok(NULL,"\n")); 483 | gNumberOfNeighbours=atoi(line); 484 | for(int i=1,linecount=0;linecountsendData(connectReqMessage); 825 | addConnection(peerConnectConn); 826 | free(fIP); 827 | //resetToPrompt(); 828 | 829 | } 830 | 831 | } 832 | else if(!strcmp(command,"LIST")) 833 | { 834 | listConnections(); 835 | resetToPrompt(); 836 | 837 | } 838 | 839 | else if(!strcmp(command,"DOWNLOAD")) 840 | { 841 | if(isServer) 842 | { 843 | printf("Invalid Command\n"); 844 | resetToPrompt(); 845 | return; 846 | } 847 | 848 | char *fileName=strtok(NULL," "); 849 | char *chunkSizeStr=strtok(NULL," "); 850 | if(!fileName||!chunkSizeStr|| !strlen(fileName)||!strlen(chunkSizeStr)) 851 | printf("Invalid Command Format.\n"); 852 | else 853 | { 854 | downloadActive=true; 855 | lastWrittenByte=0; 856 | downloadFile(fileName,atoi(chunkSizeStr),-1,NULL); 857 | } 858 | printf("Downloading %s...\n",fileName); 859 | resetToPrompt(); 860 | } 861 | 862 | else if(!strcmp(command,"TERMINATE")) 863 | { 864 | char *idStr; 865 | idStr=strtok(NULL," "); 866 | if(strlen(idStr)==0) 867 | printf("Invalid Usage.\n"); 868 | else 869 | { 870 | if(terminateConnection(atoi(idStr),false)) 871 | printf("Connection Terminated.\n"); 872 | else 873 | printf("Operation not permitted.\n"); 874 | } 875 | 876 | 877 | resetToPrompt(); 878 | } 879 | else if(!strcmp(command,"EXIT")) 880 | { 881 | terminateAllConnections(); 882 | //printf("\n*** Transferred %lld bytes in %lld us\n",totalBytesTransferred,totalTimeInMicroSecs); 883 | exit(0); 884 | } 885 | 886 | else if(!strcmp(command,"SIP")) 887 | { 888 | displayServerIPList(); 889 | resetToPrompt(); 890 | } 891 | else if(!strcmp(command,"CREATOR")) 892 | { 893 | printf("Name:Subhranil Banerjee\nUBITName:subhrani\nEmail:subhrani@buffalo.edu\n"); 894 | resetToPrompt(); 895 | } 896 | */ 897 | else 898 | { 899 | printf("Command not found.\n"); 900 | resetToPrompt(); 901 | } 902 | 903 | //} 904 | 905 | } 906 | 907 | 908 | // Receives data on the UDP socket. Also contains the implementation of the timer. 909 | void setupReceiver() 910 | { 911 | //int sendFileDesc,recvFileDesc; 912 | 913 | /* observedSockets file descriptor list and max value */ 914 | fd_set observedSockets; 915 | int fdmax; 916 | int mainSocket; 917 | // defining the address for the main socket 918 | 919 | SocketAddressInfo *socketAddress; // this structure basically stores info about the socket address 920 | socketAddress=(SocketAddressInfo*)malloc(sizeof(SocketAddressInfo)); 921 | socketAddress->sin_family=AF_INET; 922 | 923 | inet_pton(socketAddress->sin_family,gLocalIP,&(socketAddress->sin_addr)); 924 | socketAddress->sin_port=htons(gLocalPort); 925 | 926 | //create a socket for accepting incoming connections 927 | 928 | mainSocket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); 929 | if(mainSocket==-1) 930 | { 931 | printf("Error in creating socket"); 932 | exit(0); 933 | } 934 | 935 | // bind the socket to the addressinfo 936 | 937 | if(bind(mainSocket,(struct sockaddr*)socketAddress,sizeof(SocketAddressInfo))==-1) 938 | { 939 | printf("Error in binding socket IP address"); 940 | exit(0); 941 | } 942 | 943 | // Begin code for socket listening 944 | 945 | /* clear the observedSockets and temp sets */ 946 | FD_ZERO(&observedSockets); 947 | 948 | 949 | timeout.tv_sec=gUpdateInterval; 950 | timeout.tv_usec=0; 951 | // run loop for observing sockets 952 | 953 | while(true) 954 | { 955 | /* add the listener to the observedSockets set */ 956 | FD_SET(mainSocket, &observedSockets); 957 | FD_SET(0,&observedSockets); 958 | 959 | /* keep track of the biggest file descriptor */ 960 | fdmax = mainSocket ; /* so far, it's this one*/ 961 | 962 | 963 | int activity=select(fdmax+1,&observedSockets,NULL,NULL,&timeout); // blocking all until there is some activity on any of the sockets 964 | if(activity<0) 965 | { 966 | if(errno==EINTR) 967 | continue; 968 | printf("error in select"); 969 | return ; 970 | } 971 | else if(activity==0) 972 | { 973 | broadcastDistanceVectorToNeighbours(true); 974 | timeout.tv_sec=gUpdateInterval; 975 | timeout.tv_usec=0; 976 | } 977 | else { 978 | if(FD_ISSET(mainSocket,&observedSockets)) // .. there has been activity on the mainSocket. thus there s a new connection that needs to be added 979 | { 980 | char incomingMessage[MAXPACKETSIZE]; 981 | int numberOfBytesRecvd=0; 982 | numberOfBytesRecvd=recv(mainSocket,&incomingMessage,MAXPACKETSIZE-1,0); 983 | 984 | //Handle the data 985 | int32_t id; 986 | Node* incomingVector=convertMessageIntoDistanceVector(incomingMessage,&id); 987 | 988 | 989 | //resetToPrompt(); 990 | updateSelfDistanceVectorWithVector(false); 991 | 992 | } 993 | else if(FD_ISSET(0,&observedSockets)) 994 | { 995 | displayShell(); 996 | } 997 | } 998 | } 999 | 1000 | } 1001 | int main(int argc,char *argv[]) 1002 | { 1003 | init(); 1004 | parseShellArguments(argc,argv); 1005 | strcpy(gLocalIP,getLocalIP()); 1006 | initialiseLists(); 1007 | resetToPrompt(); 1008 | setupReceiver(); 1009 | } 1010 | 1011 | 1012 | 1013 | 1014 | --------------------------------------------------------------------------------