/// <summary> /// Match the waiting connection with a registration, callback registration, /// return if connection is accepted in event. /// </summary> /// <returns>true if a match was found.</returns> private bool MatchRegistration(object sender, ConnectionWaitingEventArgs e) { Registration callbackRegistration = null; bool found = false; lock (m_registrationsLock) { // first try to match single registrations foreach (var registration in m_registrations.Where(r => (r.ReverseConnectStrategy & ReverseConnectStrategy.Any) == 0)) { if (registration.EndpointUrl.Scheme.Equals(e.EndpointUrl.Scheme, StringComparison.InvariantCulture) && (registration.ServerUri == e.ServerUri || registration.EndpointUrl.Authority.Equals(e.EndpointUrl.Authority, StringComparison.InvariantCulture))) { callbackRegistration = registration; e.Accepted = true; found = true; Utils.Trace("Accepted reverse connection: {0} {1}", e.ServerUri, e.EndpointUrl); break; } } // now try any registrations. if (callbackRegistration == null) { foreach (var registration in m_registrations.Where(r => (r.ReverseConnectStrategy & ReverseConnectStrategy.Any) != 0)) { if (registration.EndpointUrl.Scheme.Equals(e.EndpointUrl.Scheme, StringComparison.InvariantCulture)) { callbackRegistration = registration; e.Accepted = true; found = true; Utils.Trace("Accept any reverse connection for approval: {0} {1}", e.ServerUri, e.EndpointUrl); break; } } } if (callbackRegistration != null) { if ((callbackRegistration.ReverseConnectStrategy & ReverseConnectStrategy.Once) != 0) { m_registrations.Remove(callbackRegistration); } } } callbackRegistration?.OnConnectionWaiting?.Invoke(sender, e); return(found); }
/// <summary> /// Raised when a reverse connection is waiting, /// finds and calls a waiting connection. /// </summary> private async Task OnConnectionWaiting(object sender, ConnectionWaitingEventArgs e) { DateTime startTime = DateTime.UtcNow; DateTime endTime = startTime + TimeSpan.FromMilliseconds(m_configuration.HoldTime); bool matched = MatchRegistration(sender, e); while (!matched) { Utils.Trace("Holding reverse connection: {0} {1}", e.ServerUri, e.EndpointUrl); CancellationToken ct; lock (m_registrationsLock) { ct = m_cts.Token; } TimeSpan delay = endTime - DateTime.UtcNow; if (delay.TotalMilliseconds > 0) { await Task.Delay(delay, ct).ContinueWith(tsk => { if (tsk.IsCanceled) { matched = MatchRegistration(sender, e); if (matched) { Utils.Trace("Matched reverse connection {0} {1} after {2}ms", e.ServerUri, e.EndpointUrl, (int)(DateTime.UtcNow - startTime).TotalMilliseconds); } } } ).ConfigureAwait(false); } break; } Utils.Trace("{0} reverse connection: {1} {2} after {3}ms", e.Accepted ? "Accepted" : "Rejected", e.ServerUri, e.EndpointUrl, (int)(DateTime.UtcNow - startTime).TotalMilliseconds); }