You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,412 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
namespace System.ServiceModel.Channels
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.ServiceModel.Diagnostics.Application;
|
||||
|
||||
abstract class TransportManager
|
||||
{
|
||||
ServiceModelActivity activity;
|
||||
int openCount;
|
||||
object thisLock = new object();
|
||||
|
||||
protected ServiceModelActivity Activity
|
||||
{
|
||||
get { return this.activity; }
|
||||
}
|
||||
|
||||
internal abstract string Scheme { get; }
|
||||
|
||||
internal object ThisLock
|
||||
{
|
||||
get { return this.thisLock; }
|
||||
}
|
||||
|
||||
internal void Close(TransportChannelListener channelListener, TimeSpan timeout)
|
||||
{
|
||||
this.Cleanup(channelListener, timeout, false);
|
||||
}
|
||||
|
||||
void Cleanup(TransportChannelListener channelListener, TimeSpan timeout, bool aborting)
|
||||
{
|
||||
using (ServiceModelActivity.BoundOperation(this.Activity))
|
||||
{
|
||||
this.Unregister(channelListener);
|
||||
}
|
||||
lock (ThisLock)
|
||||
{
|
||||
if (openCount <= 0)
|
||||
{
|
||||
throw Fx.AssertAndThrow("Invalid Open/Close state machine.");
|
||||
}
|
||||
|
||||
openCount--;
|
||||
|
||||
if (openCount == 0)
|
||||
{
|
||||
// Wrap the final close here with transfers.
|
||||
using (ServiceModelActivity.BoundOperation(this.Activity, true))
|
||||
{
|
||||
if (aborting)
|
||||
{
|
||||
OnAbort();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnClose(timeout);
|
||||
}
|
||||
}
|
||||
if (this.Activity != null)
|
||||
{
|
||||
this.Activity.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void EnsureRegistered<TChannelListener>(UriPrefixTable<TChannelListener> addressTable,
|
||||
TChannelListener channelListener, HostNameComparisonMode registeredComparisonMode)
|
||||
where TChannelListener : TransportChannelListener
|
||||
{
|
||||
TChannelListener existingFactory;
|
||||
if (!addressTable.TryLookupUri(channelListener.Uri, registeredComparisonMode, out existingFactory) ||
|
||||
(existingFactory != channelListener))
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
|
||||
SR.ListenerFactoryNotRegistered, channelListener.Uri)));
|
||||
}
|
||||
}
|
||||
|
||||
// Must be called under lock(ThisLock).
|
||||
protected void Fault<TChannelListener>(UriPrefixTable<TChannelListener> addressTable, Exception exception)
|
||||
where TChannelListener : ChannelListenerBase
|
||||
{
|
||||
foreach (KeyValuePair<BaseUriWithWildcard, TChannelListener> pair in addressTable.GetAll())
|
||||
{
|
||||
TChannelListener listener = pair.Value;
|
||||
listener.Fault(exception);
|
||||
listener.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract void OnClose(TimeSpan timeout);
|
||||
internal abstract void OnOpen();
|
||||
internal virtual void OnAbort() { }
|
||||
|
||||
internal void Open(TransportChannelListener channelListener)
|
||||
{
|
||||
if (DiagnosticUtility.ShouldUseActivity)
|
||||
{
|
||||
if (this.activity == null)
|
||||
{
|
||||
this.activity = ServiceModelActivity.CreateActivity(true);
|
||||
if (DiagnosticUtility.ShouldUseActivity)
|
||||
{
|
||||
if (null != FxTrace.Trace)
|
||||
{
|
||||
FxTrace.Trace.TraceTransfer(this.Activity.Id);
|
||||
}
|
||||
ServiceModelActivity.Start(this.Activity, SR.GetString(SR.ActivityListenAt, channelListener.Uri.ToString()), ActivityType.ListenAt);
|
||||
}
|
||||
}
|
||||
channelListener.Activity = this.Activity;
|
||||
}
|
||||
using (ServiceModelActivity.BoundOperation(this.Activity))
|
||||
{
|
||||
if (DiagnosticUtility.ShouldTraceInformation)
|
||||
{
|
||||
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TransportListen,
|
||||
SR.GetString(SR.TraceCodeTransportListen, channelListener.Uri.ToString()), this);
|
||||
}
|
||||
this.Register(channelListener);
|
||||
try
|
||||
{
|
||||
lock (ThisLock)
|
||||
{
|
||||
if (openCount == 0)
|
||||
{
|
||||
OnOpen();
|
||||
}
|
||||
|
||||
openCount++;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.Unregister(channelListener);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void Abort(TransportChannelListener channelListener)
|
||||
{
|
||||
this.Cleanup(channelListener, TimeSpan.Zero, true);
|
||||
}
|
||||
|
||||
internal abstract void Register(TransportChannelListener channelListener);
|
||||
|
||||
// should only call this under ThisLock (unless accessing purely for inspection)
|
||||
protected void ThrowIfOpen()
|
||||
{
|
||||
if (openCount > 0)
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
||||
new InvalidOperationException(SR.GetString(SR.TransportManagerOpen)));
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract void Unregister(TransportChannelListener channelListener);
|
||||
}
|
||||
|
||||
|
||||
delegate IList<TransportManager> SelectTransportManagersCallback();
|
||||
class TransportManagerContainer
|
||||
{
|
||||
IList<TransportManager> transportManagers;
|
||||
TransportChannelListener listener;
|
||||
bool closed;
|
||||
object tableLock;
|
||||
|
||||
public TransportManagerContainer(TransportChannelListener listener)
|
||||
{
|
||||
this.listener = listener;
|
||||
this.tableLock = listener.TransportManagerTable;
|
||||
this.transportManagers = new List<TransportManager>();
|
||||
}
|
||||
|
||||
TransportManagerContainer(TransportManagerContainer source)
|
||||
{
|
||||
this.listener = source.listener;
|
||||
this.tableLock = source.tableLock;
|
||||
this.transportManagers = new List<TransportManager>();
|
||||
for (int i = 0; i < source.transportManagers.Count; i++)
|
||||
{
|
||||
this.transportManagers.Add(source.transportManagers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// copy contents into a new container (used for listener/channel lifetime decoupling)
|
||||
public static TransportManagerContainer TransferTransportManagers(TransportManagerContainer source)
|
||||
{
|
||||
TransportManagerContainer result = null;
|
||||
|
||||
lock (source.tableLock)
|
||||
{
|
||||
if (source.transportManagers.Count > 0)
|
||||
{
|
||||
result = new TransportManagerContainer(source);
|
||||
source.transportManagers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
Close(true, TimeSpan.Zero);
|
||||
}
|
||||
|
||||
public IAsyncResult BeginOpen(SelectTransportManagersCallback selectTransportManagerCallback,
|
||||
AsyncCallback callback, object state)
|
||||
{
|
||||
return new OpenAsyncResult(selectTransportManagerCallback, this, callback, state);
|
||||
}
|
||||
|
||||
public void EndOpen(IAsyncResult result)
|
||||
{
|
||||
OpenAsyncResult.End(result);
|
||||
}
|
||||
|
||||
public void Open(SelectTransportManagersCallback selectTransportManagerCallback)
|
||||
{
|
||||
lock (this.tableLock)
|
||||
{
|
||||
if (closed) // if we've been aborted then don't get transport managers
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IList<TransportManager> foundTransportManagers = selectTransportManagerCallback();
|
||||
if (foundTransportManagers == null) // nothing to do
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < foundTransportManagers.Count; i++)
|
||||
{
|
||||
TransportManager transportManager = foundTransportManagers[i];
|
||||
transportManager.Open(this.listener);
|
||||
this.transportManagers.Add(transportManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
|
||||
{
|
||||
return new CloseAsyncResult(this, callback, timeout, state);
|
||||
}
|
||||
|
||||
public void EndClose(IAsyncResult result)
|
||||
{
|
||||
CloseAsyncResult.End(result);
|
||||
}
|
||||
|
||||
public void Close(TimeSpan timeout)
|
||||
{
|
||||
Close(false, timeout);
|
||||
}
|
||||
|
||||
public void Close(bool aborting, TimeSpan timeout)
|
||||
{
|
||||
if (this.closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IList<TransportManager> transportManagersCopy;
|
||||
lock (this.tableLock)
|
||||
{
|
||||
if (this.closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.closed = true;
|
||||
|
||||
transportManagersCopy = new List<TransportManager>(this.transportManagers);
|
||||
this.transportManagers.Clear();
|
||||
|
||||
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
||||
TimeoutException timeoutException = null;
|
||||
foreach (TransportManager transportManager in transportManagersCopy)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!aborting && timeoutException == null)
|
||||
{
|
||||
transportManager.Close(listener, timeoutHelper.RemainingTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
transportManager.Abort(listener);
|
||||
}
|
||||
}
|
||||
catch (TimeoutException ex)
|
||||
{
|
||||
timeoutException = ex;
|
||||
transportManager.Abort(listener);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeoutException != null)
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.TimeoutOnClose, timeout), timeoutException));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class OpenOrCloseAsyncResult : TraceAsyncResult
|
||||
{
|
||||
TransportManagerContainer parent;
|
||||
static Action<object> scheduledCallback = new Action<object>(OnScheduled);
|
||||
|
||||
protected OpenOrCloseAsyncResult(TransportManagerContainer parent, AsyncCallback callback,
|
||||
object state)
|
||||
: base(callback, state)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
protected void Begin()
|
||||
{
|
||||
ActionItem.Schedule(scheduledCallback, this);
|
||||
}
|
||||
|
||||
static void OnScheduled(object state)
|
||||
{
|
||||
((OpenOrCloseAsyncResult)state).OnScheduled();
|
||||
}
|
||||
|
||||
void OnScheduled()
|
||||
{
|
||||
using (ServiceModelActivity.BoundOperation(this.CallbackActivity))
|
||||
{
|
||||
Exception completionException = null;
|
||||
try
|
||||
{
|
||||
this.OnScheduled(this.parent);
|
||||
}
|
||||
#pragma warning suppress 56500 // [....], transferring exception to another thread
|
||||
catch (Exception e)
|
||||
{
|
||||
if (Fx.IsFatal(e))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
completionException = e;
|
||||
}
|
||||
|
||||
this.Complete(false, completionException);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void OnScheduled(TransportManagerContainer parent);
|
||||
}
|
||||
|
||||
sealed class CloseAsyncResult : OpenOrCloseAsyncResult
|
||||
{
|
||||
TimeoutHelper timeoutHelper;
|
||||
|
||||
public CloseAsyncResult(TransportManagerContainer parent, AsyncCallback callback, TimeSpan timeout,
|
||||
object state)
|
||||
: base(parent, callback, state)
|
||||
{
|
||||
this.timeoutHelper = new TimeoutHelper(timeout);
|
||||
this.timeoutHelper.RemainingTime(); //start count down
|
||||
this.Begin();
|
||||
}
|
||||
|
||||
public static void End(IAsyncResult result)
|
||||
{
|
||||
AsyncResult.End<CloseAsyncResult>(result);
|
||||
}
|
||||
|
||||
protected override void OnScheduled(TransportManagerContainer parent)
|
||||
{
|
||||
parent.Close(timeoutHelper.RemainingTime());
|
||||
}
|
||||
}
|
||||
|
||||
sealed class OpenAsyncResult : OpenOrCloseAsyncResult
|
||||
{
|
||||
SelectTransportManagersCallback selectTransportManagerCallback;
|
||||
|
||||
public OpenAsyncResult(SelectTransportManagersCallback selectTransportManagerCallback, TransportManagerContainer parent,
|
||||
AsyncCallback callback, object state)
|
||||
: base(parent, callback, state)
|
||||
{
|
||||
this.selectTransportManagerCallback = selectTransportManagerCallback;
|
||||
this.Begin();
|
||||
}
|
||||
|
||||
public static void End(IAsyncResult result)
|
||||
{
|
||||
AsyncResult.End<OpenAsyncResult>(result);
|
||||
}
|
||||
|
||||
protected override void OnScheduled(TransportManagerContainer parent)
|
||||
{
|
||||
parent.Open(this.selectTransportManagerCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user