bool NodeStore::update(NodeRef &node, NodeRefList *nl) { Mutex::AutoLocker l(mutex); bool found = false; if (!node) return false; // There may be undefined nodes in the node store that should // be removed/merged with a 'defined' node that we create from a // node description. We loop through all nodes in the store and // compare their interface lists with the one in the 'defined' node. // If any interfaces match, we remove the matching nodes in the store // and eventually replace them with the new one. for (NodeStore::iterator it = begin(); it != end();) { NodeRecord *nr = *it; bool found_now = false; nr->node.lock(); const InterfaceRefList *ifaces = nr->node->getInterfaces(); for (InterfaceRefList::const_iterator it2 = ifaces->begin(); it2 != ifaces->end(); it2++) { InterfaceRef iface = *it2; if (node->hasInterface(iface)) { // Transfer all the "up" interface states to the updated node if (iface->isUp()) node->setInterfaceUp(iface); found_now = true; } } nr->node.unlock(); if (found_now) { if (nl) nl->push_back(nr->node); nr->node->setStored(false); node->setExchangedNodeDescription(nr->node->hasExchangedNodeDescription()); it = erase(it); delete nr; found = true; } else { it++; } } if (found) { node->setStored(true); push_back(new NodeRecord(node)); } return found; }
void ProtocolManager::onSendDataObjectActual(Event *e) { int numTx = 0; if (!e || !e->hasData()) return; // Get a copy to work with DataObjectRef dObj = e->getDataObject(); // Get target list: NodeRefList *targets = (e->getNodeList()).copy(); if (!targets) { HAGGLE_ERR("no targets in data object when sending\n"); return; } unsigned int numTargets = targets->size(); // Go through all targets: while (!targets->empty()) { // A current target reference NodeRef targ = targets->pop(); if (!targ) { HAGGLE_ERR("Target num %u is NULL!\n", numTargets); numTargets--; continue; } HAGGLE_DBG("Sending to target %u - %s \n", numTargets, targ->getName().c_str()); // If we are going to loop through the node's interfaces, we need to lock the node. targ.lock(); const InterfaceRefList *interfaces = targ->getInterfaces(); // Are there any interfaces here? if (interfaces == NULL || interfaces->size() == 0) { // No interfaces for target, so we generate a // send failure event and skip the target HAGGLE_DBG("Target %s has no interfaces\n", targ->getName().c_str()); targ.unlock(); kernel->addEvent(new Event(EVENT_TYPE_DATAOBJECT_SEND_FAILURE, dObj, targ)); numTargets--; continue; } /* Find the target interface that suits us best (we assume that for any remote target interface we have a corresponding local interface). */ InterfaceRef peerIface = NULL; bool done = false; InterfaceRefList::const_iterator it = interfaces->begin(); //HAGGLE_DBG("Target node %s has %lu interfaces\n", targ->getName().c_str(), interfaces->size()); for (; it != interfaces->end() && done == false; it++) { InterfaceRef iface = *it; // If this interface is up: if (iface->isUp()) { if (iface->getAddresses()->empty()) { HAGGLE_DBG("Interface %s:%s has no addresses - IGNORING.\n", iface->getTypeStr(), iface->getIdentifierStr()); continue; } switch (iface->getType()) { #if defined(ENABLE_BLUETOOTH) case Interface::TYPE_BLUETOOTH: /* Select Bluetooth only if there are no Ethernet or WiFi interfaces. */ if (!iface->getAddress<BluetoothAddress>()) { HAGGLE_DBG("Interface %s:%s has no Bluetooth address - IGNORING.\n", iface->getTypeStr(), iface->getIdentifierStr()); break; } if (!peerIface) peerIface = iface; else if (peerIface->getType() != Interface::TYPE_ETHERNET && peerIface->getType() != Interface::TYPE_WIFI) peerIface = iface; break; #endif #if defined(ENABLE_ETHERNET) case Interface::TYPE_ETHERNET: /* Let Ethernet take priority over the other types. */ if (!iface->getAddress<IPv4Address>() #if defined(ENABLE_IPv6) && !iface->getAddress<IPv6Address>() #endif ) { HAGGLE_DBG("Interface %s:%s has no IPv4 or IPv6 addresses - IGNORING.\n", iface->getTypeStr(), iface->getIdentifierStr()); break; } if (!peerIface) peerIface = iface; else if (peerIface->getType() == Interface::TYPE_BLUETOOTH || peerIface->getType() == Interface::TYPE_WIFI) peerIface = iface; break; case Interface::TYPE_WIFI: if (!iface->getAddress<IPv4Address>() #if defined(ENABLE_IPv6) && !iface->getAddress<IPv6Address>() #endif ) { HAGGLE_DBG("Interface %s:%s has no IPv4 or IPv6 addresses - IGNORING.\n", iface->getTypeStr(), iface->getIdentifierStr()); break; } if (!peerIface) peerIface = iface; else if (peerIface->getType() == Interface::TYPE_BLUETOOTH && peerIface->getType() != Interface::TYPE_ETHERNET) peerIface = iface; break; #endif // ENABLE_ETHERNET case Interface::TYPE_APPLICATION_PORT: case Interface::TYPE_APPLICATION_LOCAL: if (!iface->getAddress<IPv4Address>() #if defined(ENABLE_IPv6) && !iface->getAddress<IPv6Address>() #endif ) { HAGGLE_DBG("Interface %s:%s has no IPv4 or IPv6 addresses - IGNORING.\n", iface->getTypeStr(), iface->getIdentifierStr()); break; } // Not much choise here. if (targ->getType() == Node::TYPE_APPLICATION) { peerIface = iface; done = true; } else { HAGGLE_DBG("ERROR: Node %s is not application, but its interface is\n", targ->getName().c_str()); } break; #if defined(ENABLE_MEDIA) case Interface::TYPE_MEDIA: break; #endif case Interface::TYPE_UNDEFINED: default: break; } } else { //HAGGLE_DBG("Send interface %s was down, ignoring...\n", iface->getIdentifierStr()); } } // We are done looking for a suitable send interface // among the node's interface list, so now we unlock // the node. targ.unlock(); if (!peerIface) { HAGGLE_DBG("No send interface found for target %s. Aborting send of data object!!!\n", targ->getName().c_str()); // Failed to send to this target, send failure event: kernel->addEvent(new Event(EVENT_TYPE_DATAOBJECT_SEND_FAILURE, dObj, targ)); numTargets--; continue; } // Ok, we now have a target and a suitable interface, // now we must figure out a protocol to use when we // transmit to that interface Protocol *p = NULL; // We make a copy of the addresses list here so that we do not // have to lock the peer interface while we call getSenderProtocol(). // getSenderProtocol() might do a lookup in the interface store in order // to find the local interface which is parent of the peer interface. // This might cause a deadlock in case another thread also does a lookup // in the interface store while we hold the interface lock. const Addresses *adds = peerIface->getAddresses()->copy(); // Figure out a suitable protocol given the addresses associated // with the selected interface for (Addresses::const_iterator it = adds->begin(); p == NULL && it != adds->end(); it++) { switch ((*it)->getType()) { #if defined(ENABLE_BLUETOOTH) case Address::TYPE_BLUETOOTH: p = getSenderProtocol(Protocol::TYPE_RFCOMM, peerIface); break; #endif case Address::TYPE_IPV4: #if defined(ENABLE_IPv6) case Address::TYPE_IPV6: #endif if (peerIface->isApplication()) { #ifdef USE_UNIX_APPLICATION_SOCKET p = getSenderProtocol(Protocol::TYPE_LOCAL, peerIface); #else p = getSenderProtocol(Protocol::TYPE_UDP, peerIface); #endif } else p = getSenderProtocol(Protocol::TYPE_TCP, peerIface); break; #if defined(ENABLE_MEDIA) case Address::TYPE_FILEPATH: p = getSenderProtocol(Protocol::TYPE_MEDIA, peerIface); break; #endif default: break; } } delete adds; // Send data object to the found protocol: if (p) { if (p->sendDataObject(dObj, targ, peerIface)) { numTx++; } else { // Failed to send to this target, send failure event: kernel->addEvent(new Event(EVENT_TYPE_DATAOBJECT_SEND_FAILURE, dObj, targ)); } } else { HAGGLE_DBG("No suitable protocol found for interface %s:%s!\n", peerIface->getTypeStr(), peerIface->getIdentifierStr()); // Failed to send to this target, send failure event: kernel->addEvent(new Event(EVENT_TYPE_DATAOBJECT_SEND_FAILURE, dObj, targ)); } numTargets--; } HAGGLE_DBG("Scheduled %d data objects for sending\n", numTx); delete targets; }