1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.ServiceModel.Channels
8 using System.Diagnostics;
11 using System.Runtime.Diagnostics;
12 using System.ServiceModel;
13 using System.ServiceModel.Diagnostics;
14 using System.ServiceModel.Diagnostics.Application;
17 delegate IConnectionOrientedTransportFactorySettings TransportSettingsCallback(Uri via);
18 delegate void ConnectionClosedCallback(InitialServerConnectionReader connectionReader);
20 // Host for a connection that deals with structured close/abort and notifying the owner appropriately
21 // used for cases where no one else (channel, etc) actually owns the reader
22 abstract class InitialServerConnectionReader : IDisposable
25 int maxContentTypeSize;
26 IConnection connection;
27 Action connectionDequeuedCallback;
28 ConnectionClosedCallback closedCallback;
31 protected InitialServerConnectionReader(IConnection connection, ConnectionClosedCallback closedCallback)
32 : this(connection, closedCallback,
33 ConnectionOrientedTransportDefaults.MaxViaSize, ConnectionOrientedTransportDefaults.MaxContentTypeSize)
37 protected InitialServerConnectionReader(IConnection connection, ConnectionClosedCallback closedCallback, int maxViaSize, int maxContentTypeSize)
39 if (connection == null)
41 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("connection");
44 if (closedCallback == null)
46 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("closedCallback");
49 this.connection = connection;
50 this.closedCallback = closedCallback;
51 this.maxContentTypeSize = maxContentTypeSize;
52 this.maxViaSize = maxViaSize;
55 public IConnection Connection
57 get { return connection; }
60 public Action ConnectionDequeuedCallback
64 return this.connectionDequeuedCallback;
69 this.connectionDequeuedCallback = value;
73 public Action GetConnectionDequeuedCallback()
75 Action dequeuedCallback = this.connectionDequeuedCallback;
76 this.connectionDequeuedCallback = null;
77 return dequeuedCallback;
80 protected bool IsClosed
82 get { return isClosed; }
85 protected int MaxContentTypeSize
89 return maxContentTypeSize;
93 protected int MaxViaSize
106 // used by the listener to release the connection object so it can be closed at a later time
107 public void ReleaseConnection()
113 // for cached connections -- try to shut down gracefully if possible
114 public void CloseFromPool(TimeSpan timeout)
120 catch (CommunicationException communicationException)
122 DiagnosticUtility.TraceHandledException(communicationException, TraceEventType.Information);
124 catch (TimeoutException timeoutException)
126 if (TD.CloseTimeoutIsEnabled())
128 TD.CloseTimeout(timeoutException.Message);
130 DiagnosticUtility.TraceHandledException(timeoutException, TraceEventType.Information);
134 public void Dispose()
143 this.isClosed = true;
146 IConnection connection = this.connection;
147 if (connection != null)
152 if (this.connectionDequeuedCallback != null)
154 this.connectionDequeuedCallback();
158 protected void Abort()
163 internal void Abort(Exception e)
177 if (DiagnosticUtility.ShouldTraceError)
179 TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.ChannelConnectionDropped,
180 SR.GetString(SR.TraceCodeChannelConnectionDropped), this, e);
188 if (closedCallback != null)
190 closedCallback(this);
193 if (this.connectionDequeuedCallback != null)
195 this.connectionDequeuedCallback();
200 protected void Close(TimeSpan timeout)
210 bool success = false;
213 connection.Close(timeout, true);
223 if (closedCallback != null)
225 closedCallback(this);
228 if (this.connectionDequeuedCallback != null)
230 this.connectionDequeuedCallback();
235 internal static void SendFault(IConnection connection, string faultString, byte[] drainBuffer, TimeSpan sendTimeout, int maxRead)
238 if (TD.ConnectionReaderSendFaultIsEnabled())
240 TD.ConnectionReaderSendFault(faultString);
243 EncodedFault encodedFault = new EncodedFault(faultString);
244 TimeoutHelper timeoutHelper = new TimeoutHelper(sendTimeout);
247 connection.Write(encodedFault.EncodedBytes, 0, encodedFault.EncodedBytes.Length, true, timeoutHelper.RemainingTime());
248 connection.Shutdown(timeoutHelper.RemainingTime());
250 catch (CommunicationException e)
252 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
256 catch (TimeoutException e)
258 if (TD.SendTimeoutIsEnabled())
260 TD.SendTimeout(e.Message);
262 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
267 // make sure we read until EOF or a quota is hit
274 read = connection.Read(drainBuffer, 0, drainBuffer.Length, timeoutHelper.RemainingTime());
276 catch (CommunicationException e)
278 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
282 catch (TimeoutException e)
284 if (TD.SendTimeoutIsEnabled())
286 TD.SendTimeout(e.Message);
288 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
297 if (readTotal > maxRead || timeoutHelper.RemainingTime() <= TimeSpan.Zero)
304 ConnectionUtilities.CloseNoThrow(connection, timeoutHelper.RemainingTime());
307 public static IAsyncResult BeginUpgradeConnection(IConnection connection, StreamUpgradeAcceptor upgradeAcceptor,
308 IDefaultCommunicationTimeouts defaultTimeouts, AsyncCallback callback, object state)
310 return new UpgradeConnectionAsyncResult(connection, upgradeAcceptor, defaultTimeouts, callback, state);
313 public static IConnection EndUpgradeConnection(IAsyncResult result)
315 // get our upgraded connection
316 return UpgradeConnectionAsyncResult.End(result);
319 public static IConnection UpgradeConnection(IConnection connection, StreamUpgradeAcceptor upgradeAcceptor, IDefaultCommunicationTimeouts defaultTimeouts)
321 ConnectionStream connectionStream = new ConnectionStream(connection, defaultTimeouts);
322 Stream stream = upgradeAcceptor.AcceptUpgrade(connectionStream);
323 if (upgradeAcceptor is StreamSecurityUpgradeAcceptor)
325 if (DiagnosticUtility.ShouldTraceInformation)
327 TraceUtility.TraceEvent(TraceEventType.Information,
328 TraceCode.StreamSecurityUpgradeAccepted, SR.GetString(SR.TraceCodeStreamSecurityUpgradeAccepted),
329 new StringTraceRecord("Type", upgradeAcceptor.GetType().ToString()), connection, null);
333 return new StreamConnection(stream, connectionStream);
336 class UpgradeConnectionAsyncResult : AsyncResult
338 ConnectionStream connectionStream;
339 static AsyncCallback onAcceptUpgrade = Fx.ThunkCallback(new AsyncCallback(OnAcceptUpgrade));
340 IConnection connection;
341 StreamUpgradeAcceptor upgradeAcceptor;
343 public UpgradeConnectionAsyncResult(IConnection connection,
344 StreamUpgradeAcceptor upgradeAcceptor, IDefaultCommunicationTimeouts defaultTimeouts,
345 AsyncCallback callback, object state)
346 : base(callback, state)
348 this.upgradeAcceptor = upgradeAcceptor;
349 this.connectionStream = new ConnectionStream(connection, defaultTimeouts);
350 bool completeSelf = false;
352 IAsyncResult result = upgradeAcceptor.BeginAcceptUpgrade(connectionStream, onAcceptUpgrade, this);
354 if (result.CompletedSynchronously)
356 CompleteAcceptUpgrade(result);
366 public static IConnection End(IAsyncResult result)
368 UpgradeConnectionAsyncResult thisPtr = AsyncResult.End<UpgradeConnectionAsyncResult>(result);
369 return thisPtr.connection;
372 void CompleteAcceptUpgrade(IAsyncResult result)
375 bool endSucceeded = false;
378 stream = this.upgradeAcceptor.EndAcceptUpgrade(result);
383 if (upgradeAcceptor is StreamSecurityUpgradeAcceptor)
385 if (DiagnosticUtility.ShouldTraceInformation && endSucceeded)
387 TraceUtility.TraceEvent(TraceEventType.Information,
388 TraceCode.StreamSecurityUpgradeAccepted, SR.GetString(SR.TraceCodeStreamSecurityUpgradeAccepted),
389 new StringTraceRecord("Type", upgradeAcceptor.GetType().ToString()), this, null);
393 this.connection = new StreamConnection(stream, this.connectionStream);
396 static void OnAcceptUpgrade(IAsyncResult result)
398 if (result.CompletedSynchronously)
401 UpgradeConnectionAsyncResult thisPtr = (UpgradeConnectionAsyncResult)result.AsyncState;
402 Exception completionException = null;
405 thisPtr.CompleteAcceptUpgrade(result);
407 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
415 completionException = e;
418 thisPtr.Complete(false, completionException);