async Task ConnectToNewNeighborAsync(DateTime timeNowUtc, bool connectAnyway, double[] directionVectorNullable) { var connectedNeighborsForNewRequests = ConnectedNeighborsCanBeUsedForNewRequests.ToList(); if (connectAnyway || connectedNeighborsForNewRequests.Count < _configuration.MinDesiredNumberOfNeighbors) { if (connectAnyway || (CurrentRegistrationOperationsCount == 0) || timeNowUtc > _latestConnectToNewNeighborOperationStartTimeUtc + TimeSpan.FromSeconds(Engine.Configuration.NeighborhoodExtensionMaxRetryIntervalS)) { if (connectAnyway == false) { if (_latestConnectToNewNeighborOperationStartTimeUtc.HasValue && (timeNowUtc - _latestConnectToNewNeighborOperationStartTimeUtc.Value).TotalSeconds < Engine.Configuration.NeighborhoodExtensionMinIntervalS) { return; // avoid too frequent registrations } if (Engine.PowThreadQueueCount != 0) // avoid having concurrent PoW operations, it leads to 200sec+ PoW delays when mobile device has bad internet connection { return; } Engine.WriteToLog_reg_requesterSide_higherLevelDetail($"extending neighborhood: {connectedNeighborsForNewRequests.Count} neighbors now", null, null); } _latestConnectToNewNeighborOperationStartTimeUtc = timeNowUtc; try { // extend neighbors via ep (3% probability) or via existing neighbors --- increase mindistance, from 1 if (this.Configuration.EntryPeerEndpoints != null && (Engine.InsecureRandom.NextDouble() < 0.01 || connectedNeighborsForNewRequests.Count == 0)) { var epEndpoint = this.Configuration.EntryPeerEndpoints[Engine.InsecureRandom.Next(this.Configuration.EntryPeerEndpoints.Length)]; Engine.WriteToLog_reg_requesterSide_higherLevelDetail($"extending neighborhood via EP {epEndpoint} ({connectedNeighborsForNewRequests.Count} connected operable neighbors now)", null, null); await Engine.RegisterAsync(this, epEndpoint, 0, RegisterRequestPacket.MaxNumberOfHopsRemaining, directionVectorNullable); } else { if (connectedNeighborsForNewRequests.Count != 0) { var neighborToSendRegister = connectedNeighborsForNewRequests[Engine.InsecureRandom.Next(connectedNeighborsForNewRequests.Count)]; Engine.WriteToLog_reg_requesterSide_higherLevelDetail($"extending neighborhood via neighbor {neighborToSendRegister} ({connectedNeighborsForNewRequests.Count} connected operable neighbors now)", null, null); await neighborToSendRegister.RegisterAsync(0, ConnectedNeighborsBusySectorIds, RegisterRequestPacket.MaxNumberOfHopsRemaining, (byte)Engine.InsecureRandom.Next(10), directionVectorNullable ); _neighborhoodExtensionFailuresCountInArow = 0; } } } catch (Exception exc) { _neighborhoodExtensionFailuresCountInArow++; if (exc is RequestRejectedException || exc is DrpTimeoutException) { var msg = $"failed to extend neighbors for {this}: {exc.Message}\r\n{_neighborhoodExtensionFailuresCountInArow} failures in a row"; if (_neighborhoodExtensionFailuresCountInArow < 3) { Engine.WriteToLog_reg_requesterSide_higherLevelDetail(msg, null, null); } else if (_neighborhoodExtensionFailuresCountInArow < 5) { Engine.WriteToLog_reg_requesterSide_lightPain(msg, null, null); } else { Engine.WriteToLog_reg_requesterSide_mediumPain(msg, null, null); } } else { Engine.WriteToLog_reg_requesterSide_mediumPain($"failed to extend neighbors for {this}: {exc}\r\n{_neighborhoodExtensionFailuresCountInArow} failures in a row", null, null); } } } } }