public IPEndPoint SyncWithPeer(PeerInfo peer, int timeout, UdpClient udpClient) { long waitTime = timeout * 10000; long startTime = DateTime.Now.Ticks; Logger.Debug("Syncing with peer " + peer + " from " + udpClient.Client.LocalEndPoint + " to establish tunnel " + Id); StandardSyncRqTunnelPacket syncRq = new StandardSyncRqTunnelPacket(); _syncEvent.Reset(); _udpClient = udpClient; InitReceiverThread(); int attempts = 0; do { if (DateTime.Now.Ticks - startTime > waitTime) { Logger.Debug("Tunnel " + Id + ", sync Timeout : " + (DateTime.Now.Ticks - startTime)); throw new TimeoutException("Tunnel " + Id + ", timeout occured while attempting sync with peer " + peer); } byte[] syncBytes = syncRq.getBytes(); if ((_syncTypes.Contains(SyncType.All) || _syncTypes.Contains(SyncType.Internal))) { Logger.Debug("Tunnel " + Id + ", sent requests, waiting for sync response from internal of " + peer); foreach (var endPoint in peer.InternalEndPoints) { udpClient.Send(syncBytes, syncBytes.Length, endPoint); } } if (attempts > internalAttempts && (_syncTypes.Contains(SyncType.All) || _syncTypes.Contains(SyncType.External))) { Logger.Debug("Tunnel " + Id + ", sent requests, waiting for sync response from external of " + peer); udpClient.Send(syncBytes, syncBytes.Length, peer.ExternalEndPoint); } // Faciliatator is our last choice, only send here after 3 attempts at the other ones if (attempts >= externalAttempts && (_syncTypes.Contains(SyncType.All) || _syncTypes.Contains(SyncType.Facilitator))) { Logger.Debug("Tunnel " + Id + ", sent requests, waiting for sync response from facilitator of " + peer); udpClient.Send(syncBytes, syncBytes.Length, peer.FacilitatorRepeatedEndPoint); } attempts++; } while (!_syncEvent.WaitOne(1000)); var activeIp = _lastSyncPacketIp; Logger.Debug("Tunnel " + Id + ", synchronisation with " + activeIp + " established"); return activeIp; }