InitialServerConnectionReader.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System;
  7. using System.Diagnostics;
  8. using System.IO;
  9. using System.Runtime;
  10. using System.Runtime.Diagnostics;
  11. using System.ServiceModel;
  12. using System.ServiceModel.Diagnostics;
  13. using System.ServiceModel.Diagnostics.Application;
  14. delegate IConnectionOrientedTransportFactorySettings TransportSettingsCallback(Uri via);
  15. delegate void ConnectionClosedCallback(InitialServerConnectionReader connectionReader);
  16. // Host for a connection that deals with structured close/abort and notifying the owner appropriately
  17. // used for cases where no one else (channel, etc) actually owns the reader
  18. abstract class InitialServerConnectionReader : IDisposable
  19. {
  20. int maxViaSize;
  21. int maxContentTypeSize;
  22. IConnection connection;
  23. Action connectionDequeuedCallback;
  24. ConnectionClosedCallback closedCallback;
  25. bool isClosed;
  26. protected InitialServerConnectionReader(IConnection connection, ConnectionClosedCallback closedCallback)
  27. : this(connection, closedCallback,
  28. ConnectionOrientedTransportDefaults.MaxViaSize, ConnectionOrientedTransportDefaults.MaxContentTypeSize)
  29. {
  30. }
  31. protected InitialServerConnectionReader(IConnection connection, ConnectionClosedCallback closedCallback, int maxViaSize, int maxContentTypeSize)
  32. {
  33. if (connection == null)
  34. {
  35. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("connection");
  36. }
  37. if (closedCallback == null)
  38. {
  39. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("closedCallback");
  40. }
  41. this.connection = connection;
  42. this.closedCallback = closedCallback;
  43. this.maxContentTypeSize = maxContentTypeSize;
  44. this.maxViaSize = maxViaSize;
  45. }
  46. public IConnection Connection
  47. {
  48. get { return connection; }
  49. }
  50. public Action ConnectionDequeuedCallback
  51. {
  52. get
  53. {
  54. return this.connectionDequeuedCallback;
  55. }
  56. set
  57. {
  58. this.connectionDequeuedCallback = value;
  59. }
  60. }
  61. public Action GetConnectionDequeuedCallback()
  62. {
  63. Action dequeuedCallback = this.connectionDequeuedCallback;
  64. this.connectionDequeuedCallback = null;
  65. return dequeuedCallback;
  66. }
  67. protected bool IsClosed
  68. {
  69. get { return isClosed; }
  70. }
  71. protected int MaxContentTypeSize
  72. {
  73. get
  74. {
  75. return maxContentTypeSize;
  76. }
  77. }
  78. protected int MaxViaSize
  79. {
  80. get
  81. {
  82. return maxViaSize;
  83. }
  84. }
  85. object ThisLock
  86. {
  87. get { return this; }
  88. }
  89. // used by the listener to release the connection object so it can be closed at a later time
  90. public void ReleaseConnection()
  91. {
  92. isClosed = true;
  93. connection = null;
  94. }
  95. // for cached connections -- try to shut down gracefully if possible
  96. public void CloseFromPool(TimeSpan timeout)
  97. {
  98. try
  99. {
  100. Close(timeout);
  101. }
  102. catch (CommunicationException communicationException)
  103. {
  104. DiagnosticUtility.TraceHandledException(communicationException, TraceEventType.Information);
  105. }
  106. catch (TimeoutException timeoutException)
  107. {
  108. if (TD.CloseTimeoutIsEnabled())
  109. {
  110. TD.CloseTimeout(timeoutException.Message);
  111. }
  112. DiagnosticUtility.TraceHandledException(timeoutException, TraceEventType.Information);
  113. }
  114. }
  115. public void Dispose()
  116. {
  117. lock (ThisLock)
  118. {
  119. if (isClosed)
  120. {
  121. return;
  122. }
  123. this.isClosed = true;
  124. }
  125. IConnection connection = this.connection;
  126. if (connection != null)
  127. {
  128. connection.Abort();
  129. }
  130. if (this.connectionDequeuedCallback != null)
  131. {
  132. this.connectionDequeuedCallback();
  133. }
  134. }
  135. protected void Abort()
  136. {
  137. Abort(null);
  138. }
  139. internal void Abort(Exception e)
  140. {
  141. lock (ThisLock)
  142. {
  143. if (isClosed)
  144. return;
  145. isClosed = true;
  146. }
  147. try
  148. {
  149. if (e != null)
  150. {
  151. if (DiagnosticUtility.ShouldTraceError)
  152. {
  153. TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.ChannelConnectionDropped,
  154. SR.GetString(SR.TraceCodeChannelConnectionDropped), this, e);
  155. }
  156. }
  157. connection.Abort();
  158. }
  159. finally
  160. {
  161. if (closedCallback != null)
  162. {
  163. closedCallback(this);
  164. }
  165. if (this.connectionDequeuedCallback != null)
  166. {
  167. this.connectionDequeuedCallback();
  168. }
  169. }
  170. }
  171. protected void Close(TimeSpan timeout)
  172. {
  173. lock (ThisLock)
  174. {
  175. if (isClosed)
  176. return;
  177. isClosed = true;
  178. }
  179. bool success = false;
  180. try
  181. {
  182. connection.Close(timeout, true);
  183. success = true;
  184. }
  185. finally
  186. {
  187. if (!success)
  188. {
  189. connection.Abort();
  190. }
  191. if (closedCallback != null)
  192. {
  193. closedCallback(this);
  194. }
  195. if (this.connectionDequeuedCallback != null)
  196. {
  197. this.connectionDequeuedCallback();
  198. }
  199. }
  200. }
  201. internal static void SendFault(IConnection connection, string faultString, byte[] drainBuffer, TimeSpan sendTimeout, int maxRead)
  202. {
  203. if (TD.ConnectionReaderSendFaultIsEnabled())
  204. {
  205. TD.ConnectionReaderSendFault(faultString);
  206. }
  207. EncodedFault encodedFault = new EncodedFault(faultString);
  208. TimeoutHelper timeoutHelper = new TimeoutHelper(sendTimeout);
  209. try
  210. {
  211. connection.Write(encodedFault.EncodedBytes, 0, encodedFault.EncodedBytes.Length, true, timeoutHelper.RemainingTime());
  212. connection.Shutdown(timeoutHelper.RemainingTime());
  213. }
  214. catch (CommunicationException e)
  215. {
  216. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  217. connection.Abort();
  218. return;
  219. }
  220. catch (TimeoutException e)
  221. {
  222. if (TD.SendTimeoutIsEnabled())
  223. {
  224. TD.SendTimeout(e.Message);
  225. }
  226. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  227. connection.Abort();
  228. return;
  229. }
  230. // make sure we read until EOF or a quota is hit
  231. int read = 0;
  232. int readTotal = 0;
  233. for (;;)
  234. {
  235. try
  236. {
  237. read = connection.Read(drainBuffer, 0, drainBuffer.Length, timeoutHelper.RemainingTime());
  238. }
  239. catch (CommunicationException e)
  240. {
  241. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  242. connection.Abort();
  243. return;
  244. }
  245. catch (TimeoutException e)
  246. {
  247. if (TD.SendTimeoutIsEnabled())
  248. {
  249. TD.SendTimeout(e.Message);
  250. }
  251. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  252. connection.Abort();
  253. return;
  254. }
  255. if (read == 0)
  256. break;
  257. readTotal += read;
  258. if (readTotal > maxRead || timeoutHelper.RemainingTime() <= TimeSpan.Zero)
  259. {
  260. connection.Abort();
  261. return;
  262. }
  263. }
  264. ConnectionUtilities.CloseNoThrow(connection, timeoutHelper.RemainingTime());
  265. }
  266. public static IAsyncResult BeginUpgradeConnection(IConnection connection, StreamUpgradeAcceptor upgradeAcceptor,
  267. IDefaultCommunicationTimeouts defaultTimeouts, AsyncCallback callback, object state)
  268. {
  269. return new UpgradeConnectionAsyncResult(connection, upgradeAcceptor, defaultTimeouts, callback, state);
  270. }
  271. public static IConnection EndUpgradeConnection(IAsyncResult result)
  272. {
  273. // get our upgraded connection
  274. return UpgradeConnectionAsyncResult.End(result);
  275. }
  276. public static IConnection UpgradeConnection(IConnection connection, StreamUpgradeAcceptor upgradeAcceptor, IDefaultCommunicationTimeouts defaultTimeouts)
  277. {
  278. ConnectionStream connectionStream = new ConnectionStream(connection, defaultTimeouts);
  279. Stream stream = upgradeAcceptor.AcceptUpgrade(connectionStream);
  280. if (upgradeAcceptor is StreamSecurityUpgradeAcceptor)
  281. {
  282. if (DiagnosticUtility.ShouldTraceInformation)
  283. {
  284. TraceUtility.TraceEvent(TraceEventType.Information,
  285. TraceCode.StreamSecurityUpgradeAccepted, SR.GetString(SR.TraceCodeStreamSecurityUpgradeAccepted),
  286. new StringTraceRecord("Type", upgradeAcceptor.GetType().ToString()), connection, null);
  287. }
  288. }
  289. return new StreamConnection(stream, connectionStream);
  290. }
  291. class UpgradeConnectionAsyncResult : AsyncResult
  292. {
  293. ConnectionStream connectionStream;
  294. static AsyncCallback onAcceptUpgrade = Fx.ThunkCallback(new AsyncCallback(OnAcceptUpgrade));
  295. IConnection connection;
  296. StreamUpgradeAcceptor upgradeAcceptor;
  297. public UpgradeConnectionAsyncResult(IConnection connection,
  298. StreamUpgradeAcceptor upgradeAcceptor, IDefaultCommunicationTimeouts defaultTimeouts,
  299. AsyncCallback callback, object state)
  300. : base(callback, state)
  301. {
  302. this.upgradeAcceptor = upgradeAcceptor;
  303. this.connectionStream = new ConnectionStream(connection, defaultTimeouts);
  304. bool completeSelf = false;
  305. IAsyncResult result = upgradeAcceptor.BeginAcceptUpgrade(connectionStream, onAcceptUpgrade, this);
  306. if (result.CompletedSynchronously)
  307. {
  308. CompleteAcceptUpgrade(result);
  309. completeSelf = true;
  310. }
  311. if (completeSelf)
  312. {
  313. base.Complete(true);
  314. }
  315. }
  316. public static IConnection End(IAsyncResult result)
  317. {
  318. UpgradeConnectionAsyncResult thisPtr = AsyncResult.End<UpgradeConnectionAsyncResult>(result);
  319. return thisPtr.connection;
  320. }
  321. void CompleteAcceptUpgrade(IAsyncResult result)
  322. {
  323. Stream stream;
  324. bool endSucceeded = false;
  325. try
  326. {
  327. stream = this.upgradeAcceptor.EndAcceptUpgrade(result);
  328. endSucceeded = true;
  329. }
  330. finally
  331. {
  332. if (upgradeAcceptor is StreamSecurityUpgradeAcceptor)
  333. {
  334. if (DiagnosticUtility.ShouldTraceInformation && endSucceeded)
  335. {
  336. TraceUtility.TraceEvent(TraceEventType.Information,
  337. TraceCode.StreamSecurityUpgradeAccepted, SR.GetString(SR.TraceCodeStreamSecurityUpgradeAccepted),
  338. new StringTraceRecord("Type", upgradeAcceptor.GetType().ToString()), this, null);
  339. }
  340. }
  341. }
  342. this.connection = new StreamConnection(stream, this.connectionStream);
  343. }
  344. static void OnAcceptUpgrade(IAsyncResult result)
  345. {
  346. if (result.CompletedSynchronously)
  347. return;
  348. UpgradeConnectionAsyncResult thisPtr = (UpgradeConnectionAsyncResult)result.AsyncState;
  349. Exception completionException = null;
  350. try
  351. {
  352. thisPtr.CompleteAcceptUpgrade(result);
  353. }
  354. #pragma warning suppress 56500 // [....], transferring exception to another thread
  355. catch (Exception e)
  356. {
  357. if (Fx.IsFatal(e))
  358. {
  359. throw;
  360. }
  361. completionException = e;
  362. }
  363. thisPtr.Complete(false, completionException);
  364. }
  365. }
  366. }
  367. }