private void TryNextPeer()
{
var address = _inactives.Take();
while (true)
{
try
{
var peer = new Peer(_params, address, _blockStore.GetChainHead().Height, _chain);
_peerPool.Execute(
() =>
{
try
{
_log.Info("Connecting to " + peer);
peer.Connect();
_peers.Add(peer);
HandleNewPeer(peer);
peer.Run();
}
catch (PeerException ex)
{
// Do not propagate PeerException - log and try next peer. Suppress stack traces for
// exceptions we expect as part of normal network behaviour.
var cause = ex.InnerException;
if (cause is SocketException)
{
if (((SocketException) cause).SocketErrorCode == SocketError.TimedOut)
_log.Info("Timeout talking to " + peer + ": " + cause.Message);
else
_log.Info("Could not connect to " + peer + ": " + cause.Message);
}
else if (cause is IOException)
{
_log.Info("Error talking to " + peer + ": " + cause.Message);
}
else
{
_log.Error("Unexpected exception whilst talking to " + peer, ex);
}
}
finally
{
// In all cases, disconnect and put the address back on the queue.
// We will retry this peer after all other peers have been tried.
peer.Disconnect();
_inactives.Add(address);
if (_peers.Remove(peer))
HandlePeerDeath(peer);
}
});
break;
}
catch (RejectedExecutionException)
{
// Reached maxConnections, try again after a delay
// TODO - consider being smarter about retry. No need to retry
// if we reached maxConnections or if peer queue is empty. Also consider
// exponential backoff on peers and adjusting the sleep time according to the
// lowest backoff value in queue.
}
catch (BlockStoreException e)
{
// Fatal error
_log.Error("Block store corrupt?", e);
_running = false;
throw new Exception(e.Message, e);
}
// If we got here, we should retry this address because an error unrelated
// to the peer has occurred.
Thread.Sleep(_connectionDelayMillis);
}
}