Fix deadlock-causing regression in Network.

This commit is contained in:
Adam Ierymenko 2016-09-30 12:22:54 -07:00
parent 1eeebba2f7
commit 9eaa3756f8

View File

@ -886,11 +886,13 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr)
const unsigned int chunkLen = chunk.at<uint16_t>(ptr); ptr += 2; const unsigned int chunkLen = chunk.at<uint16_t>(ptr); ptr += 2;
const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen; const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen;
NetworkConfig *nc = (NetworkConfig *)0;
uint64_t configUpdateId;
{
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
_IncomingConfigChunk *c = (_IncomingConfigChunk *)0; _IncomingConfigChunk *c = (_IncomingConfigChunk *)0;
uint64_t chunkId = 0; uint64_t chunkId = 0;
uint64_t configUpdateId;
unsigned long totalLength,chunkIndex; unsigned long totalLength,chunkIndex;
if (ptr < chunk.size()) { if (ptr < chunk.size()) {
const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0); const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0);
@ -989,15 +991,25 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr)
if (c->haveBytes == totalLength) { if (c->haveBytes == totalLength) {
c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated
NetworkConfig *const nc = new NetworkConfig(); nc = new NetworkConfig();
try { try {
if (nc->fromDictionary(c->data)) { if (!nc->fromDictionary(c->data)) {
delete nc;
nc = (NetworkConfig *)0;
}
} catch ( ... ) {
delete nc;
nc = (NetworkConfig *)0;
}
}
}
if (nc) {
this->_setConfiguration(*nc,true); this->_setConfiguration(*nc,true);
delete nc; delete nc;
return configUpdateId; return configUpdateId;
} } else {
} catch ( ... ) {} return 0;
delete nc;
} }
return 0; return 0;
@ -1027,10 +1039,9 @@ void Network::requestConfiguration()
NetworkConfig *nconf = new NetworkConfig(); NetworkConfig *nconf = new NetworkConfig();
try { try {
switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,rmd,*nconf)) { switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,rmd,*nconf)) {
case NetworkController::NETCONF_QUERY_OK: { case NetworkController::NETCONF_QUERY_OK:
Mutex::Lock _l(_lock);
this->_setConfiguration(*nconf,true); this->_setConfiguration(*nconf,true);
} break; break;
case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND:
this->setNotFound(); this->setNotFound();
break; break;
@ -1238,7 +1249,7 @@ ZT_VirtualNetworkStatus Network::_status() const
int Network::_setConfiguration(const NetworkConfig &nconf,bool saveToDisk) int Network::_setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
{ {
// assumes _lock is locked // _lock is NOT locked when this is called
try { try {
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id)) if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
return 0; return 0;
@ -1246,20 +1257,27 @@ int Network::_setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
return 1; // OK config, but duplicate of what we already have return 1; // OK config, but duplicate of what we already have
ZT_VirtualNetworkConfig ctmp; ZT_VirtualNetworkConfig ctmp;
bool oldPortInitialized;
{
Mutex::Lock _l(_lock);
_config = nconf; _config = nconf;
_lastConfigUpdate = RR->node->now(); _lastConfigUpdate = RR->node->now();
_netconfFailure = NETCONF_FAILURE_NONE; _netconfFailure = NETCONF_FAILURE_NONE;
_externalConfig(&ctmp); oldPortInitialized = _portInitialized;
const bool oldPortInitialized = _portInitialized;
_portInitialized = true; _portInitialized = true;
_externalConfig(&ctmp);
}
_portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
if (saveToDisk) { if (saveToDisk) {
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *d = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
try {
char n[64]; char n[64];
Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id);
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> d; if (nconf.toDictionary(*d,false))
if (nconf.toDictionary(d,false)) RR->node->dataStorePut(n,(const void *)d->data(),d->sizeBytes(),true);
RR->node->dataStorePut(n,(const void *)d.data(),d.sizeBytes(),true); } catch ( ... ) {}
delete d;
} }
return 2; // OK and configuration has changed return 2; // OK and configuration has changed