#include //#include // added for syscall //_syscall2(int, add_routable_node, unsigned int, arg1, int, arg2); //some global variables here //needed for signal handlers EVENT event; //to decide which event has been triggered, our machine is event driven struct timeval blockTime; //time for which select waits int retval; static sigjmp_buf jmpbuf; int firstSigFlag = 0; unsigned short /* this function generates header checksums */ csum (unsigned short *buf, int nwords) { unsigned long sum; for (sum = 0; nwords > 0; nwords--) sum += *buf++; sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; } void DDCA::initDDCA() { //commenting out this section cause this is old and we dont know //whether we are gonna use it /* joinTimer = DEFAULT_JOIN_TIMER; adoptTimer = DEFAULT_ADOPT_TIMER; */ initTimer (JOIN_TIMER); initTimer (ADOPT_TIMER); initTimer (HELLO_TIMER); initThreshold (); //cout << "Entering and exiting initDDCA, initializing timers" << endl; } /* initialize all raw stuff right here 1)in the IP packet the stuff that does not change should be put in some initializer 2)Also got to write a function to accept the payload */ void DDCA::initRAW() { char buf[100]; int sendbuff; struct hostent *ht; struct sockaddr_in sin; sockfd = socket (PF_INET, SOCK_RAW, IPPROTO_DDCA); /* open raw socket */ if (sockfd < 0) { perror("Error opening the socket!"); } /*begin get our own IP address*/ if (gethostname (buf, sizeof (buf)) < 0) { perror ("gethostname"); exit(1); } if ((ht = gethostbyname (buf)) == NULL) { perror ("blah error"); exit (0); } this->ip_addr = inet_addr(inet_ntoa(*((struct in_addr*)ht->h_addr))); sin.sin_addr.s_addr = this->ip_addr; this->myNid = this->ip_addr; /*initialized our network id*/ /* finally, it is very advisable to do a IP_HDRINCL call, to make sure that the kernel knows the header is included in the data, and doesn't insert its own header into the packet before our data */ { /* lets do it the ugly way.. */ int one = 1; const int *val = &one; if (setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) printf ("Warning: Cannot set HDRINCL!\n"); } /*allow broadcast on this socket*/ if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&sendbuff, sizeof(sendbuff)) < 0) { perror("Error setting broadcast flags"); } } //note that the building of the packet should go like this //how should we build the packet? char *DDCA::buildDDCAPacket(int msg_type) { struct ddca_header * dh = (struct ddca_header *)(datagram_snd + IP_HEADER_LENGTH); dh->ver = 1; dh->proto = PKT_DDCA; dh->ttl = 255; //no significance right now dh->reserved = 0; //consider null dh->seq = 0; dh->nid = ip_addr; dh->cid = myCid; // myCid is set to 0 if not in any cluster //dh->cid = 0;//nothing until we join a cluster dh->csum = 197; //right now we put it to zero. anyways when we calculate //checksum, the checksum field itself is considered zero. //guess that the integers and longs are same in length so should not matter //if we use htonl for integers //putting the message directly in the body of the packet struct ddca_body *db = (struct ddca_body *)(datagram_snd + IP_HEADER_LENGTH + sizeof (struct ddca_header)); db->msg_type = htonl(msg_type); db->nid = ip_addr; db->alpha = alpha; db->t = t; //cout << "***dummy is : " << ntohl(*dummy) << endl; return datagram_snd; } /* * Note that whenever we decide to send a packet, we make sure that the size is always less than the * MTU size so that IP never fragments our packets. If at all it does, reassembly is also done by it * and not by us. */ void DDCA::broadcastMsg(char *msg, int len) { //July 16th addition //implies proper broadcast struct ddca_header *dh = (struct ddca_header *)(msg + sizeof(struct ip)); dh->dest_cid = 0; dh->dest_nid = 0; struct sockaddr_in sin; sin.sin_family = AF_INET; iph_snd = (struct ip*)msg;//still to check how long a datagram can be //memset(datagram_snd, 0, 4096); sin.sin_addr.s_addr = inet_addr("255.255.255.255"); //still to fill up the broadcast address sin.sin_port = htons(999); //leaving for now, guess will remove later iph_snd->ip_hl = 5; iph_snd->ip_v = 4; iph_snd->ip_tos = 0; iph_snd->ip_len = sizeof(struct ip) + len; //check, this means no payload iph_snd->ip_id = htonl(54321); //cause we never will send more than what //ip can handle iph_snd->ip_off = 0; //offset 0 iph_snd->ip_ttl = 255; //live long packet! iph_snd->ip_p = IPPROTO_DDCA; //the DDCA protocol iph_snd->ip_sum = 0; //checksum will be calculated later iph_snd->ip_src.s_addr = this->ip_addr; //our ip address iph_snd->ip_dst.s_addr = sin.sin_addr.s_addr; //the broadcast address //calculate the checksum again iph_snd->ip_sum = csum ((unsigned short *) datagram_snd, iph_snd->ip_len >> 1); /* commanting out to change datagram_snd to msg and hopefully, it will work. if(sendto(sockfd, datagram_snd, iph_snd->ip_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror ("BCast Error"); } */ if(sendto(sockfd, msg, iph_snd->ip_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror ("BCast Error"); } } void DDCA::broadcastMsg_u(char *msg, int len, unsigned int send_to) { //July 16th addition //implies proper broadcast struct ddca_header *dh = (struct ddca_header *)(msg + sizeof(struct ip)); dh->dest_cid = 0; dh->dest_nid = send_to; struct sockaddr_in sin; sin.sin_family = AF_INET; iph_snd = (struct ip*)msg;//still to check how long a datagram can be //memset(datagram_snd, 0, 4096); sin.sin_addr.s_addr = inet_addr("255.255.255.255"); //still to fill up the broadcast address sin.sin_port = htons(999); //leaving for now, guess will remove later iph_snd->ip_hl = 5; iph_snd->ip_v = 4; iph_snd->ip_tos = 0; iph_snd->ip_len = sizeof(struct ip) + len; //check, this means no payload iph_snd->ip_id = htonl(54321); //cause we never will send more than what //ip can handle iph_snd->ip_off = 0; //offset 0 iph_snd->ip_ttl = 255; //live long packet! iph_snd->ip_p = IPPROTO_DDCA; //the DDCA protocol iph_snd->ip_sum = 0; //checksum will be calculated later iph_snd->ip_src.s_addr = this->ip_addr; //our ip address iph_snd->ip_dst.s_addr = sin.sin_addr.s_addr; //the broadcast address //calculate the checksum again iph_snd->ip_sum = csum ((unsigned short *) datagram_snd, iph_snd->ip_len >> 1); /* commanting out to change datagram_snd to msg and hopefully, it will work. if(sendto(sockfd, datagram_snd, iph_snd->ip_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror ("BCast Error"); } */ if(sendto(sockfd, msg, iph_snd->ip_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror ("BCast Error"); } } void DDCA::broadcastMsgRT(char *msg, int len) { /* struct sockaddr_in sin; char pkt[IP_HEADER_LENGTH + 1500]; sin.sin_family = AF_INET; iph_snd = (struct ip*)pkt; memcpy(pkt + IP_HEADER_LENGTH, msg, len); sin.sin_addr.s_addr = inet_addr("255.255.255.255"); sin.sin_port = htons(999); iph_snd->ip_hl = 5; iph_snd->ip_v = 4; iph_snd->ip_tos = 0; iph_snd->ip_len = sizeof(struct ip) + len; iph_snd->ip_id = htonl(54321); iph_snd->ip_off = 0; iph_snd->ip_ttl = 255; iph_snd->ip_p = IPPROTO_DDCA; iph_snd->ip_sum = 0; iph_snd->ip_src.s_addr = this->ip_addr; iph_snd->ip_dst.s_addr = sin.sin_addr.s_addr; iph_snd->ip_sum = csum ((unsigned short *) pkt, iph_snd->ip_len >> 1); if(sendto(sockfd, pkt, iph_snd->ip_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror ("BCast Error"); } */ struct sockaddr_in sin; sin.sin_family = AF_INET; iph_snd = (struct ip*)msg;//still to check how long a datagram can be sin.sin_addr.s_addr = inet_addr("255.255.255.255"); sin.sin_port = htons(1590); iph_snd->ip_hl = 5; iph_snd->ip_v = 4; iph_snd->ip_tos = 0; iph_snd->ip_len = sizeof(struct ip) + len ; //check, this means no payload iph_snd->ip_id = htonl(54321); iph_snd->ip_off = 0; //offset 0 iph_snd->ip_ttl = 255; //live long packet! iph_snd->ip_p = IPPROTO_DDCA; //the DDCA protocol iph_snd->ip_sum = 0; //checksum will be calculated later iph_snd->ip_src.s_addr = this->ip_addr; //our ip address iph_snd->ip_dst.s_addr = sin.sin_addr.s_addr; //the broadcast address //calculate the checksum again iph_snd->ip_sum = csum ((unsigned short *) msg, iph_snd->ip_len >> 1); if(sendto(sockfd, msg, iph_snd->ip_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror ("ROUTER BCast Error"); } } void DDCA::unicastMsg(char *msg, int len, int send_to) { //July 16th addition //implies proper broadcast struct ddca_header *dh = (struct ddca_header *)(msg + sizeof(struct ip)); dh->dest_cid = 0; dh->dest_nid = send_to; struct sockaddr_in sin; sin.sin_family = AF_INET; iph_snd = (struct ip*)msg;//still to check how long a datagram can be //memset(datagram_snd, 0, 4096); sin.sin_addr.s_addr = send_to; sin.sin_port = htons(1590); iph_snd->ip_hl = 5; iph_snd->ip_v = 4; iph_snd->ip_tos = 0; iph_snd->ip_len = sizeof(struct ip) + len ; //check, this means no payload iph_snd->ip_id = htonl(54321); iph_snd->ip_off = 0; //offset 0 iph_snd->ip_ttl = 255; //live long packet! iph_snd->ip_p = IPPROTO_DDCA; //the DDCA protocol iph_snd->ip_sum = 0; //checksum will be calculated later iph_snd->ip_src.s_addr = this->ip_addr; //our ip address iph_snd->ip_dst.s_addr = sin.sin_addr.s_addr; //the broadcast address //calculate the checksum again iph_snd->ip_sum = csum ((unsigned short *) msg, iph_snd->ip_len >> 1); if(sendto(sockfd, msg, iph_snd->ip_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror ("UCast Error"); } } /* for all state processings check how to send the message using broadcast and unicast */ // parent state processing void DDCA::parentState (EVENT which) { ddca_header *tmp_dh; RTEntry rte; cout <<"PARENT STATE handling an event" << endl; switch (which) { case CLUSTER_DISCONNECTION: /* going to get this worked out in the goto broadcastMsg (buildDDCAPacket (JOIN_REQUEST), DDCA_LEN); setTimer (JOIN_TIMER); joinFlag = UNSET; retryFlag = UNSET; myState = UNCLUSTERED; cancelTimer (HELLO_TIMER); // cancel the hello timer. //must flush the routing table router->flushTable(); */ event = CLUSTER_DISCONNECTION; goto cluster_disconnect; //break; case RCV_JOIN_REQUEST: // checking if max cluster is reached or not if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "** Error : max cluster reached **" << endl; break; } // if cluster strength satisfied && max cluster is not reached { struct in_addr in; in.s_addr = rcvNid; cout <<"Join Request frm a child with id: " << inet_ntoa(in) << endl; //BUG: if we rcv a join request for a guy who already is in our //database, we drop the previous entry broadcastMsg_u (buildDDCAPacket (JOIN_RESPONSE), DDCA_LEN, rcvNid); } break; case RCV_MAX_CLUSTER: if (rcvCid == myCid) // check to see if same cluster { clusterSize = MAX_CLUSTER_SIZE; cerr << "Message received -- cluster maxed out" << endl; } break; case RCV_GATEWAY: cerr << "in parent received gateway broadcast" << endl; if (rcvCid == myCid) // if node is part of cluster { cerr << "GOING TO ADD GW in parent" << endl; //add_routable_node(rcvNid, ADD_GW); add_gateway (rcvNid); // add node as a gateway to our list -- thru system call } break; case RCV_NOT_GATEWAY: cerr << " received NOT GATEWAY broadcast" << endl; if (rcvCid == myCid) { cerr << " REMOVING GATEWAY FROM PARENT" << endl; // add_routable_node (rcvNid, DELETE_GW); remove_gateway (rcvNid); } break; case RCV_ADOPT_REQUEST: // checking if max cluster is reached or not if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "** Error : max cluster reached **" << endl; break; } // if cluster strength satisfied && max cluster is not reached { //first update your own tables saying that this is //our child broadcastMsg_u (buildDDCAPacket (ADOPT_RESPONSE), DDCA_LEN, rcvNid); } break; case RCV_JOIN_CLUSTER: //child has finally said that he is gonna join us, so if we are still free //we will insert his entry in our table and let him know /* if(we still have space in our cluster) { final admit into our cluster } */ // checking to see if the size of the cluster is ok or not if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "** Error : max cluster reached **" << endl; broadcastMsg (buildDDCAPacket (MAX_CLUSTER), DDCA_LEN); break; } //here updating the table tmp_dh = (struct ddca_header*)(datagram_rcv + sizeof(struct ip)); rte.nid = tmp_dh->nid; rte.gw = myNid; rte.cid = myCid; // since child is joining his cid = myCid if (router->insertEntry(&rte) > 0) { clusterSize++; cout << "cluster size = " << clusterSize << endl; if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "WAAAH !!! MAX REACHED" << endl; broadcastMsg (buildDDCAPacket (MAX_CLUSTER), DDCA_LEN); } } router->printTable(); break; /* do this later //03.19.02 Hello messages to update Border Node status case HELLO_MSG: tmp_dh = (struct ddca_header*)(datagram_rcv + sizeof(struct ip)); rte.nid = tmp_dh->nid; //if we rcv a hello msg from a node that does not belong to our cluster, //we declare ourselves a border node if(tmp_dh->cid != myCid) { //note down all the info, about the entry to another cluster //and then we are a border node router->setBorderNode(); } break; */ /* do some work when the hello timer expires */ case HELLO_TIMER_EXPIRATION: send_hello (); setTimer (HELLO_TIMER); // update our routing table router->updateRoutingTable (); // update gateway status if we are a gateway node if (nodeStatus == IS_GATEWAY) { if (router->updateGatewayStatus () == 0) { unsetGateway (); // basically no more me a gateway cerr << " ME NO PARENT GATEWAY" << endl; broadcastMsg (buildDDCAPacket (NOT_GATEWAY), DDCA_LEN); // delete from proc using system call //add_routable_node (myNid, DELETE_GW); remove_gateway (myNid); } } router->printTable (); // check for the cluster size and if no other fire event if (clusterSize == 1) { event = CLUSTER_DISCONNECTION; goto cluster_disconnect; } break; case RCV_HELLO_MSG: // do some work --> update the tables. struct in_addr ha; // added just to print the address out tmp_dh = (struct ddca_header*)(datagram_rcv + sizeof(struct ip)); //if we rcv a hello msg from a node that does not belong to our cluster, //we declare ourselves a border node if(tmp_dh->cid != myCid) { cerr << " CIDS are different out here" << endl; //note down all the info, about the entry to another cluster //and then we are a border node // router->setBorderNode(); some problem here ha.s_addr = tmp_dh->cid; cerr << "WAY TO GO -- me a gateway node" << endl; cerr << "to CLUSTER with ID: "<< inet_ntoa(ha) << endl << endl; cout << "status was : " << nodeStatus << endl; setGateway (); //add_routable_node (myNid, ADD_GW); add_gateway (myNid); cerr << "new status is : " << nodeStatus << endl; // broadcast now that i am a gateway node broadcastMsg (buildDDCAPacket (GATEWAY), DDCA_LEN); } ha.s_addr = rcvNid; cerr << " YIPEE !!!!! received a hello from " << inet_ntoa(ha) << endl; cerr << "UP TO HERE THANK GOD" << endl; // adding the route to the kernel routing table router->addRoute (rcvNid, myNid); add_routable (rcvNid); if (rcvCid == myCid) { //add_routable_node (rcvNid, ADD_RT); } // updating the routing tables for this particular rcvNid rte.nid = rcvNid; rte.gw = myNid; rte.cid = rcvCid; // sending hello --> cid exists router->insertEntry (&rte); break; cluster_disconnect: if (event == CLUSTER_DISCONNECTION) // fire only if correct event { cerr << " parent: NO !!! ME DISCONNECTED" << endl; broadcastMsg (buildDDCAPacket (JOIN_REQUEST), DDCA_LEN); setTimer (JOIN_TIMER); joinFlag = UNSET; retryFlag = UNSET; myState = UNCLUSTERED; cancelTimer (HELLO_TIMER); // cancel the hello timer. //must flush the routing table router->flushTable(); break; } } } // unclustered state processing void DDCA::unclusteredState (EVENT which) { switch (which) { case JOIN_TIMER_EXPIRATION: if (retryFlag == SET) { broadcastMsg (buildDDCAPacket (JOIN_REQUEST), DDCA_LEN); setTimer (JOIN_TIMER); retryFlag = UNSET; } else if (joinFlag == SET) { struct in_addr ha; myCid = joinCluster (); // get this from the join cluster function, ha.s_addr = myCid; cout << "Problem = " << inet_ntoa (ha) << endl; // as with orphan, takes care of CHG_CLUSTER router->flushTable (); // just in case myState = CHILD; cout << "entered child state" << endl; // 4th handshake may be useful for max cluster //TODO check if this might be buggy broadcastMsg_u(buildDDCAPacket (JOIN_CLUSTER), DDCA_LEN, old_parent.nid); setTimer (HELLO_TIMER); // start the hello timer. } else { myCid = myNid; setTimer (ADOPT_TIMER); adoptFlag = UNSET; joinFlag = SET; router->flushTable (); // just in case myState = ORPHAN; clusterSize = 1; // i am the only one now cout << "size of cluster is : " << clusterSize << endl; cout << "entering the orphan state" << endl; setTimer (HELLO_TIMER); // start hello for orphan also. } //wont hurt if we set this flag to false here //if the retryFlag is set, means nobody replied, so flag //is false anyways, in any other case, state has changed //so must set the flag to false. // setStateFlag(FALSE); initThreshold (); break; case RCV_JOIN_RESPONSE: retryFlag = UNSET; joinFlag = SET; struct ddca_body *new_parent; new_parent = (struct ddca_body *)(datagram_rcv + sizeof(struct ip) + sizeof(struct ddca_header)); //select the best parent before the final joining //if recieveing from the first parent go here /* if( getStateFlag() == FALSE) { old_parent = *new_parent; setStateFlag(TRUE); break; } */ //else if already one parent was found, check if new //parent is better than the old one or no. selectBestParent(new_parent); break; case RCV_JOIN_REQUEST: if (myNid > rcvNid) { retryFlag = SET; } //what about the else case? //should we become a parent and start a cluster? //does not make sense here to break for both if and else break; } } // child state processing void DDCA::childState (EVENT which) { RTEntry rte; cout <<"Child State:Handling an Event" << endl; switch (which) { case CLUSTER_DISCONNECTION: /* going to get this worked out in the goto broadcastMsg (buildDDCAPacket (JOIN_REQUEST), DDCA_LEN); setTimer (JOIN_TIMER); retryFlag = UNSET; joinFlag = UNSET; myState = UNCLUSTERED; cancelTimer (HELLO_TIMER); // cancel the hello timer. //must flush the routing table router->flushTable(); */ event = CLUSTER_DISCONNECTION; goto cluster_disconnect; //break; case CLUSTER_PARTITION: setTimer (JOIN_TIMER); retryFlag = SET; joinFlag = UNSET; myState = UNCLUSTERED; router->flushTable (); // must flush the routing table. cancelTimer (HELLO_TIMER); // cancel the hello timer. break; case RCV_GATEWAY: cerr << "received the gateway broadcast" << endl; if (rcvCid == myCid) // if node is part of my cluster { cerr << "GOING TO ADD GATEWAY in child" << endl; //add_routable_node (rcvNid, ADD_GW); add_gateway (rcvNid); // add node as a gateway to our list -- thru system call } break; case RCV_NOT_GATEWAY: cerr << " received NOT GATEWAY broadcast" << endl; if (rcvCid == myCid) { cerr << " REMOVING GATEWAY FROM CHILD" << endl; // add_routable_node (rcvNid, DELETE_GW); remove_gateway (rcvNid); } break; case RCV_MAX_CLUSTER: clusterSize = MAX_CLUSTER_SIZE; cerr << "Message received -- cluster maxed out" << endl; break; case RCV_JOIN_REQUEST: // checking if max cluster is reached or not if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "** Error : max cluster reached **" << endl; break; } // if cluster strength is satisfied && max cluster not reached { broadcastMsg_u (buildDDCAPacket (JOIN_RESPONSE), DDCA_LEN, rcvNid); } //4 way handshake to take place here break; case RCV_ADOPT_REQUEST: // checking if max cluster is reached or not if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "** Error : max cluster reached **" << endl; break; } // if cluster strength is satisfied && max cluster not reached { broadcastMsg_u (buildDDCAPacket (ADOPT_RESPONSE), DDCA_LEN, rcvNid); } break; /* do some work when the hello timer expires */ case HELLO_TIMER_EXPIRATION: send_hello (); setTimer (HELLO_TIMER); // update our routing table router->updateRoutingTable (); // update gateway status if we are a gateway node if (nodeStatus == IS_GATEWAY) { if (router->updateGatewayStatus () == 0) { unsetGateway (); // basically no more me a gateway cerr << "ME NO CHILD GATEWAY" << endl; broadcastMsg (buildDDCAPacket (NOT_GATEWAY), DDCA_LEN); // delete from proc using system call //add_routable_node (myNid, DELETE_GW); remove_gateway (myNid); } } router->printTable (); // check for the cluster size and if no other fire event if (clusterSize == 1) { event = CLUSTER_DISCONNECTION; goto cluster_disconnect; } break; case RCV_HELLO_MSG: // do some work --> update the clustering tables. struct in_addr ha; // added just to print the address out //tmp_dh (struct ddca_header *)(datagram_rcv + sizeof (struct ip)); if (rcvCid != myCid) { // note down all the info, about the entry to anothr cluster //router->setBorderNode (); ha.s_addr = rcvCid; cerr << "WAY TO GO -- me a gateway node" << endl; cerr << "to CLUSTER with ID: " << inet_ntoa (ha) << endl; cout << "status was : " << nodeStatus << endl; setGateway (); //add_routable_node (myNid, ADD_GW); add_gateway (myNid); cerr << "new status is : " << nodeStatus << endl; // broadcast now that i am a gateway node broadcastMsg (buildDDCAPacket (GATEWAY), DDCA_LEN); } ha.s_addr = rcvNid; cerr << " YIPEE !!!!! received a hello from " << inet_ntoa(ha) << endl; // adding the route to the kernel routing table router->addRoute (rcvNid, myNid); add_routable (rcvNid); if (rcvCid == myCid) { //add_routable_node (rcvNid, ADD_RT); } // updating the routing tables for this particular rcvNid rte.nid = rcvNid; rte.gw = myNid; rte.cid = rcvCid; // sending hello --> cid exists router->insertEntry (&rte); break; case RCV_JOIN_CLUSTER: //child has finally said that he is gonna join us, so if we are still free //we will insert his entry in our table and let him know /* if(we still have space in our cluster) { final admit into our cluster } */ // checking to see if the size of the cluster is ok or not if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "** max cluster reached **" << endl; broadcastMsg (buildDDCAPacket (MAX_CLUSTER), DDCA_LEN); break; } //here updating the table //ddca_header *tmp_dh = (struct ddca_header*)(datagram_rcv + sizeof(struct ip)); rte.nid = rcvNid; rte.gw = myNid; rte.cid = myCid; // since child is joining his cid = myCid if (router->insertEntry(&rte) > 0) { clusterSize++; cout << "cluster size = " << clusterSize << endl; if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "WAAAH !!! MAX REACHED" << endl; broadcastMsg (buildDDCAPacket (MAX_CLUSTER), DDCA_LEN); } } router->printTable(); break; cluster_disconnect: if (event == CLUSTER_DISCONNECTION) // fire only if correct event { cerr << " child: NO !!! ME DISCONNECTED" << endl; broadcastMsg (buildDDCAPacket (JOIN_REQUEST), DDCA_LEN); setTimer (JOIN_TIMER); joinFlag = UNSET; retryFlag = UNSET; myState = UNCLUSTERED; cancelTimer (HELLO_TIMER); // cancel the hello timer. //must flush the routing table router->flushTable(); break; } /* old code out here //here updating the table RTEntry rte; ddca_header *tmp_dh = (struct ddca_header*)(datagram_rcv + sizeof(struct ip)); rte.nid = tmp_dh->nid; router->insertEntry(&rte); router->printTable(); break; */ } } // orphan state processing void DDCA::orphanState (EVENT which) { cout <<"Handling Event in orphanState" << endl; switch (which) { case JOIN_TIMER_EXPIRATION: cout << "entering jtimer expiration" << endl; if (joinFlag == SET) { myCid = joinCluster (); // get from join cluster, this will take care // of the case of CHG_CLUSTER when u want to join someone cerr << "changing state to child" << endl; // do we need the 4th hand shake ?? -- might be useful for max_cluster broadcastMsg_u(buildDDCAPacket(JOIN_CLUSTER), DDCA_LEN, old_parent.nid); myState = CHILD; setTimer (HELLO_TIMER); // start the hello timer. } else { cout << "in the other else in orphan" << endl; setTimer (ADOPT_TIMER); adoptFlag = UNSET; //modification -- must set this to broadcast //each time joinFlag = SET; } //must set the state flag to false break; case ADOPT_TIMER_EXPIRATION: if (joinFlag == SET) { if(adoptFlag == UNSET) { broadcastMsg (buildDDCAPacket (ADOPT_REQUEST), DDCA_LEN); //send_hello (); // send hello at the same time also cout <<"broadcasting in orphanState" << endl; //setTimer (JOIN_TIMER); joinFlag = UNSET; adoptFlag = SET; } else ;// setTimer(JOIN_TIMER); } else ;//setTimer (JOIN_TIMER); // doubt here setTimer(JOIN_TIMER); break; /* Not needed for orphan -- we will see about that */ case HELLO_TIMER_EXPIRATION: cerr << "*** in here sending the hello ***" << endl; send_hello (); setTimer (HELLO_TIMER); // update the routing tables router->updateRoutingTable (); // update gateway status if we are a gateway node if (nodeStatus == IS_GATEWAY) { if (router->updateGatewayStatus () == 0) { unsetGateway (); // basically no more me a gateway cerr << " ME NO ORPHAN GATEWAY" << endl; //add_routable_node (myNid, DELETE_GW); remove_gateway (myNid); } } router->printTable (); /* not needed for orphan as he/she is not part of cluster :( if (clusterSize == 1) { goto cluster_disconnect; } */ break; case RCV_HELLO_MSG: struct in_addr ha; RTEntry rte; ha.s_addr = rcvCid; if (rcvCid != myCid) { cerr << " WAY TO GO - me an orphan gateway" << endl; cerr << " to cluster with ID: " << inet_ntoa (ha) << endl; setGateway (); //add_routable_node (myNid, ADD_GW); add_gateway (myNid); } // adding route to the kernel routing table router->addRoute (rcvNid, myNid); // not needed to add route in orphan as we are not in any cluster //add_routable_node (rcvNid, ADD_RT); // we need to add the route if we need to send out packets add_routable (rcvNid); // updating the routing tables for this particular rcvNid rte.nid = rcvNid; rte.gw = myNid; rte.cid = rcvCid; // sending hello --> cid exists router->insertEntry (&rte); break; case RCV_JOIN_REQUEST: cerr <<"orphan: join request rcvd" << endl; // if cluster strength is satisfied { broadcastMsg_u (buildDDCAPacket (JOIN_RESPONSE), DDCA_LEN, rcvNid); adoptFlag = UNSET; joinFlag = UNSET; event = CLUSTER_EXPANSION; goto expand_cluster; } break; case RCV_ADOPT_REQUEST: cerr <<"orphan: adopt request rcvd" << endl; if (myNid < rcvNid /* && check link strengh */) { cout << "myNid < rcvNid so adopted the guy" << endl; cout.flush(); broadcastMsg_u (buildDDCAPacket (ADOPT_RESPONSE), DDCA_LEN, rcvNid); adoptFlag = UNSET; joinFlag = UNSET; // as for now fire the cluster expansion immediately, later // on wait for the do_cluster reply before firing this, // that way we can make sure that the child has replied event = CLUSTER_EXPANSION; // to make sure to get out at end goto expand_cluster; } else { cerr <<"myNid > rcvNid so could not adopt" << endl; } break; case RCV_ADOPT_RESPONSE: cerr <<"orphan: adopt response rcvd" << endl; if (adoptFlag == SET) joinFlag = SET; struct ddca_body *new_parent; new_parent = (struct ddca_body *)(datagram_rcv + sizeof(struct ip) + sizeof(struct ddca_header)); //select the best parent before the final joining //if recieveing from the first parent go here selectBestParent(new_parent); break; case CLUSTER_EXPANSION: break; case RCV_JOIN_CLUSTER: // no need to check for max cluster as i am an orphan (poor me) // make the child join and update the clustering tables { broadcastMsg_u (buildDDCAPacket (JOIN_CLUSTER), DDCA_LEN, rcvNid); adoptFlag = UNSET; joinFlag = UNSET; event = CLUSTER_EXPANSION; goto expand_cluster; } //REMEMBER THAT THE FOUR expand_cluster: if (event == CLUSTER_EXPANSION) // fire only if correct event { cerr <<"orphan: cluster expansion fired" << endl; cancelTimer (JOIN_TIMER); cancelTimer (ADOPT_TIMER); //here updating the table RTEntry rte; ddca_header *tmp_dh = (struct ddca_header*)(datagram_rcv + sizeof(struct ip)); cout << "hha" << endl; router->flushTable (); // flush all entries just in case myState = PARENT; cout << "entered the parent state" << endl; myCid = myNid; // set myCid as my own ip as i am parent rte.nid = tmp_dh->nid; rte.gw = myNid; rte.cid = myCid; // i am adopting --> cid = myCid if (router->insertEntry(&rte) >= 0) { clusterSize++; cout << "cluster size = " << clusterSize << endl; if (clusterSize >= MAX_CLUSTER_SIZE) { cerr << "WAAAH !!! MAX REACHED" << endl; broadcastMsg (buildDDCAPacket (MAX_CLUSTER), DDCA_LEN); } } router->printTable(); cout << " upto here" << endl; /* old code //Enter the routing data about this child in our table RTEntry rte; ddca_header *tmp_dh = (struct ddca_header*)(datagram_rcv + sizeof(struct ip)); rte.nid = tmp_dh->nid; router->insertEntry(&rte); router->printTable(); */ cancelTimer (HELLO_TIMER); // cancel the previous timer setTimer (HELLO_TIMER); // start the hello timer. break; } } } void join_action (int signo, siginfo_t *info, void *context) { /* do the action required when the join timer expires */ cout << "join_action invoked" << endl; // setting the event that occured event = JOIN_TIMER_EXPIRATION; cerr << " event in join handler = " << event << endl; retval = -1; // setting the long jump if(firstSigFlag == 0) return; siglongjmp (jmpbuf, 1); } void adopt_action (int signo, siginfo_t *info, void *context) { /* do the action required when the adopt timer expires */ cout << "adopt_action invoked" << endl; // setting the event that occured event = ADOPT_TIMER_EXPIRATION; cerr << " event in adopt handler = " << event << endl; retval = -1; // setting the long jump siglongjmp (jmpbuf, 1); } void hello_action (int signo, siginfo_t *info, void *context) { cout << "hello_action invoked" << endl; event = HELLO_TIMER_EXPIRATION; cerr << " event in hello handler = " << event << endl; retval = -1; // setting the long jump siglongjmp (jmpbuf, 1); } // initialize the key as we compare it everytime void DDCA::initThreshold () { old_parent.alpha = ALPHA_THRESHOLD; old_parent.t = T_THRESHOLD; old_parent.nid = 0; // cout << "key initialized out here" << endl; // cout << "alpha = " << key->alpha << "\t t = " << key->t << endl; } /* intialize the timers and their associated structures */ /* for the timers, give them initial values, decide about the intervals later on */ void DDCA::initTimer (TIMER which) { struct itimerspec dummy; switch (which) { case JOIN_TIMER: joinEvent.sigev_notify = SIGEV_SIGNAL; joinEvent.sigev_signo = JOIN_SIGNAL; joinEvent.sigev_value.sival_ptr = &joinTimer; joinSpec.it_value.tv_sec = JOIN_EXPIRE_SEC; joinSpec.it_value.tv_nsec = JOIN_EXPIRE_NSEC; joinSpec.it_interval.tv_sec = 0L; joinSpec.it_interval.tv_nsec = 0L; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = join_action; sigemptyset (&sa.sa_mask); // adding extra signals to be blocked sigaddset (&sa.sa_mask, ADOPT_SIGNAL); sigaddset (&sa.sa_mask, HELLO_SIGNAL); if (sigaction (JOIN_SIGNAL, &sa, NULL)) { perror ("sigaction failed"); exit (1); } if (timer_create (CLOCK_REALTIME, &joinEvent, &joinTimer)) { perror ("joinTimer creation"); exit (1); } /* check to see if the other timer exists or not */ if (timer_gettime (adoptTimer, &dummy) && timer_gettime (helloTimer, &dummy)) { sigemptyset (&set); } sigaddset (&set, JOIN_SIGNAL); break; case ADOPT_TIMER: adoptEvent.sigev_notify = SIGEV_SIGNAL; adoptEvent.sigev_signo = ADOPT_SIGNAL; adoptEvent.sigev_value.sival_ptr = &adoptTimer; adoptSpec.it_value.tv_sec = ADOPT_EXPIRE_SEC; adoptSpec.it_value.tv_nsec = ADOPT_EXPIRE_NSEC; adoptSpec.it_interval.tv_sec = 0L; adoptSpec.it_interval.tv_nsec = 0L; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = adopt_action; sigemptyset (&sa.sa_mask); // adding extra signals to be blocked sigaddset (&sa.sa_mask, JOIN_SIGNAL); sigaddset (&sa.sa_mask, HELLO_SIGNAL); if (sigaction (ADOPT_SIGNAL, &sa, NULL)) { perror ("sigaction failed"); exit (1); } if (timer_create (CLOCK_REALTIME, &adoptEvent, &adoptTimer)) { perror ("adoptTimer creation"); exit (1); } /* check to see if the other timer exists or not */ if (timer_gettime (joinTimer, &dummy) && timer_gettime (helloTimer, &dummy)) { sigemptyset (&set); } sigaddset (&set, ADOPT_SIGNAL); break; case HELLO_TIMER: helloEvent.sigev_notify = SIGEV_SIGNAL; helloEvent.sigev_signo = HELLO_SIGNAL; helloEvent.sigev_value.sival_ptr = &helloTimer; helloSpec.it_value.tv_sec = HELLO_EXPIRE_SEC; helloSpec.it_value.tv_nsec = HELLO_EXPIRE_NSEC; helloSpec.it_interval.tv_sec = 0L; helloSpec.it_interval.tv_nsec = 0L; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = hello_action; sigemptyset (&sa.sa_mask); // adding extra signals to be blocked sigaddset (&sa.sa_mask, JOIN_SIGNAL); sigaddset (&sa.sa_mask, ADOPT_SIGNAL); if (sigaction (HELLO_SIGNAL, &sa, NULL)) { perror ("sigaction failed"); exit (1); } if (timer_create (CLOCK_REALTIME, &helloEvent, &helloTimer)) { perror ("helloTimer creation"); exit (1); } /* check to see if the other timer exists or not */ if (timer_gettime (adoptTimer, &dummy) && timer_gettime (joinTimer, &dummy)) { sigemptyset (&set); } sigaddset (&set, HELLO_SIGNAL); break; } } void DDCA::setTimer (TIMER which) { switch (which) { case JOIN_TIMER: if (timer_settime (joinTimer, 0, &joinSpec, NULL)) { perror ("settime for joinTimer failed"); exit (1); } break; case ADOPT_TIMER: if (timer_settime (adoptTimer, 0, &adoptSpec, NULL)) { perror ("settime for adoptTimer failed"); exit (1); } break; case HELLO_TIMER: if (timer_settime (helloTimer, 0, &helloSpec, NULL)) { perror ("settime for helloTimer failed"); exit (1); } break; } } void DDCA::cancelTimer (TIMER which) { struct itimerspec dummy; // used to zero out the timer dummy.it_value.tv_sec = 0L; dummy.it_value.tv_nsec = 0L; dummy.it_interval.tv_sec = 0L; dummy.it_interval.tv_nsec = 0L; switch (which) { case JOIN_TIMER: if (timer_settime (joinTimer, 0, &dummy, NULL)) { perror ("cancel for joinTimer failed"); exit (1); } break; case ADOPT_TIMER: if (timer_settime (adoptTimer, 0, &dummy, NULL)) { perror ("cancel for adoptTimer failed"); exit (1); } break; case HELLO_TIMER: if (timer_settime (helloTimer, 0, &dummy, NULL)) { perror ("cancel for helloTimer failed"); exit (1); } break; } } void DDCA::deleteTimer (TIMER which) { switch (which) { case JOIN_TIMER: if (timer_delete (joinTimer)) { perror ("timer_delete of joinTimer failed"); exit (1); } break; case ADOPT_TIMER: if (timer_delete (adoptTimer)) { perror ("timer_delete of adoptTimer failed"); exit (1); } break; case HELLO_TIMER: if (timer_delete (helloTimer)) { perror ("timer_delete of helloTimer failed"); exit (1); } break; } } /* axg--timer main int main (void) { ha.initTimer (JOIN_TIMER); ha.initTimer (ADOPT_TIMER); ha.setTimer (ADOPT_TIMER); ha.setTimer (JOIN_TIMER); while (1) { sleep (SLEEP_TIME); } return 0; } */ void DDCA::enterInactive() { /* Algorithm 1: Inactive State Input:Event Output:Event INACTIVE(Event) switch Event case Node Activation BroadcastMessage(Join Request) SetTimer(JoinTimer) retryFlag = unset joinFlag = unset my_cid = NULL return Inactive break */ cout << "machine entering inactive state..." << endl; broadcastMsg(buildDDCAPacket(JOIN_REQUEST), DDCA_LEN); // initializing event to no event for pleasing select event = NO_EVENT; setTimer(JOIN_TIMER); // broadcastMsg(buildDDCAPacket(ADOPT_REQUEST), sizeof(struct ddca_header) + sizeof(int)); retryFlag = UNSET; joinFlag = UNSET; myCid = 0; //change state to unclustered myState = UNCLUSTERED; nodeStatus = NO_GATEWAY; cout << "entering the unclustered state" << endl; } void temp_rcv() { char buff[4096]; unsigned int packet_len = 0; socklen_t fromlen; int * ptr; int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_DDCA); while(1) { //cout <<"gonna get stuck at before the rcvfrom" << endl; packet_len = recvfrom(sockfd, buff, 4096, 0, 0, &fromlen); cout <<"successfully rcvd a packet of length: " << packet_len << endl; ptr = (int *)(buff + sizeof(struct ip) + sizeof(struct ddca_header)); cout <<"Message type: " << ntohl(*ptr) << endl; } } char * DDCA::recvPacket(char *buff) { unsigned int packet_len = 0; socklen_t fromlen; packet_len = recvfrom(sockfd, buff, 4096, 0, 0, &fromlen); if(packet_len <= 0) { cerr <<"Packet could not be received successfully" << endl; } cout <<"successfully rcvd a packet of length: " << packet_len << endl; cout <<"Message type: " << ntohl(((((struct ddca_body *)(buff + sizeof(struct ip) + sizeof(struct ddca_header)))->msg_type))) << endl; return buff; } int DDCA::ddcaMain() { sigset_t timer_sigs; int pkt_type; fd_set readfds; sigemptyset(&timer_sigs); //we have to add all the signals here sigaddset(&timer_sigs, JOIN_SIGNAL); sigaddset(&timer_sigs, ADOPT_SIGNAL); sigaddset(&timer_sigs, HELLO_SIGNAL); //initialize the stuff for select FD_ZERO(&readfds); FD_SET(sockfd, &readfds); blockTime.tv_sec = 100; //arbitrary value right now, must put in something proper blockTime.tv_usec = 100; //again arbitrary value while(1) //machine does this forever { //signals might attack here //if a timer comes here, we gotta set the event variable in the handler cerr << "BEFORE select" << endl; if (event == NO_EVENT) retval = select(sockfd +1, &readfds, NULL, NULL, &blockTime); //timers can hit here cerr << "AFTER select" << endl; //interruption not allowed here so block all signals //one bug here, if a packet arrived and a signal arrived immediately after that, //the packet will be lost sigprocmask(SIG_SETMASK, &timer_sigs, NULL); //block the timers if( firstSigFlag == 0) { firstSigFlag = 1; } if (sigsetjmp (jmpbuf, 1) < 0) { perror ("sigsetjmp"); exit (0); } cerr << " jumped here" << endl; // doing this for testing, setting this so we can handle the signals //later to be removed by setting the last else case for the signals //04.02.02 commented this line // pkt_type = PKT_DDCA; //gotta decipher the packet here //also notice here that we have exactly one file descriptor in the //select to wait on so there is no checking of how many file //descriptors are ready for action. only while we are waiting to read //something we wait actually. when we gotta send, we just send and dont //wait if(retval > 0) { cerr << " in retval > 0" << endl; char *buff = recvPacket(datagram_rcv); //recv the datagram here //first scan the header and set the packet type struct ddca_header *tmp_header = (struct ddca_header *)(buff + sizeof(struct ip)); //check the conversion between the unsigned char and int here pkt_type = tmp_header->proto; //for now the packet will always be of type ddca // unsigned long *ptr = (unsigned long *)(buff + sizeof(struct ip) + sizeof(struct ddca_header)); // unsigned long temp_event = ntohl(*ptr); /* int *ptr = (int *)(buff + sizeof(struct ip) + sizeof(struct ddca_header)); */ //int *ptr = (int *)(((struct ddca_body *)(buff + sizeof(struct ip) + sizeof(struct ddca_header)))->msg_type); //int temp_event = ntohl(*ptr); //04.04.02 adding the routing functionality in the ddcaMain //ok guys now check if we are the one who broadcast this packet struct ip* iph = (struct ip*)buff; if(iph->ip_src.s_addr == ip_addr) { //cerr <<"Blah. I am receiving my own packets!!!" << endl; goto rcvd_my_own_packet; //cant think of a a better way to break } //July 16 modifications if (tmp_header->dest_nid != ip_addr && tmp_header->dest_nid != 0) { goto not_for_me; } if(pkt_type == PKT_ROUTING) { cout <<"-*-*-*-*|||-*A PKT WAS RCVD THAT WAS PKT_ROUTING" << endl; goto do_pkt_routing; } rcvNid = iph->ip_src.s_addr; //the receivers id // axg -- how can we assume that we always get a ddca_body and not a // RPKT int temp_event = ntohl((((struct ddca_body *)(buff + sizeof(struct ip) + sizeof(struct ddca_header)))->msg_type)); cout << "temp event = " << temp_event << endl; switch(temp_event) { case JOIN_REQUEST: event = RCV_JOIN_REQUEST; break; case ADOPT_REQUEST: event = RCV_ADOPT_REQUEST; break; case JOIN_RESPONSE: event = RCV_JOIN_RESPONSE; break; case ADOPT_RESPONSE: event = RCV_ADOPT_RESPONSE; break; case JOIN_CLUSTER: event = RCV_JOIN_CLUSTER; break; case HELLO_MSG: event = RCV_HELLO_MSG; break; case MAX_CLUSTER: event = RCV_MAX_CLUSTER; break; case GATEWAY: event = RCV_GATEWAY; break; case NOT_GATEWAY: event = RCV_NOT_GATEWAY; break; default: cerr <<"Unknown request in ddca packet" << endl; } //a valid packet must set the appropriate event } else if(retval == 0) { cerr <<"OOPS!! the select was never meant to timeout..." << endl; goto rcvd_my_own_packet; //should not handle any event, just //jump to the end and unblock the signals } else { //cerr <<"Fine must be exiting due to a signal handler..." << endl; //should we ask each signal handler to set a varible which we can //check here, lest we come here in case of a genuine error //which we wont really be able to detect cerr << " in the last else" <cid; struct in_addr ha; // added just to print the address out ha.s_addr = rcvCid; cerr << "rcv Cid = " << inet_ntoa (ha) << endl; switch(myState) { case ORPHAN: orphanState(event); break; case UNCLUSTERED: unclusteredState(event); break; case CHILD: childState(event); break; case PARENT: parentState(event); break; default: cerr<<"****************************FATAL ERROR***************************"<alpha > old_parent.alpha && new_parent->t > old_parent.t)//gauranteed metric for a better parent { //store new parent in place of old parent old_parent = *new_parent; cout <<"new parent is better: alpha " << new_parent->alpha << " t: " << new_parent->t << endl; } else ;//dont need to do anything since new parent is not as good as old one //old_parent = *new_parent; return 0;//just return something } // added the send_hello function for the HELLO MSG packets, int DDCA::send_hello () { broadcastMsg (buildDDCAPacket (HELLO_MSG), DDCA_LEN); return 1; } int DDCA::setGateway () { nodeStatus = IS_GATEWAY; return 1; } int DDCA::unsetGateway () { nodeStatus = NO_GATEWAY; return 1; } /* int DDCA::limitedBcast() { bcast to all if(rcvd bcast from yourself) //must go in the reception, we do it anyways discard it else { if (you already got this update) //should go in the router's handling section just discard it. else update your net_db } // broadcastMsg(router->buildRouterPacket(), ROUTER_LEN); } */ /* int main (int argc, char **argv) { class DDCA machine; if(getuid() != 0 && geteuid() != 0) { cerr <<"You MUST be ROOT to execute this program" << endl; return 0; } machine.initDDCA(); machine.initRAW(); // machine.unicastMsg(machine.datagram_snd, 8, inet_addr("136.142.79.177")); if( argc < 1) { printf("Usage: ddca arg1\n"); return 0; } machine.enterInactive(); machine.ddcaMain (); return 0; } */