#include #include #include #include #include #include #include #include #include #include #include "MKCommModel.h" #include "MKControl.h" #include "MKNode.h" using namespace std; MKCommModel::MKCommModelInit MKCommModel::init; ostream *MKCommModel::logh; /** Agnostic to the mesh network type. * @return new CommModel */ CommModel *CommModel::init() { return dynamic_cast(new MKCommModel); } void MKCommModel::staticInit() { logh = new ofstream(MK_LOG_FILE, ios_base::app); // require root if(geteuid() != 0) { cerr << "meshkit must be run with root privileges!" << endl; MKCommModel::log() << "meshkit must be run with root privileges!" << endl; exit(EXIT_FAILURE); } } MKCommModel::MKCommModel() : count(0), ocu(NULL), target(NULL) { sem_init(&sem1, 0, 1); nodes = new map(); ipTable = new map(); heartBeatThread = HeartBeatListener::start(this); control = MKControl::start(this); } MKCommModel::~MKCommModel() { map::iterator nodesItr; pthread_cancel(heartBeatThread); pthread_join(heartBeatThread, NULL); delete control; for(nodesItr = nodes->begin(); nodesItr != nodes->end(); nodesItr++) { // delete the MKNode * delete nodesItr->second; } delete nodes; delete ipTable; MKRequest::reset(); } node* MKCommModel::get_node(ip4_t tar_ip_addr){ MKNode *curr; node *node = NULL; MKCommModel::log() << "CommModel: calling get_node(ip)" << endl; sem_wait(&sem1); if(curr = findByIP(tar_ip_addr)) { node = curr->asCommNode(); } sem_post(&sem1); return node; } node* MKCommModel::get_node(mac_t tar_mac_addr){ MKNode *curr; node *node = NULL; //MKCommModel::log() << "CommModel: calling get_node(mac)" << endl; sem_wait(&sem1); if(curr = find(tar_mac_addr)) { node = curr->asCommNode(); } sem_post(&sem1); return node; } throughput_t MKCommModel::get_throughput(node* from, node* to) { MKNode *mFrom, *mTo; MKNode::MKRoute *rt; throughput_t tp = 0; //log() << "Calling get_throughput() " << endl; sem_wait(&sem1); mFrom = this->find(from); mTo = this->find(to); if(mFrom != NULL && mTo != NULL) { rt = mFrom->route(to->mac_addr); if(rt != NULL) { tp = rt->throughput() / 1024; // convert to kb } sem_post(&sem1); // anticipate asking for it again //MKRequest::throughput(mFrom, mTo)->send(); } else { sem_post(&sem1); } return tp; } latency_t MKCommModel::get_latency(node *from, node *to) { MKNode *mFrom, *mTo; MKNode::MKRoute *rt; latency_t lat = 0; log() << "Calling get_latency() " << endl; sem_wait(&sem1); mFrom = this->find(from); mTo = this->find(to); if(mFrom != NULL && mTo != NULL) { log() << "from " << static_cast(*mFrom) << " to " << static_cast(*mTo) << endl; rt = mFrom->route(to->mac_addr); if(rt != NULL) { lat = rt->latency; } sem_post(&sem1); // anticipate asking for it again MKRequest::latency(mFrom, mTo)->send(); } else { log() << "-> NODES NOT FOUND" << endl; sem_post(&sem1); } return lat; } signal_strength_t MKCommModel::get_signal_strength(node *from, node *to) { MKNode *mFrom; MKNode::MKNeighbor *nb; signal_strength_t str = 0; sem_wait(&sem1); mFrom = find(from); nb = mFrom->nbr(to->mac_addr); if(nb != NULL) { str = nb->signal; } sem_post(&sem1); return str; } /* weight is deprecated */ weight_t MKCommModel::get_weight(node* from, node* to) { int wgt = 0; return wgt; } inactive_t MKCommModel::get_inactive_time(node *n1, node *n2) { MKNode *mFrom; MKNode::MKNeighbor *nb; inactive_t act_t = 0; sem_wait(&sem1); mFrom = find(n1); nb = mFrom->nbr(n2->mac_addr); if(nb != NULL) { act_t = nb->inactive; } sem_post(&sem1); return act_t; } vector MKCommModel::get_all_nodes() { map::const_iterator nodesItr; vector nodeList; //MKCommModel::log() << "CommModel: calling get_all_nodes()" << endl; sem_wait(&sem1); for(nodesItr = nodes->begin(); nodesItr != nodes->end(); nodesItr++) { nodeList.push_back(nodesItr->second->asCommNode()); } sem_post(&sem1); return nodeList; } vector MKCommModel::get_neighbors(node *target) { const MKNode *mkNode; vector neighbors; vector::const_iterator it; vector nodeList; //MKCommModel::log() << "CommModel: calling get_neighbors()" << endl; //MKCommModel::log() << "get_neighbors from: [" << MKLib::mac2string(target->mac_addr) << " @ " << MKLib::ip2string(htonl(target->ip_addr)) << "]" << endl; sem_wait(&sem1); mkNode = this->find(target->mac_addr); if(mkNode != NULL) { neighbors = mkNode->getNeighbors(); //MKCommModel::log() << "Neighbors Are: " << endl; for(it = neighbors.begin(); it != neighbors.end(); it++) { nodeList.push_back((*it)->asCommNode()); //MKCommModel::log() << MKLib::mac2string((*it)->asCommNode()->mac_addr) << endl; } } sem_post(&sem1); return nodeList; } bool MKCommModel::set_target(node* node) { target = node; return true; } bool MKCommModel::set_ocu_machine(node* node) { ocu = node; return true; } vector MKCommModel::get_preferred_path() { vector path; MKNode *src, *dest; MKNode::MKRoute *rt; vector hops; vector::iterator pItr; //MKCommModel::log() << "Calling get_preferred_path()" << endl; sem_wait(&sem1); if(ocu != NULL && target != NULL && (src = this->find(ocu->mac_addr)) != NULL && (dest = this->find(target->mac_addr)) != NULL) { if(rt = src->route(target->mac_addr)) { hops = rt->getHops(); for(pItr = hops.begin(); pItr != hops.end(); pItr++) { path.push_back((*pItr)->asCommNode()); } } sem_post(&sem1); MKRequest::route(src, dest)->send(); } else { sem_post(&sem1); } return path; } int MKCommModel::size() { return nodes->size(); } void MKCommModel::update(HeartBeatPacket *pkt) { NeighborInfo *ndata; MKNode *src, *neighbor; mac_t mac = MacAddr(pkt->mac).addr; ip4_t ip; sem_wait(&sem1); src = this->find(mac); ip = ntohl(pkt->ip_addr); log() << "Heartbeat received from " << MKLib::ip2string(ip) << endl; if(src == NULL) { // add new MKNode to the node list src = new MKNode(mac, ip); (*nodes)[mac] = src; (*ipTable)[ip] = mac; MKCommModel::log() << "New node discovered: " << static_cast(*src) << endl; } else { if(ip != src->getIP4()) { MKCommModel::log() << "Node IP address updated from " << MKLib::ip2string(src->getIP4()) << " to " << MKLib::ip2string(ip) << endl; ipTable->erase(src->getIP4()); (*ipTable)[ip] = mac; src->setIP(ip); } } src->clearNeighbors(); // neighboring nodes for(int i = 0; i < pkt->num_stations; i++) { ndata = ((NeighborInfo *) &pkt->mp) + i; // zomg pointer arithmetic mac = MacAddr(ndata->mac).addr; neighbor = this->find(mac); if(neighbor == NULL) { // if neighbor not known, add to map of all nodes ip = ntohl(ndata->ip_addr); neighbor = new MKNode(mac, ip); (*nodes)[mac] = neighbor; (*ipTable)[ip] = mac; MKCommModel::log() << "New node discovered (neighbor): " << static_cast(*neighbor) << endl; } src->addNeighbor(neighbor, ndata); } sem_post(&sem1); } void MKCommModel::update(mongo::BSONObj *data, MKRequest *req) { NeighborInfo *ndata; MKNode *src, *hop; MKNode::MKRoute *rt; mac_t mac; ip4_t ip; mongo::BSONObj result, oHops; mongo::BSONElement elem, hops, eHop; vector vHops; // int macSize = MAC_ADDR_BYTES; // retarded bson code needs a reference so we cant pass inline log() << "BSON update from " << static_cast(*req->from) << ": " << data->toString() << endl; sem_wait(&sem1); src = req->from; switch(req->type()) { case MKRequest::kLatency: rt = src->route(req->to->getMAC()); if(rt == NULL) { rt = src->addRoute(req->to); } result = data->getObjectField("data"); elem = result.getField("latency"); rt->latency = elem.Int(); break; case MKRequest::kTraceRoute: rt = src->route(req->to->getMAC()); if(rt == NULL) { rt = src->addRoute(req->to); } result = data->getObjectField("data"); oHops = result.getObjectField("hops"); //hops = result.getField("hops"); rt->clearHops(); { mongo::BSONObjIterator hItr = oHops.begin(); // bson array comes out backwards... vector items; vector::reverse_iterator reverse; while(hItr.more()) { items.push_back(hItr.next()); } // ignore first entry (pop the last one) if(items.size() > 0) { items.pop_back(); rt->addNextHop(req->from); log() << "Traceroute source: '" << MKLib::ip2string(req->from->getIP4()) << "'" << endl; } reverse = items.rbegin(); while(reverse != items.rend()) { char ipStr[20] = {'\0'}; const char *data; int strIdx = 0; eHop = *reverse; data = eHop.value(); for(int i = 0; i < eHop.valuesize() && i < 20; i++) { if(!iscntrl(*(data + i))) { ipStr[strIdx++] = *(data + i); } } ipStr[strIdx] = '\0'; if(*ipStr != '*') { log() << "Traceroute hop: '" << ipStr << "'" << endl; ip = MKLib::parseIP4Addr(ipStr); hop = findByIP(ip); if(hop != NULL) { rt->addNextHop(hop); } else { log() << "Warning: node not found at " << ipStr << ", dumping ip table" << endl; { map::const_iterator ipItr = ipTable->begin(); while(ipItr != ipTable->end()) { log() << "IP: " << MKLib::ip2string(ipItr->first) << " MAC: " << MKLib::mac2string(ipItr->second) << endl; ipItr++; } } } } reverse++; } } break; default: log() << "Unknown bson response type" << endl; break; } sem_post(&sem1); } MKNode *MKCommModel::find(node *node) { return find(node->mac_addr); } MKNode *MKCommModel::find(mac_t addr) { map::const_iterator itr = nodes->find(addr); if(itr == nodes->end()) { return NULL; } return itr->second; } MKNode *MKCommModel::findByIP(ip4_t addr) { MKNode *node = NULL; map::const_iterator ipItr = ipTable->find(addr); map::const_iterator nItr; if(ipItr != ipTable->end()) { nItr = nodes->find(MacAddr(ipItr->second)); if(nItr != nodes->end()) { node = nItr->second; } } return node; }