SocketConnection.cs 88 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Net;
  9. using System.Net.Sockets;
  10. using System.Runtime;
  11. using System.Runtime.Diagnostics;
  12. using System.Runtime.InteropServices;
  13. using System.Security;
  14. using System.Security.Permissions;
  15. using System.ServiceModel;
  16. using System.ServiceModel.Diagnostics;
  17. using System.ServiceModel.Diagnostics.Application;
  18. using System.Text;
  19. using System.Threading;
  20. class SocketConnection : IConnection
  21. {
  22. static AsyncCallback onReceiveCompleted;
  23. static EventHandler<SocketAsyncEventArgs> onReceiveAsyncCompleted;
  24. static EventHandler<SocketAsyncEventArgs> onSocketSendCompleted;
  25. // common state
  26. Socket socket;
  27. TimeSpan sendTimeout;
  28. TimeSpan readFinTimeout;
  29. TimeSpan receiveTimeout;
  30. CloseState closeState;
  31. bool isShutdown;
  32. bool noDelay = false;
  33. bool aborted;
  34. TraceEventType exceptionEventType;
  35. // close state
  36. TimeoutHelper closeTimeoutHelper;
  37. static WaitCallback onWaitForFinComplete = new WaitCallback(OnWaitForFinComplete);
  38. // read state
  39. int asyncReadSize;
  40. SocketAsyncEventArgs asyncReadEventArgs;
  41. byte[] readBuffer;
  42. int asyncReadBufferSize;
  43. object asyncReadState;
  44. WaitCallback asyncReadCallback;
  45. Exception asyncReadException;
  46. bool asyncReadPending;
  47. // write state
  48. SocketAsyncEventArgs asyncWriteEventArgs;
  49. object asyncWriteState;
  50. WaitCallback asyncWriteCallback;
  51. Exception asyncWriteException;
  52. bool asyncWritePending;
  53. IOThreadTimer receiveTimer;
  54. static Action<object> onReceiveTimeout;
  55. IOThreadTimer sendTimer;
  56. static Action<object> onSendTimeout;
  57. string timeoutErrorString;
  58. TransferOperation timeoutErrorTransferOperation;
  59. IPEndPoint remoteEndpoint;
  60. ConnectionBufferPool connectionBufferPool;
  61. string remoteEndpointAddress;
  62. public SocketConnection(Socket socket, ConnectionBufferPool connectionBufferPool, bool autoBindToCompletionPort)
  63. {
  64. if (socket == null)
  65. {
  66. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("socket");
  67. }
  68. Fx.Assert(connectionBufferPool != null, "Argument connectionBufferPool cannot be null");
  69. this.closeState = CloseState.Open;
  70. this.exceptionEventType = TraceEventType.Error;
  71. this.socket = socket;
  72. this.connectionBufferPool = connectionBufferPool;
  73. this.readBuffer = this.connectionBufferPool.Take();
  74. this.asyncReadBufferSize = this.readBuffer.Length;
  75. this.socket.SendBufferSize = this.socket.ReceiveBufferSize = this.asyncReadBufferSize;
  76. this.sendTimeout = this.receiveTimeout = TimeSpan.MaxValue;
  77. this.remoteEndpoint = null;
  78. if (autoBindToCompletionPort)
  79. {
  80. this.socket.UseOnlyOverlappedIO = false;
  81. }
  82. // In SMSvcHost, sockets must be duplicated to the target process. Binding a handle to a completion port
  83. // prevents any duplicated handle from ever binding to a completion port. The target process is where we
  84. // want to use completion ports for performance. This means that in SMSvcHost, socket.UseOnlyOverlappedIO
  85. // must be set to true to prevent completion port use.
  86. if (this.socket.UseOnlyOverlappedIO)
  87. {
  88. // Init BeginRead state
  89. if (onReceiveCompleted == null)
  90. {
  91. onReceiveCompleted = Fx.ThunkCallback(new AsyncCallback(OnReceiveCompleted));
  92. }
  93. }
  94. this.TraceSocketInfo(socket, TraceCode.SocketConnectionCreate, SR.TraceCodeSocketConnectionCreate, null);
  95. }
  96. public int AsyncReadBufferSize
  97. {
  98. get { return asyncReadBufferSize; }
  99. }
  100. public byte[] AsyncReadBuffer
  101. {
  102. get
  103. {
  104. return readBuffer;
  105. }
  106. }
  107. object ThisLock
  108. {
  109. get { return this; }
  110. }
  111. public TraceEventType ExceptionEventType
  112. {
  113. get { return this.exceptionEventType; }
  114. set { this.exceptionEventType = value; }
  115. }
  116. public IPEndPoint RemoteIPEndPoint
  117. {
  118. get
  119. {
  120. // this property should only be called on the receive path
  121. if (remoteEndpoint == null && this.closeState == CloseState.Open)
  122. {
  123. try
  124. {
  125. remoteEndpoint = (IPEndPoint)socket.RemoteEndPoint;
  126. }
  127. catch (SocketException socketException)
  128. {
  129. // will never be a timeout error, so TimeSpan.Zero is ok
  130. #pragma warning suppress 56503 // Called from Receive path, SocketConnection cannot allow a SocketException to escape.
  131. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  132. ConvertReceiveException(socketException, TimeSpan.Zero), ExceptionEventType);
  133. }
  134. catch (ObjectDisposedException objectDisposedException)
  135. {
  136. Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Undefined);
  137. if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
  138. {
  139. #pragma warning suppress 56503 // rethrow
  140. throw;
  141. }
  142. else
  143. {
  144. #pragma warning suppress 56503 // Called from Receive path, SocketConnection must convert ObjectDisposedException properly.
  145. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
  146. }
  147. }
  148. }
  149. return remoteEndpoint;
  150. }
  151. }
  152. IOThreadTimer SendTimer
  153. {
  154. get
  155. {
  156. if (this.sendTimer == null)
  157. {
  158. if (onSendTimeout == null)
  159. {
  160. onSendTimeout = new Action<object>(OnSendTimeout);
  161. }
  162. this.sendTimer = new IOThreadTimer(onSendTimeout, this, false);
  163. }
  164. return this.sendTimer;
  165. }
  166. }
  167. IOThreadTimer ReceiveTimer
  168. {
  169. get
  170. {
  171. if (this.receiveTimer == null)
  172. {
  173. if (onReceiveTimeout == null)
  174. {
  175. onReceiveTimeout = new Action<object>(OnReceiveTimeout);
  176. }
  177. this.receiveTimer = new IOThreadTimer(onReceiveTimeout, this, false);
  178. }
  179. return this.receiveTimer;
  180. }
  181. }
  182. string RemoteEndpointAddress
  183. {
  184. get
  185. {
  186. if (remoteEndpointAddress == null)
  187. {
  188. try
  189. {
  190. IPEndPoint local, remote;
  191. if (TryGetEndpoints(out local, out remote))
  192. {
  193. this.remoteEndpointAddress = TraceUtility.GetRemoteEndpointAddressPort(remote);
  194. }
  195. else
  196. {
  197. //null indicates not initialized.
  198. remoteEndpointAddress = string.Empty;
  199. }
  200. }
  201. catch (Exception exception)
  202. {
  203. if (Fx.IsFatal(exception))
  204. {
  205. throw;
  206. }
  207. }
  208. }
  209. return remoteEndpointAddress;
  210. }
  211. }
  212. static void OnReceiveTimeout(object state)
  213. {
  214. SocketConnection thisPtr = (SocketConnection)state;
  215. thisPtr.Abort(SR.GetString(SR.SocketAbortedReceiveTimedOut, thisPtr.receiveTimeout), TransferOperation.Read);
  216. }
  217. static void OnSendTimeout(object state)
  218. {
  219. SocketConnection thisPtr = (SocketConnection)state;
  220. thisPtr.Abort(TraceEventType.Warning,
  221. SR.GetString(SR.SocketAbortedSendTimedOut, thisPtr.sendTimeout), TransferOperation.Write);
  222. }
  223. static void OnReceiveCompleted(IAsyncResult result)
  224. {
  225. ((SocketConnection)result.AsyncState).OnReceive(result);
  226. }
  227. static void OnReceiveAsyncCompleted(object sender, SocketAsyncEventArgs e)
  228. {
  229. ((SocketConnection)e.UserToken).OnReceiveAsync(sender, e);
  230. }
  231. static void OnSendAsyncCompleted(object sender, SocketAsyncEventArgs e)
  232. {
  233. ((SocketConnection)e.UserToken).OnSendAsync(sender, e);
  234. }
  235. public void Abort()
  236. {
  237. Abort(null, TransferOperation.Undefined);
  238. }
  239. void Abort(string timeoutErrorString, TransferOperation transferOperation)
  240. {
  241. TraceEventType traceEventType = TraceEventType.Warning;
  242. // we could be timing out a cached connection
  243. if (this.ExceptionEventType == TraceEventType.Information)
  244. {
  245. traceEventType = this.ExceptionEventType;
  246. }
  247. Abort(traceEventType, timeoutErrorString, transferOperation);
  248. }
  249. void Abort(TraceEventType traceEventType)
  250. {
  251. Abort(traceEventType, null, TransferOperation.Undefined);
  252. }
  253. void Abort(TraceEventType traceEventType, string timeoutErrorString, TransferOperation transferOperation)
  254. {
  255. if (TD.SocketConnectionAbortIsEnabled())
  256. {
  257. TD.SocketConnectionAbort(this.socket.GetHashCode());
  258. }
  259. lock (ThisLock)
  260. {
  261. if (closeState == CloseState.Closed)
  262. {
  263. return;
  264. }
  265. this.timeoutErrorString = timeoutErrorString;
  266. this.timeoutErrorTransferOperation = transferOperation;
  267. aborted = true;
  268. closeState = CloseState.Closed;
  269. if (this.asyncReadPending)
  270. {
  271. CancelReceiveTimer();
  272. }
  273. else
  274. {
  275. this.DisposeReadEventArgs();
  276. }
  277. if (this.asyncWritePending)
  278. {
  279. CancelSendTimer();
  280. }
  281. else
  282. {
  283. this.DisposeWriteEventArgs();
  284. }
  285. }
  286. if (DiagnosticUtility.ShouldTrace(traceEventType))
  287. {
  288. TraceUtility.TraceEvent(traceEventType, TraceCode.SocketConnectionAbort,
  289. SR.GetString(SR.TraceCodeSocketConnectionAbort), this);
  290. }
  291. socket.Close(0);
  292. }
  293. void AbortRead()
  294. {
  295. lock (ThisLock)
  296. {
  297. if (this.asyncReadPending)
  298. {
  299. if (closeState != CloseState.Closed)
  300. {
  301. this.SetUserToken(this.asyncReadEventArgs, null);
  302. this.asyncReadPending = false;
  303. CancelReceiveTimer();
  304. }
  305. else
  306. {
  307. this.DisposeReadEventArgs();
  308. }
  309. }
  310. }
  311. }
  312. void CancelReceiveTimer()
  313. {
  314. // CSDMain 34539: Snapshot the timer so that we don't null ref if there is a ----
  315. // between calls to CancelReceiveTimer (e.g., Abort, AsyncReadCallback)
  316. IOThreadTimer receiveTimerSnapshot = this.receiveTimer;
  317. this.receiveTimer = null;
  318. if (receiveTimerSnapshot != null)
  319. {
  320. receiveTimerSnapshot.Cancel();
  321. }
  322. }
  323. void CancelSendTimer()
  324. {
  325. IOThreadTimer sendTimerSnapshot = this.sendTimer;
  326. this.sendTimer = null;
  327. if (sendTimerSnapshot != null)
  328. {
  329. sendTimerSnapshot.Cancel();
  330. }
  331. }
  332. void CloseAsyncAndLinger()
  333. {
  334. readFinTimeout = closeTimeoutHelper.RemainingTime();
  335. try
  336. {
  337. if (BeginReadCore(0, 1, readFinTimeout, onWaitForFinComplete, this) == AsyncCompletionResult.Queued)
  338. {
  339. return;
  340. }
  341. int bytesRead = EndRead();
  342. if (bytesRead > 0)
  343. {
  344. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  345. new CommunicationException(SR.GetString(SR.SocketCloseReadReceivedData, socket.RemoteEndPoint)),
  346. ExceptionEventType);
  347. }
  348. }
  349. catch (TimeoutException timeoutException)
  350. {
  351. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new TimeoutException(
  352. SR.GetString(SR.SocketCloseReadTimeout, socket.RemoteEndPoint, readFinTimeout), timeoutException),
  353. ExceptionEventType);
  354. }
  355. ContinueClose(closeTimeoutHelper.RemainingTime());
  356. }
  357. static void OnWaitForFinComplete(object state)
  358. {
  359. SocketConnection thisPtr = (SocketConnection)state;
  360. try
  361. {
  362. int bytesRead;
  363. try
  364. {
  365. bytesRead = thisPtr.EndRead();
  366. if (bytesRead > 0)
  367. {
  368. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  369. new CommunicationException(SR.GetString(SR.SocketCloseReadReceivedData, thisPtr.socket.RemoteEndPoint)),
  370. thisPtr.ExceptionEventType);
  371. }
  372. }
  373. catch (TimeoutException timeoutException)
  374. {
  375. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new TimeoutException(
  376. SR.GetString(SR.SocketCloseReadTimeout, thisPtr.socket.RemoteEndPoint, thisPtr.readFinTimeout),
  377. timeoutException), thisPtr.ExceptionEventType);
  378. }
  379. thisPtr.ContinueClose(thisPtr.closeTimeoutHelper.RemainingTime());
  380. }
  381. catch (Exception e)
  382. {
  383. if (Fx.IsFatal(e))
  384. {
  385. throw;
  386. }
  387. DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
  388. // The user has no opportunity to clean up the connection in the async and linger
  389. // code path, ensure cleanup finishes.
  390. thisPtr.Abort();
  391. }
  392. }
  393. public void Close(TimeSpan timeout, bool asyncAndLinger)
  394. {
  395. lock (ThisLock)
  396. {
  397. if (closeState == CloseState.Closing || closeState == CloseState.Closed)
  398. {
  399. // already closing or closed, so just return
  400. return;
  401. }
  402. this.TraceSocketInfo(this.socket, TraceCode.SocketConnectionClose, SR.TraceCodeSocketConnectionClose, timeout.ToString());
  403. closeState = CloseState.Closing;
  404. }
  405. // first we shutdown our send-side
  406. closeTimeoutHelper = new TimeoutHelper(timeout);
  407. Shutdown(closeTimeoutHelper.RemainingTime());
  408. if (asyncAndLinger)
  409. {
  410. CloseAsyncAndLinger();
  411. }
  412. else
  413. {
  414. CloseSync();
  415. }
  416. }
  417. void CloseSync()
  418. {
  419. byte[] dummy = new byte[1];
  420. // then we check for a FIN from the other side (i.e. read zero)
  421. int bytesRead;
  422. readFinTimeout = closeTimeoutHelper.RemainingTime();
  423. try
  424. {
  425. bytesRead = ReadCore(dummy, 0, 1, readFinTimeout, true);
  426. if (bytesRead > 0)
  427. {
  428. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  429. new CommunicationException(SR.GetString(SR.SocketCloseReadReceivedData, socket.RemoteEndPoint)), ExceptionEventType);
  430. }
  431. }
  432. catch (TimeoutException timeoutException)
  433. {
  434. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new TimeoutException(
  435. SR.GetString(SR.SocketCloseReadTimeout, socket.RemoteEndPoint, readFinTimeout), timeoutException), ExceptionEventType);
  436. }
  437. // finally we call Close with whatever time is remaining
  438. ContinueClose(closeTimeoutHelper.RemainingTime());
  439. }
  440. public void ContinueClose(TimeSpan timeout)
  441. {
  442. // trace if we're effectively aborting
  443. if (timeout <= TimeSpan.Zero && DiagnosticUtility.ShouldTraceWarning)
  444. {
  445. TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.SocketConnectionAbortClose,
  446. SR.GetString(SR.TraceCodeSocketConnectionAbortClose), this);
  447. }
  448. socket.Close(TimeoutHelper.ToMilliseconds(timeout));
  449. lock (ThisLock)
  450. {
  451. // Abort could have been called on a separate thread and cleaned up
  452. // our buffers/completion here
  453. if (this.closeState != CloseState.Closed)
  454. {
  455. if (!this.asyncReadPending)
  456. {
  457. this.DisposeReadEventArgs();
  458. }
  459. if (!this.asyncWritePending)
  460. {
  461. this.DisposeWriteEventArgs();
  462. }
  463. }
  464. closeState = CloseState.Closed;
  465. }
  466. }
  467. public void Shutdown(TimeSpan timeout)
  468. {
  469. lock (ThisLock)
  470. {
  471. if (isShutdown)
  472. {
  473. return;
  474. }
  475. isShutdown = true;
  476. }
  477. try
  478. {
  479. socket.Shutdown(SocketShutdown.Send);
  480. }
  481. catch (SocketException socketException)
  482. {
  483. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  484. ConvertSendException(socketException, TimeSpan.MaxValue), ExceptionEventType);
  485. }
  486. catch (ObjectDisposedException objectDisposedException)
  487. {
  488. Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Undefined);
  489. if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
  490. {
  491. throw;
  492. }
  493. else
  494. {
  495. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
  496. }
  497. }
  498. }
  499. void ThrowIfNotOpen()
  500. {
  501. if (closeState == CloseState.Closing || closeState == CloseState.Closed)
  502. {
  503. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  504. ConvertObjectDisposedException(new ObjectDisposedException(
  505. this.GetType().ToString(), SR.GetString(SR.SocketConnectionDisposed)), TransferOperation.Undefined), ExceptionEventType);
  506. }
  507. }
  508. void ThrowIfClosed()
  509. {
  510. if (closeState == CloseState.Closed)
  511. {
  512. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  513. ConvertObjectDisposedException(new ObjectDisposedException(
  514. this.GetType().ToString(), SR.GetString(SR.SocketConnectionDisposed)), TransferOperation.Undefined), ExceptionEventType);
  515. }
  516. }
  517. void TraceSocketInfo(Socket socket, int traceCode, string srString, string timeoutString)
  518. {
  519. if (DiagnosticUtility.ShouldTraceInformation)
  520. {
  521. Dictionary<string, string> values = new Dictionary<string, string>(4);
  522. values["State"] = this.closeState.ToString();
  523. if (timeoutString != null)
  524. {
  525. values["Timeout"] = timeoutString;
  526. }
  527. if (socket != null && this.closeState != CloseState.Closing)
  528. {
  529. if (socket.LocalEndPoint != null)
  530. {
  531. values["LocalEndpoint"] = socket.LocalEndPoint.ToString();
  532. }
  533. if (socket.RemoteEndPoint != null)
  534. {
  535. values["RemoteEndPoint"] = socket.RemoteEndPoint.ToString();
  536. }
  537. }
  538. TraceUtility.TraceEvent(TraceEventType.Information, traceCode, SR.GetString(srString), new DictionaryTraceRecord(values), this, null);
  539. }
  540. }
  541. bool TryGetEndpoints(out IPEndPoint localIPEndpoint, out IPEndPoint remoteIPEndpoint)
  542. {
  543. localIPEndpoint = null;
  544. remoteIPEndpoint = null;
  545. if (this.closeState == CloseState.Open)
  546. {
  547. try
  548. {
  549. remoteIPEndpoint = this.remoteEndpoint ?? (IPEndPoint)this.socket.RemoteEndPoint;
  550. localIPEndpoint = (IPEndPoint)this.socket.LocalEndPoint;
  551. }
  552. catch (Exception exception)
  553. {
  554. if (Fx.IsFatal(exception))
  555. {
  556. throw;
  557. }
  558. DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning);
  559. }
  560. }
  561. return localIPEndpoint != null && remoteIPEndpoint != null;
  562. }
  563. public object DuplicateAndClose(int targetProcessId)
  564. {
  565. object result = socket.DuplicateAndClose(targetProcessId);
  566. this.Abort(TraceEventType.Information);
  567. return result;
  568. }
  569. public object GetCoreTransport()
  570. {
  571. return socket;
  572. }
  573. public IAsyncResult BeginValidate(Uri uri, AsyncCallback callback, object state)
  574. {
  575. return new CompletedAsyncResult<bool>(true, callback, state);
  576. }
  577. public bool EndValidate(IAsyncResult result)
  578. {
  579. return CompletedAsyncResult<bool>.End(result);
  580. }
  581. Exception ConvertSendException(SocketException socketException, TimeSpan remainingTime)
  582. {
  583. return ConvertTransferException(socketException, this.sendTimeout, socketException,
  584. TransferOperation.Write, this.aborted, this.timeoutErrorString, this.timeoutErrorTransferOperation, this, remainingTime);
  585. }
  586. Exception ConvertReceiveException(SocketException socketException, TimeSpan remainingTime)
  587. {
  588. return ConvertTransferException(socketException, this.receiveTimeout, socketException,
  589. TransferOperation.Read, this.aborted, this.timeoutErrorString, this.timeoutErrorTransferOperation, this, remainingTime);
  590. }
  591. internal static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException)
  592. {
  593. return ConvertTransferException(socketException, timeout, originalException,
  594. TransferOperation.Undefined, false, null, TransferOperation.Undefined, null, TimeSpan.MaxValue);
  595. }
  596. Exception ConvertObjectDisposedException(ObjectDisposedException originalException, TransferOperation transferOperation)
  597. {
  598. if (this.timeoutErrorString != null)
  599. {
  600. return ConvertTimeoutErrorException(originalException, transferOperation, this.timeoutErrorString, this.timeoutErrorTransferOperation);
  601. }
  602. else if (this.aborted)
  603. {
  604. return new CommunicationObjectAbortedException(SR.GetString(SR.SocketConnectionDisposed), originalException);
  605. }
  606. else
  607. {
  608. return originalException;
  609. }
  610. }
  611. static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException,
  612. TransferOperation transferOperation, bool aborted, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation,
  613. SocketConnection socketConnection, TimeSpan remainingTime)
  614. {
  615. if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
  616. {
  617. return new CommunicationObjectAbortedException(socketException.Message, socketException);
  618. }
  619. if (timeoutErrorString != null)
  620. {
  621. return ConvertTimeoutErrorException(originalException, transferOperation, timeoutErrorString, timeoutErrorTransferOperation);
  622. }
  623. TraceEventType exceptionEventType = socketConnection == null ? TraceEventType.Error : socketConnection.ExceptionEventType;
  624. // 10053 can occur due to our timeout sockopt firing, so map to TimeoutException in that case
  625. if (socketException.ErrorCode == UnsafeNativeMethods.WSAECONNABORTED &&
  626. remainingTime <= TimeSpan.Zero)
  627. {
  628. TimeoutException timeoutException = new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout), originalException);
  629. if (TD.TcpConnectionTimedOutIsEnabled())
  630. {
  631. if (socketConnection != null)
  632. {
  633. int socketid = (socketConnection != null && socketConnection.socket != null) ? socketConnection.socket.GetHashCode() : -1;
  634. TD.TcpConnectionTimedOut(socketid, socketConnection.RemoteEndpointAddress);
  635. }
  636. }
  637. if (DiagnosticUtility.ShouldTrace(exceptionEventType))
  638. {
  639. TraceUtility.TraceEvent(exceptionEventType, TraceCode.TcpConnectionTimedOut, GetEndpointString(SR.TcpConnectionTimedOut, timeout, null, socketConnection), timeoutException, null);
  640. }
  641. return timeoutException;
  642. }
  643. if (socketException.ErrorCode == UnsafeNativeMethods.WSAENETRESET ||
  644. socketException.ErrorCode == UnsafeNativeMethods.WSAECONNABORTED ||
  645. socketException.ErrorCode == UnsafeNativeMethods.WSAECONNRESET)
  646. {
  647. if (aborted)
  648. {
  649. return new CommunicationObjectAbortedException(SR.GetString(SR.TcpLocalConnectionAborted), originalException);
  650. }
  651. else
  652. {
  653. CommunicationException communicationException = new CommunicationException(SR.GetString(SR.TcpConnectionResetError, timeout), originalException);
  654. if (TD.TcpConnectionResetErrorIsEnabled())
  655. {
  656. if (socketConnection != null)
  657. {
  658. int socketId = (socketConnection.socket != null) ? socketConnection.socket.GetHashCode() : -1;
  659. TD.TcpConnectionResetError(socketId, socketConnection.RemoteEndpointAddress);
  660. }
  661. }
  662. if (DiagnosticUtility.ShouldTrace(exceptionEventType))
  663. {
  664. TraceUtility.TraceEvent(exceptionEventType, TraceCode.TcpConnectionResetError, GetEndpointString(SR.TcpConnectionResetError, timeout, null, socketConnection), communicationException, null);
  665. }
  666. return communicationException;
  667. }
  668. }
  669. else if (socketException.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
  670. {
  671. TimeoutException timeoutException = new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout), originalException);
  672. if (DiagnosticUtility.ShouldTrace(exceptionEventType))
  673. {
  674. TraceUtility.TraceEvent(exceptionEventType, TraceCode.TcpConnectionTimedOut, GetEndpointString(SR.TcpConnectionTimedOut, timeout, null, socketConnection), timeoutException, null);
  675. }
  676. return timeoutException;
  677. }
  678. else
  679. {
  680. if (aborted)
  681. {
  682. return new CommunicationObjectAbortedException(SR.GetString(SR.TcpTransferError, socketException.ErrorCode, socketException.Message), originalException);
  683. }
  684. else
  685. {
  686. CommunicationException communicationException = new CommunicationException(SR.GetString(SR.TcpTransferError, socketException.ErrorCode, socketException.Message), originalException);
  687. if (DiagnosticUtility.ShouldTrace(exceptionEventType))
  688. {
  689. TraceUtility.TraceEvent(exceptionEventType, TraceCode.TcpTransferError, GetEndpointString(SR.TcpTransferError, TimeSpan.MinValue, socketException, socketConnection), communicationException, null);
  690. }
  691. return communicationException;
  692. }
  693. }
  694. }
  695. static Exception ConvertTimeoutErrorException(Exception originalException,
  696. TransferOperation transferOperation, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation)
  697. {
  698. if (timeoutErrorString == null)
  699. {
  700. Fx.Assert("Argument timeoutErrorString must not be null.");
  701. }
  702. if (transferOperation == timeoutErrorTransferOperation)
  703. {
  704. return new TimeoutException(timeoutErrorString, originalException);
  705. }
  706. else
  707. {
  708. return new CommunicationException(timeoutErrorString, originalException);
  709. }
  710. }
  711. static string GetEndpointString(string sr, TimeSpan timeout, SocketException socketException, SocketConnection socketConnection)
  712. {
  713. IPEndPoint remoteEndpoint = null;
  714. IPEndPoint localEndpoint = null;
  715. bool haveEndpoints = socketConnection != null && socketConnection.TryGetEndpoints(out localEndpoint, out remoteEndpoint);
  716. if (string.Compare(sr, SR.TcpConnectionTimedOut, StringComparison.OrdinalIgnoreCase) == 0)
  717. {
  718. return haveEndpoints
  719. ? SR.GetString(SR.TcpConnectionTimedOutWithIP, timeout, localEndpoint, remoteEndpoint)
  720. : SR.GetString(SR.TcpConnectionTimedOut, timeout);
  721. }
  722. else if (string.Compare(sr, SR.TcpConnectionResetError, StringComparison.OrdinalIgnoreCase) == 0)
  723. {
  724. return haveEndpoints
  725. ? SR.GetString(SR.TcpConnectionResetErrorWithIP, timeout, localEndpoint, remoteEndpoint)
  726. : SR.GetString(SR.TcpConnectionResetError, timeout);
  727. }
  728. else
  729. {
  730. // sr == SR.TcpTransferError
  731. return haveEndpoints
  732. ? SR.GetString(SR.TcpTransferErrorWithIP, socketException.ErrorCode, socketException.Message, localEndpoint, remoteEndpoint)
  733. : SR.GetString(SR.TcpTransferError, socketException.ErrorCode, socketException.Message);
  734. }
  735. }
  736. public AsyncCompletionResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout,
  737. WaitCallback callback, object state)
  738. {
  739. ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
  740. bool abortWrite = true;
  741. try
  742. {
  743. if (TD.SocketAsyncWriteStartIsEnabled())
  744. {
  745. TraceWriteStart(size, true);
  746. }
  747. lock (ThisLock)
  748. {
  749. Fx.Assert(!this.asyncWritePending, "Called BeginWrite twice.");
  750. this.ThrowIfClosed();
  751. this.EnsureWriteEventArgs();
  752. SetImmediate(immediate);
  753. SetWriteTimeout(timeout, false);
  754. this.SetUserToken(this.asyncWriteEventArgs, this);
  755. this.asyncWritePending = true;
  756. this.asyncWriteCallback = callback;
  757. this.asyncWriteState = state;
  758. }
  759. this.asyncWriteEventArgs.SetBuffer(buffer, offset, size);
  760. if (socket.SendAsync(this.asyncWriteEventArgs))
  761. {
  762. abortWrite = false;
  763. return AsyncCompletionResult.Queued;
  764. }
  765. this.HandleSendAsyncCompleted();
  766. abortWrite = false;
  767. return AsyncCompletionResult.Completed;
  768. }
  769. catch (SocketException socketException)
  770. {
  771. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  772. ConvertSendException(socketException, TimeSpan.MaxValue), ExceptionEventType);
  773. }
  774. catch (ObjectDisposedException objectDisposedException)
  775. {
  776. Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
  777. if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
  778. {
  779. throw;
  780. }
  781. else
  782. {
  783. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
  784. }
  785. }
  786. finally
  787. {
  788. if (abortWrite)
  789. {
  790. this.AbortWrite();
  791. }
  792. }
  793. }
  794. public void EndWrite()
  795. {
  796. if (this.asyncWriteException != null)
  797. {
  798. this.AbortWrite();
  799. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(this.asyncWriteException, ExceptionEventType);
  800. }
  801. lock (ThisLock)
  802. {
  803. if (!this.asyncWritePending)
  804. {
  805. throw Fx.AssertAndThrow("SocketConnection.EndWrite called with no write pending.");
  806. }
  807. this.SetUserToken(this.asyncWriteEventArgs, null);
  808. this.asyncWritePending = false;
  809. if (this.closeState == CloseState.Closed)
  810. {
  811. this.DisposeWriteEventArgs();
  812. }
  813. }
  814. }
  815. void OnSendAsync(object sender, SocketAsyncEventArgs eventArgs)
  816. {
  817. Fx.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL.");
  818. this.CancelSendTimer();
  819. try
  820. {
  821. this.HandleSendAsyncCompleted();
  822. Fx.Assert(eventArgs.BytesTransferred == this.asyncWriteEventArgs.Count, "The socket SendAsync did not send all the bytes.");
  823. }
  824. catch (SocketException socketException)
  825. {
  826. this.asyncWriteException = ConvertSendException(socketException, TimeSpan.MaxValue);
  827. }
  828. #pragma warning suppress 56500 // [....], transferring exception to caller
  829. catch (Exception exception)
  830. {
  831. if (Fx.IsFatal(exception))
  832. {
  833. throw;
  834. }
  835. this.asyncWriteException = exception;
  836. }
  837. this.FinishWrite();
  838. }
  839. void HandleSendAsyncCompleted()
  840. {
  841. if (this.asyncWriteEventArgs.SocketError == SocketError.Success)
  842. {
  843. return;
  844. }
  845. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)this.asyncWriteEventArgs.SocketError));
  846. }
  847. // This method should be called inside ThisLock
  848. void DisposeWriteEventArgs()
  849. {
  850. if (this.asyncWriteEventArgs != null)
  851. {
  852. this.asyncWriteEventArgs.Completed -= onSocketSendCompleted;
  853. this.asyncWriteEventArgs.Dispose();
  854. }
  855. }
  856. void AbortWrite()
  857. {
  858. lock (ThisLock)
  859. {
  860. if (this.asyncWritePending)
  861. {
  862. if (this.closeState != CloseState.Closed)
  863. {
  864. this.SetUserToken(this.asyncWriteEventArgs, null);
  865. this.asyncWritePending = false;
  866. this.CancelSendTimer();
  867. }
  868. else
  869. {
  870. this.DisposeWriteEventArgs();
  871. }
  872. }
  873. }
  874. }
  875. void FinishWrite()
  876. {
  877. WaitCallback asyncWriteCallback = this.asyncWriteCallback;
  878. object asyncWriteState = this.asyncWriteState;
  879. this.asyncWriteState = null;
  880. this.asyncWriteCallback = null;
  881. asyncWriteCallback(asyncWriteState);
  882. }
  883. public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
  884. {
  885. // as per http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b201213
  886. // we shouldn't write more than 64K synchronously to a socket
  887. const int maxSocketWrite = 64 * 1024;
  888. ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
  889. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  890. try
  891. {
  892. if (TD.SocketWriteStartIsEnabled())
  893. {
  894. TraceWriteStart(size, false);
  895. }
  896. SetImmediate(immediate);
  897. int bytesToWrite = size;
  898. while (bytesToWrite > 0)
  899. {
  900. SetWriteTimeout(timeoutHelper.RemainingTime(), true);
  901. size = Math.Min(bytesToWrite, maxSocketWrite);
  902. socket.Send(buffer, offset, size, SocketFlags.None);
  903. bytesToWrite -= size;
  904. offset += size;
  905. timeout = timeoutHelper.RemainingTime();
  906. }
  907. }
  908. catch (SocketException socketException)
  909. {
  910. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  911. ConvertSendException(socketException, timeoutHelper.RemainingTime()), ExceptionEventType);
  912. }
  913. catch (ObjectDisposedException objectDisposedException)
  914. {
  915. Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
  916. if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
  917. {
  918. throw;
  919. }
  920. else
  921. {
  922. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
  923. }
  924. }
  925. }
  926. void TraceWriteStart(int size, bool async)
  927. {
  928. if (!async)
  929. {
  930. TD.SocketWriteStart(this.socket.GetHashCode(), size, this.RemoteEndpointAddress);
  931. }
  932. else
  933. {
  934. TD.SocketAsyncWriteStart(this.socket.GetHashCode(), size, this.RemoteEndpointAddress);
  935. }
  936. }
  937. public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager)
  938. {
  939. try
  940. {
  941. Write(buffer, offset, size, immediate, timeout);
  942. }
  943. finally
  944. {
  945. bufferManager.ReturnBuffer(buffer);
  946. }
  947. }
  948. public int Read(byte[] buffer, int offset, int size, TimeSpan timeout)
  949. {
  950. ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
  951. ThrowIfNotOpen();
  952. return ReadCore(buffer, offset, size, timeout, false);
  953. }
  954. int ReadCore(byte[] buffer, int offset, int size, TimeSpan timeout, bool closing)
  955. {
  956. int bytesRead = 0;
  957. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  958. try
  959. {
  960. SetReadTimeout(timeoutHelper.RemainingTime(), true, closing);
  961. bytesRead = socket.Receive(buffer, offset, size, SocketFlags.None);
  962. if (TD.SocketReadStopIsEnabled())
  963. {
  964. TraceSocketReadStop(bytesRead, false);
  965. }
  966. }
  967. catch (SocketException socketException)
  968. {
  969. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  970. ConvertReceiveException(socketException, timeoutHelper.RemainingTime()), ExceptionEventType);
  971. }
  972. catch (ObjectDisposedException objectDisposedException)
  973. {
  974. Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
  975. if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
  976. {
  977. throw;
  978. }
  979. else
  980. {
  981. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
  982. }
  983. }
  984. return bytesRead;
  985. }
  986. private void TraceSocketReadStop(int bytesRead, bool async)
  987. {
  988. if (!async)
  989. {
  990. TD.SocketReadStop((this.socket != null) ? this.socket.GetHashCode() : -1, bytesRead, this.RemoteEndpointAddress);
  991. }
  992. else
  993. {
  994. TD.SocketAsyncReadStop((this.socket != null) ? this.socket.GetHashCode() : -1, bytesRead, this.RemoteEndpointAddress);
  995. }
  996. }
  997. public virtual AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout,
  998. WaitCallback callback, object state)
  999. {
  1000. ConnectionUtilities.ValidateBufferBounds(AsyncReadBufferSize, offset, size);
  1001. this.ThrowIfNotOpen();
  1002. return this.BeginReadCore(offset, size, timeout, callback, state);
  1003. }
  1004. AsyncCompletionResult BeginReadCore(int offset, int size, TimeSpan timeout,
  1005. WaitCallback callback, object state)
  1006. {
  1007. bool abortRead = true;
  1008. lock (ThisLock)
  1009. {
  1010. this.ThrowIfClosed();
  1011. this.EnsureReadEventArgs();
  1012. this.asyncReadState = state;
  1013. this.asyncReadCallback = callback;
  1014. this.SetUserToken(this.asyncReadEventArgs, this);
  1015. this.asyncReadPending = true;
  1016. this.SetReadTimeout(timeout, false, false);
  1017. }
  1018. try
  1019. {
  1020. if (socket.UseOnlyOverlappedIO)
  1021. {
  1022. // ReceiveAsync does not respect UseOnlyOverlappedIO but BeginReceive does.
  1023. IAsyncResult result = socket.BeginReceive(AsyncReadBuffer, offset, size, SocketFlags.None, onReceiveCompleted, this);
  1024. if (!result.CompletedSynchronously)
  1025. {
  1026. abortRead = false;
  1027. return AsyncCompletionResult.Queued;
  1028. }
  1029. asyncReadSize = socket.EndReceive(result);
  1030. }
  1031. else
  1032. {
  1033. if (offset != this.asyncReadEventArgs.Offset ||
  1034. size != this.asyncReadEventArgs.Count)
  1035. {
  1036. this.asyncReadEventArgs.SetBuffer(offset, size);
  1037. }
  1038. if (this.ReceiveAsync())
  1039. {
  1040. abortRead = false;
  1041. return AsyncCompletionResult.Queued;
  1042. }
  1043. this.HandleReceiveAsyncCompleted();
  1044. this.asyncReadSize = this.asyncReadEventArgs.BytesTransferred;
  1045. }
  1046. if (TD.SocketReadStopIsEnabled())
  1047. {
  1048. TraceSocketReadStop(asyncReadSize, true);
  1049. }
  1050. abortRead = false;
  1051. return AsyncCompletionResult.Completed;
  1052. }
  1053. catch (SocketException socketException)
  1054. {
  1055. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertReceiveException(socketException, TimeSpan.MaxValue), ExceptionEventType);
  1056. }
  1057. catch (ObjectDisposedException objectDisposedException)
  1058. {
  1059. Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
  1060. if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
  1061. {
  1062. throw;
  1063. }
  1064. else
  1065. {
  1066. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
  1067. }
  1068. }
  1069. finally
  1070. {
  1071. if (abortRead)
  1072. {
  1073. AbortRead();
  1074. }
  1075. }
  1076. }
  1077. [Fx.Tag.SecurityNote(Critical = "Uses a SecurityCritical method to suppress ExecutionContext flow when running in fullTrust.",
  1078. Safe = "Safe because we're only suppressing the ExecutionContext if we're already in full trust.")]
  1079. [SecuritySafeCritical]
  1080. bool ReceiveAsync()
  1081. {
  1082. if (!PartialTrustHelpers.ShouldFlowSecurityContext)
  1083. {
  1084. if (!ExecutionContext.IsFlowSuppressed())
  1085. {
  1086. return ReceiveAsyncNoFlow();
  1087. }
  1088. }
  1089. return this.socket.ReceiveAsync(this.asyncReadEventArgs);
  1090. }
  1091. [Fx.Tag.SecurityNote(Critical = "Suppresses execution context flow and restores it after invocation. Fulltrust async callbacks " +
  1092. "will not have an ExecutionContext, LogicalCallcontext or SecurityContext and should not take dependency on them.")]
  1093. [SecurityCritical]
  1094. bool ReceiveAsyncNoFlow()
  1095. {
  1096. using (ExecutionContext.SuppressFlow())
  1097. {
  1098. return this.socket.ReceiveAsync(this.asyncReadEventArgs);
  1099. }
  1100. }
  1101. void OnReceive(IAsyncResult result)
  1102. {
  1103. this.CancelReceiveTimer();
  1104. if (result.CompletedSynchronously)
  1105. {
  1106. return;
  1107. }
  1108. try
  1109. {
  1110. this.asyncReadSize = socket.EndReceive(result);
  1111. if (TD.SocketReadStopIsEnabled())
  1112. {
  1113. TraceSocketReadStop(this.asyncReadSize, true);
  1114. }
  1115. }
  1116. catch (SocketException socketException)
  1117. {
  1118. this.asyncReadException = ConvertReceiveException(socketException, TimeSpan.MaxValue);
  1119. }
  1120. catch (ObjectDisposedException objectDisposedException)
  1121. {
  1122. this.asyncReadException = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
  1123. }
  1124. #pragma warning suppress 56500 // [....], transferring exception to caller
  1125. catch (Exception exception)
  1126. {
  1127. if (Fx.IsFatal(exception))
  1128. {
  1129. throw;
  1130. }
  1131. this.asyncReadException = exception;
  1132. }
  1133. this.FinishRead();
  1134. }
  1135. void OnReceiveAsync(object sender, SocketAsyncEventArgs eventArgs)
  1136. {
  1137. Fx.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL.");
  1138. this.CancelReceiveTimer();
  1139. try
  1140. {
  1141. this.HandleReceiveAsyncCompleted();
  1142. this.asyncReadSize = eventArgs.BytesTransferred;
  1143. if (TD.SocketReadStopIsEnabled())
  1144. {
  1145. TraceSocketReadStop(asyncReadSize, true);
  1146. }
  1147. }
  1148. catch (SocketException socketException)
  1149. {
  1150. asyncReadException = ConvertReceiveException(socketException, TimeSpan.MaxValue);
  1151. }
  1152. #pragma warning suppress 56500 // [....], transferring exception to caller
  1153. catch (Exception exception)
  1154. {
  1155. if (Fx.IsFatal(exception))
  1156. {
  1157. throw;
  1158. }
  1159. asyncReadException = exception;
  1160. }
  1161. FinishRead();
  1162. }
  1163. void HandleReceiveAsyncCompleted()
  1164. {
  1165. if (this.asyncReadEventArgs.SocketError == SocketError.Success)
  1166. {
  1167. return;
  1168. }
  1169. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)this.asyncReadEventArgs.SocketError));
  1170. }
  1171. void FinishRead()
  1172. {
  1173. WaitCallback asyncReadCallback = this.asyncReadCallback;
  1174. object asyncReadState = this.asyncReadState;
  1175. this.asyncReadState = null;
  1176. this.asyncReadCallback = null;
  1177. asyncReadCallback(asyncReadState);
  1178. }
  1179. // Both BeginRead/ReadAsync paths completed themselves. EndRead's only job is to deliver the result.
  1180. public int EndRead()
  1181. {
  1182. if (this.asyncReadException != null)
  1183. {
  1184. AbortRead();
  1185. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(this.asyncReadException, ExceptionEventType);
  1186. }
  1187. lock (ThisLock)
  1188. {
  1189. if (!this.asyncReadPending)
  1190. {
  1191. throw Fx.AssertAndThrow("SocketConnection.EndRead called with no read pending.");
  1192. }
  1193. this.SetUserToken(this.asyncReadEventArgs, null);
  1194. this.asyncReadPending = false;
  1195. if (closeState == CloseState.Closed)
  1196. {
  1197. this.DisposeReadEventArgs();
  1198. }
  1199. }
  1200. return this.asyncReadSize;
  1201. }
  1202. // This method should be called inside ThisLock
  1203. void DisposeReadEventArgs()
  1204. {
  1205. if (this.asyncReadEventArgs != null)
  1206. {
  1207. this.asyncReadEventArgs.Completed -= onReceiveAsyncCompleted;
  1208. this.asyncReadEventArgs.Dispose();
  1209. }
  1210. // We release the buffer only if there is no outstanding I/O
  1211. this.TryReturnReadBuffer();
  1212. }
  1213. void TryReturnReadBuffer()
  1214. {
  1215. // The buffer must not be returned and nulled when an abort occurs. Since the buffer
  1216. // is also accessed by higher layers, code that has not yet realized the stack is
  1217. // aborted may be attempting to read from the buffer.
  1218. if (this.readBuffer != null && !this.aborted)
  1219. {
  1220. this.connectionBufferPool.Return(this.readBuffer);
  1221. this.readBuffer = null;
  1222. }
  1223. }
  1224. void SetUserToken(SocketAsyncEventArgs args, object userToken)
  1225. {
  1226. // The socket args can be pinned by the overlapped callback. Ensure SocketConnection is
  1227. // only pinned when there is outstanding IO.
  1228. if (args != null)
  1229. {
  1230. args.UserToken = userToken;
  1231. }
  1232. }
  1233. void SetImmediate(bool immediate)
  1234. {
  1235. if (immediate != this.noDelay)
  1236. {
  1237. lock (ThisLock)
  1238. {
  1239. ThrowIfNotOpen();
  1240. socket.NoDelay = immediate;
  1241. }
  1242. this.noDelay = immediate;
  1243. }
  1244. }
  1245. void SetReadTimeout(TimeSpan timeout, bool synchronous, bool closing)
  1246. {
  1247. if (synchronous)
  1248. {
  1249. CancelReceiveTimer();
  1250. // 0 == infinite for winsock timeouts, so we should preempt and throw
  1251. if (timeout <= TimeSpan.Zero)
  1252. {
  1253. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  1254. new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout)), ExceptionEventType);
  1255. }
  1256. if (UpdateTimeout(this.receiveTimeout, timeout))
  1257. {
  1258. lock (ThisLock)
  1259. {
  1260. if (!closing || this.closeState != CloseState.Closing)
  1261. {
  1262. ThrowIfNotOpen();
  1263. }
  1264. this.socket.ReceiveTimeout = TimeoutHelper.ToMilliseconds(timeout);
  1265. }
  1266. this.receiveTimeout = timeout;
  1267. }
  1268. }
  1269. else
  1270. {
  1271. this.receiveTimeout = timeout;
  1272. if (timeout == TimeSpan.MaxValue)
  1273. {
  1274. CancelReceiveTimer();
  1275. }
  1276. else
  1277. {
  1278. ReceiveTimer.Set(timeout);
  1279. }
  1280. }
  1281. }
  1282. void SetWriteTimeout(TimeSpan timeout, bool synchronous)
  1283. {
  1284. if (synchronous)
  1285. {
  1286. CancelSendTimer();
  1287. // 0 == infinite for winsock timeouts, so we should preempt and throw
  1288. if (timeout <= TimeSpan.Zero)
  1289. {
  1290. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  1291. new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout)), ExceptionEventType);
  1292. }
  1293. if (UpdateTimeout(this.sendTimeout, timeout))
  1294. {
  1295. lock (ThisLock)
  1296. {
  1297. ThrowIfNotOpen();
  1298. this.socket.SendTimeout = TimeoutHelper.ToMilliseconds(timeout);
  1299. }
  1300. this.sendTimeout = timeout;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. this.sendTimeout = timeout;
  1306. if (timeout == TimeSpan.MaxValue)
  1307. {
  1308. CancelSendTimer();
  1309. }
  1310. else
  1311. {
  1312. SendTimer.Set(timeout);
  1313. }
  1314. }
  1315. }
  1316. bool UpdateTimeout(TimeSpan oldTimeout, TimeSpan newTimeout)
  1317. {
  1318. if (oldTimeout == newTimeout)
  1319. {
  1320. return false;
  1321. }
  1322. long threshold = oldTimeout.Ticks / 10;
  1323. long delta = Math.Max(oldTimeout.Ticks, newTimeout.Ticks) - Math.Min(oldTimeout.Ticks, newTimeout.Ticks);
  1324. return delta > threshold;
  1325. }
  1326. // This method should be called inside ThisLock
  1327. void EnsureReadEventArgs()
  1328. {
  1329. if (this.asyncReadEventArgs == null)
  1330. {
  1331. // Init ReadAsync state
  1332. if (onReceiveAsyncCompleted == null)
  1333. {
  1334. onReceiveAsyncCompleted = new EventHandler<SocketAsyncEventArgs>(OnReceiveAsyncCompleted);
  1335. }
  1336. this.asyncReadEventArgs = new SocketAsyncEventArgs();
  1337. this.asyncReadEventArgs.SetBuffer(this.readBuffer, 0, this.readBuffer.Length);
  1338. this.asyncReadEventArgs.Completed += onReceiveAsyncCompleted;
  1339. }
  1340. }
  1341. // This method should be called inside ThisLock
  1342. void EnsureWriteEventArgs()
  1343. {
  1344. if (this.asyncWriteEventArgs == null)
  1345. {
  1346. // Init SendAsync state
  1347. if (onSocketSendCompleted == null)
  1348. {
  1349. onSocketSendCompleted = new EventHandler<SocketAsyncEventArgs>(OnSendAsyncCompleted);
  1350. }
  1351. this.asyncWriteEventArgs = new SocketAsyncEventArgs();
  1352. this.asyncWriteEventArgs.Completed += onSocketSendCompleted;
  1353. }
  1354. }
  1355. enum CloseState
  1356. {
  1357. Open,
  1358. Closing,
  1359. Closed,
  1360. }
  1361. enum TransferOperation
  1362. {
  1363. Write,
  1364. Read,
  1365. Undefined,
  1366. }
  1367. }
  1368. class SocketConnectionInitiator : IConnectionInitiator
  1369. {
  1370. int bufferSize;
  1371. ConnectionBufferPool connectionBufferPool;
  1372. public SocketConnectionInitiator(int bufferSize)
  1373. {
  1374. this.bufferSize = bufferSize;
  1375. this.connectionBufferPool = new ConnectionBufferPool(bufferSize);
  1376. }
  1377. IConnection CreateConnection(Socket socket)
  1378. {
  1379. return new SocketConnection(socket, this.connectionBufferPool, false);
  1380. }
  1381. public static Exception ConvertConnectException(SocketException socketException, Uri remoteUri, TimeSpan timeSpent, Exception innerException)
  1382. {
  1383. if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
  1384. {
  1385. return new CommunicationObjectAbortedException(socketException.Message, socketException);
  1386. }
  1387. if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRNOTAVAIL ||
  1388. socketException.ErrorCode == UnsafeNativeMethods.WSAECONNREFUSED ||
  1389. socketException.ErrorCode == UnsafeNativeMethods.WSAENETDOWN ||
  1390. socketException.ErrorCode == UnsafeNativeMethods.WSAENETUNREACH ||
  1391. socketException.ErrorCode == UnsafeNativeMethods.WSAEHOSTDOWN ||
  1392. socketException.ErrorCode == UnsafeNativeMethods.WSAEHOSTUNREACH ||
  1393. socketException.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
  1394. {
  1395. if (timeSpent == TimeSpan.MaxValue)
  1396. {
  1397. return new EndpointNotFoundException(SR.GetString(SR.TcpConnectError, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message), innerException);
  1398. }
  1399. else
  1400. {
  1401. return new EndpointNotFoundException(SR.GetString(SR.TcpConnectErrorWithTimeSpan, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message, timeSpent), innerException);
  1402. }
  1403. }
  1404. else if (socketException.ErrorCode == UnsafeNativeMethods.WSAENOBUFS)
  1405. {
  1406. return new InsufficientMemoryException(SR.GetString(SR.TcpConnectNoBufs), innerException);
  1407. }
  1408. else if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY ||
  1409. socketException.ErrorCode == UnsafeNativeMethods.ERROR_NO_SYSTEM_RESOURCES ||
  1410. socketException.ErrorCode == UnsafeNativeMethods.ERROR_OUTOFMEMORY)
  1411. {
  1412. return new InsufficientMemoryException(SR.GetString(SR.InsufficentMemory), socketException);
  1413. }
  1414. else
  1415. {
  1416. if (timeSpent == TimeSpan.MaxValue)
  1417. {
  1418. return new CommunicationException(SR.GetString(SR.TcpConnectError, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message), innerException);
  1419. }
  1420. else
  1421. {
  1422. return new CommunicationException(SR.GetString(SR.TcpConnectErrorWithTimeSpan, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message, timeSpent), innerException);
  1423. }
  1424. }
  1425. }
  1426. static IPAddress[] GetIPAddresses(Uri uri)
  1427. {
  1428. if (uri.HostNameType == UriHostNameType.IPv4 ||
  1429. uri.HostNameType == UriHostNameType.IPv6)
  1430. {
  1431. IPAddress ipAddress = IPAddress.Parse(uri.DnsSafeHost);
  1432. return new IPAddress[] { ipAddress };
  1433. }
  1434. IPHostEntry hostEntry = null;
  1435. try
  1436. {
  1437. hostEntry = DnsCache.Resolve(uri);
  1438. }
  1439. catch (SocketException socketException)
  1440. {
  1441. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1442. new EndpointNotFoundException(SR.GetString(SR.UnableToResolveHost, uri.Host), socketException));
  1443. }
  1444. if (hostEntry.AddressList.Length == 0)
  1445. {
  1446. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1447. new EndpointNotFoundException(SR.GetString(SR.UnableToResolveHost, uri.Host)));
  1448. }
  1449. return hostEntry.AddressList;
  1450. }
  1451. static TimeoutException CreateTimeoutException(Uri uri, TimeSpan timeout, IPAddress[] addresses, int invalidAddressCount,
  1452. SocketException innerException)
  1453. {
  1454. StringBuilder addressStringBuilder = new StringBuilder();
  1455. for (int i = 0; i < invalidAddressCount; i++)
  1456. {
  1457. if (addresses[i] == null)
  1458. {
  1459. continue;
  1460. }
  1461. if (addressStringBuilder.Length > 0)
  1462. {
  1463. addressStringBuilder.Append(", ");
  1464. }
  1465. addressStringBuilder.Append(addresses[i].ToString());
  1466. }
  1467. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(
  1468. SR.GetString(SR.TcpConnectingToViaTimedOut, uri.AbsoluteUri, timeout.ToString(),
  1469. invalidAddressCount, addresses.Length, addressStringBuilder.ToString()), innerException));
  1470. }
  1471. public IConnection Connect(Uri uri, TimeSpan timeout)
  1472. {
  1473. if (DiagnosticUtility.ShouldTraceInformation)
  1474. {
  1475. TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.InitiatingTcpConnection,
  1476. SR.GetString(SR.TraceCodeInitiatingTcpConnection),
  1477. new StringTraceRecord("Uri", uri.ToString()), this, null);
  1478. }
  1479. int port = uri.Port;
  1480. IPAddress[] addresses = SocketConnectionInitiator.GetIPAddresses(uri);
  1481. Socket socket = null;
  1482. SocketException lastException = null;
  1483. if (port == -1)
  1484. {
  1485. port = TcpUri.DefaultPort;
  1486. }
  1487. int invalidAddressCount = 0;
  1488. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  1489. for (int i = 0; i < addresses.Length; i++)
  1490. {
  1491. if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
  1492. {
  1493. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1494. CreateTimeoutException(uri, timeoutHelper.OriginalTimeout, addresses, invalidAddressCount, lastException));
  1495. }
  1496. AddressFamily addressFamily = addresses[i].AddressFamily;
  1497. if (addressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6)
  1498. {
  1499. addresses[i] = null; // disregard for exception attempt purposes
  1500. continue;
  1501. }
  1502. DateTime connectStartTime = DateTime.UtcNow;
  1503. try
  1504. {
  1505. socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
  1506. socket.Connect(new IPEndPoint(addresses[i], port));
  1507. lastException = null;
  1508. break;
  1509. }
  1510. catch (SocketException socketException)
  1511. {
  1512. invalidAddressCount++;
  1513. SocketConnectionInitiator.TraceConnectFailure(socket, socketException, uri, DateTime.UtcNow - connectStartTime);
  1514. lastException = socketException;
  1515. socket.Close();
  1516. }
  1517. }
  1518. if (socket == null)
  1519. {
  1520. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1521. new EndpointNotFoundException(SR.GetString(SR.NoIPEndpointsFoundForHost, uri.Host)));
  1522. }
  1523. if (lastException != null)
  1524. {
  1525. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1526. SocketConnectionInitiator.ConvertConnectException(lastException, uri,
  1527. timeoutHelper.ElapsedTime(), lastException));
  1528. }
  1529. return CreateConnection(socket);
  1530. }
  1531. public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
  1532. {
  1533. if (DiagnosticUtility.ShouldTraceInformation)
  1534. {
  1535. TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.InitiatingTcpConnection,
  1536. SR.GetString(SR.TraceCodeInitiatingTcpConnection),
  1537. new StringTraceRecord("Uri", uri.ToString()), this, null);
  1538. }
  1539. return new ConnectAsyncResult(uri, timeout, callback, state);
  1540. }
  1541. public IConnection EndConnect(IAsyncResult result)
  1542. {
  1543. Socket socket = ConnectAsyncResult.End(result);
  1544. return CreateConnection(socket);
  1545. }
  1546. public static void TraceConnectFailure(Socket socket, SocketException socketException, Uri remoteUri,
  1547. TimeSpan timeSpentInConnect)
  1548. {
  1549. if (DiagnosticUtility.ShouldTraceWarning)
  1550. {
  1551. Exception traceException = ConvertConnectException(socketException, remoteUri, timeSpentInConnect, socketException);
  1552. TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.TcpConnectError,
  1553. SR.GetString(SR.TraceCodeTcpConnectError), socket, traceException);
  1554. }
  1555. }
  1556. class ConnectAsyncResult : AsyncResult
  1557. {
  1558. IPAddress[] addresses;
  1559. int currentIndex;
  1560. int port;
  1561. SocketException lastException;
  1562. TimeSpan timeout;
  1563. TimeoutHelper timeoutHelper;
  1564. int invalidAddressCount;
  1565. DateTime connectStartTime;
  1566. Socket socket;
  1567. Uri uri;
  1568. static Action<object> startConnectCallback;
  1569. static AsyncCallback onConnect = Fx.ThunkCallback(new AsyncCallback(OnConnect));
  1570. public ConnectAsyncResult(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
  1571. : base(callback, state)
  1572. {
  1573. this.uri = uri;
  1574. addresses = SocketConnectionInitiator.GetIPAddresses(uri);
  1575. port = uri.Port;
  1576. if (port == -1)
  1577. {
  1578. port = TcpUri.DefaultPort;
  1579. }
  1580. currentIndex = 0;
  1581. this.timeout = timeout;
  1582. this.timeoutHelper = new TimeoutHelper(timeout);
  1583. if (Thread.CurrentThread.IsThreadPoolThread)
  1584. {
  1585. if (StartConnect())
  1586. {
  1587. base.Complete(true);
  1588. }
  1589. }
  1590. else
  1591. {
  1592. // If we're not on a threadpool thread, then we need to post a callback to start our accepting loop
  1593. // Otherwise if the calling thread aborts then the async I/O will get inadvertantly cancelled
  1594. if (startConnectCallback == null)
  1595. {
  1596. startConnectCallback = StartConnectCallback;
  1597. }
  1598. ActionItem.Schedule(startConnectCallback, this);
  1599. }
  1600. }
  1601. static void StartConnectCallback(object state)
  1602. {
  1603. ConnectAsyncResult connectAsyncResult = (ConnectAsyncResult)state;
  1604. bool completeSelf = false;
  1605. Exception completionException = null;
  1606. try
  1607. {
  1608. completeSelf = connectAsyncResult.StartConnect();
  1609. }
  1610. #pragma warning suppress 56500 // covered by FxCOP
  1611. catch (Exception e)
  1612. {
  1613. if (Fx.IsFatal(e))
  1614. {
  1615. throw;
  1616. }
  1617. completeSelf = true;
  1618. completionException = e;
  1619. }
  1620. if (completeSelf)
  1621. {
  1622. connectAsyncResult.Complete(false, completionException);
  1623. }
  1624. }
  1625. bool StartConnect()
  1626. {
  1627. while (currentIndex < addresses.Length)
  1628. {
  1629. if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
  1630. {
  1631. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1632. CreateTimeoutException(uri, timeoutHelper.OriginalTimeout, addresses, invalidAddressCount, lastException));
  1633. }
  1634. AddressFamily addressFamily = addresses[currentIndex].AddressFamily;
  1635. if (addressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6)
  1636. {
  1637. addresses[currentIndex++] = null; // disregard for exception attempt purposes
  1638. continue;
  1639. }
  1640. this.connectStartTime = DateTime.UtcNow;
  1641. try
  1642. {
  1643. IPEndPoint ipEndPoint = new IPEndPoint(addresses[currentIndex], port);
  1644. this.socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
  1645. IAsyncResult result = socket.BeginConnect(ipEndPoint, onConnect, this);
  1646. if (!result.CompletedSynchronously)
  1647. {
  1648. return false;
  1649. }
  1650. socket.EndConnect(result);
  1651. return true;
  1652. }
  1653. catch (SocketException socketException)
  1654. {
  1655. invalidAddressCount++;
  1656. this.TraceConnectFailure(socketException);
  1657. lastException = socketException;
  1658. currentIndex++;
  1659. }
  1660. }
  1661. if (socket == null)
  1662. {
  1663. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1664. new EndpointNotFoundException(SR.GetString(SR.NoIPEndpointsFoundForHost, uri.Host)));
  1665. }
  1666. Fx.Assert(lastException != null, "StartConnect: Can't get here without an exception.");
  1667. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1668. SocketConnectionInitiator.ConvertConnectException(lastException, uri,
  1669. timeoutHelper.ElapsedTime(), lastException));
  1670. }
  1671. void TraceConnectFailure(SocketException exception)
  1672. {
  1673. SocketConnectionInitiator.TraceConnectFailure(this.socket, exception, uri, DateTime.UtcNow - connectStartTime);
  1674. this.socket.Close();
  1675. }
  1676. static void OnConnect(IAsyncResult result)
  1677. {
  1678. if (result.CompletedSynchronously)
  1679. {
  1680. return;
  1681. }
  1682. bool completeSelf = false;
  1683. Exception completionException = null;
  1684. ConnectAsyncResult thisPtr = (ConnectAsyncResult)result.AsyncState;
  1685. try
  1686. {
  1687. thisPtr.socket.EndConnect(result);
  1688. completeSelf = true;
  1689. }
  1690. catch (SocketException socketException)
  1691. {
  1692. thisPtr.TraceConnectFailure(socketException);
  1693. thisPtr.lastException = socketException;
  1694. thisPtr.currentIndex++;
  1695. try
  1696. {
  1697. completeSelf = thisPtr.StartConnect();
  1698. }
  1699. #pragma warning suppress 56500 // [....], transferring exception to another thread
  1700. catch (Exception e)
  1701. {
  1702. if (Fx.IsFatal(e))
  1703. {
  1704. throw;
  1705. }
  1706. completeSelf = true;
  1707. completionException = e;
  1708. }
  1709. }
  1710. if (completeSelf)
  1711. {
  1712. thisPtr.Complete(false, completionException);
  1713. }
  1714. }
  1715. public static Socket End(IAsyncResult result)
  1716. {
  1717. ConnectAsyncResult thisPtr = AsyncResult.End<ConnectAsyncResult>(result);
  1718. return thisPtr.socket;
  1719. }
  1720. }
  1721. }
  1722. internal interface ISocketListenerSettings
  1723. {
  1724. int BufferSize { get; }
  1725. bool TeredoEnabled { get; }
  1726. int ListenBacklog { get; }
  1727. }
  1728. class SocketConnectionListener : IConnectionListener
  1729. {
  1730. IPEndPoint localEndpoint;
  1731. bool isDisposed;
  1732. bool isListening;
  1733. Socket listenSocket;
  1734. ISocketListenerSettings settings;
  1735. bool useOnlyOverlappedIO;
  1736. ConnectionBufferPool connectionBufferPool;
  1737. SocketAsyncEventArgsPool socketAsyncEventArgsPool;
  1738. public SocketConnectionListener(Socket listenSocket, ISocketListenerSettings settings, bool useOnlyOverlappedIO)
  1739. : this(settings, useOnlyOverlappedIO)
  1740. {
  1741. this.listenSocket = listenSocket;
  1742. }
  1743. public SocketConnectionListener(IPEndPoint localEndpoint, ISocketListenerSettings settings, bool useOnlyOverlappedIO)
  1744. : this(settings, useOnlyOverlappedIO)
  1745. {
  1746. this.localEndpoint = localEndpoint;
  1747. }
  1748. SocketConnectionListener(ISocketListenerSettings settings, bool useOnlyOverlappedIO)
  1749. {
  1750. Fx.Assert(settings != null, "Input settings should not be null");
  1751. this.settings = settings;
  1752. this.useOnlyOverlappedIO = useOnlyOverlappedIO;
  1753. this.connectionBufferPool = new ConnectionBufferPool(settings.BufferSize);
  1754. }
  1755. object ThisLock
  1756. {
  1757. get { return this; }
  1758. }
  1759. public IAsyncResult BeginAccept(AsyncCallback callback, object state)
  1760. {
  1761. return new AcceptAsyncResult(this, callback, state);
  1762. }
  1763. SocketAsyncEventArgs TakeSocketAsyncEventArgs()
  1764. {
  1765. return this.socketAsyncEventArgsPool.Take();
  1766. }
  1767. void ReturnSocketAsyncEventArgs(SocketAsyncEventArgs socketAsyncEventArgs)
  1768. {
  1769. Fx.Assert(socketAsyncEventArgsPool != null, "The socketAsyncEventArgsPool should not be null");
  1770. this.socketAsyncEventArgsPool.Return(socketAsyncEventArgs);
  1771. }
  1772. // This is the buffer size that is used by the System.Net for accepting new connections
  1773. static int GetAcceptBufferSize(Socket listenSocket)
  1774. {
  1775. return (listenSocket.LocalEndPoint.Serialize().Size + 16) * 2;
  1776. }
  1777. bool InternalBeginAccept(Func<Socket, bool> acceptAsyncFunc)
  1778. {
  1779. lock (ThisLock)
  1780. {
  1781. if (isDisposed)
  1782. {
  1783. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(this.GetType().ToString(), SR.GetString(SR.SocketListenerDisposed)));
  1784. }
  1785. if (!isListening)
  1786. {
  1787. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SocketListenerNotListening)));
  1788. }
  1789. return acceptAsyncFunc(listenSocket);
  1790. }
  1791. }
  1792. public IConnection EndAccept(IAsyncResult result)
  1793. {
  1794. Socket socket = AcceptAsyncResult.End(result);
  1795. if (socket == null)
  1796. return null;
  1797. if (useOnlyOverlappedIO)
  1798. {
  1799. socket.UseOnlyOverlappedIO = true;
  1800. }
  1801. return new SocketConnection(socket, this.connectionBufferPool, false);
  1802. }
  1803. public void Dispose()
  1804. {
  1805. lock (ThisLock)
  1806. {
  1807. if (!isDisposed)
  1808. {
  1809. if (listenSocket != null)
  1810. {
  1811. listenSocket.Close();
  1812. }
  1813. if (this.socketAsyncEventArgsPool != null)
  1814. {
  1815. this.socketAsyncEventArgsPool.Close();
  1816. }
  1817. isDisposed = true;
  1818. }
  1819. }
  1820. }
  1821. public void Listen()
  1822. {
  1823. // If you call listen() on a port, then kill the process, then immediately start a new process and
  1824. // try to listen() on the same port, you sometimes get WSAEADDRINUSE. Even if nothing was accepted.
  1825. // Ports don't immediately free themselves on process shutdown. We call listen() in a loop on a delay
  1826. // for a few iterations for this reason.
  1827. //
  1828. TimeSpan listenTimeout = TimeSpan.FromSeconds(1);
  1829. BackoffTimeoutHelper backoffHelper = new BackoffTimeoutHelper(listenTimeout);
  1830. lock (ThisLock)
  1831. {
  1832. if (this.listenSocket != null)
  1833. {
  1834. this.listenSocket.Listen(settings.ListenBacklog);
  1835. isListening = true;
  1836. }
  1837. while (!isListening)
  1838. {
  1839. try
  1840. {
  1841. this.listenSocket = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  1842. if (localEndpoint.AddressFamily == AddressFamily.InterNetworkV6 && settings.TeredoEnabled)
  1843. {
  1844. this.listenSocket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)23, 10);
  1845. }
  1846. this.listenSocket.Bind(localEndpoint);
  1847. this.listenSocket.Listen(settings.ListenBacklog);
  1848. isListening = true;
  1849. }
  1850. catch (SocketException socketException)
  1851. {
  1852. bool retry = false;
  1853. if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRINUSE)
  1854. {
  1855. if (!backoffHelper.IsExpired())
  1856. {
  1857. backoffHelper.WaitAndBackoff();
  1858. retry = true;
  1859. }
  1860. }
  1861. if (!retry)
  1862. {
  1863. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1864. SocketConnectionListener.ConvertListenException(socketException, this.localEndpoint));
  1865. }
  1866. }
  1867. }
  1868. this.socketAsyncEventArgsPool = new SocketAsyncEventArgsPool(GetAcceptBufferSize(this.listenSocket));
  1869. }
  1870. }
  1871. public static Exception ConvertListenException(SocketException socketException, IPEndPoint localEndpoint)
  1872. {
  1873. if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
  1874. {
  1875. return new CommunicationObjectAbortedException(socketException.Message, socketException);
  1876. }
  1877. if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRINUSE)
  1878. {
  1879. return new AddressAlreadyInUseException(SR.GetString(SR.TcpAddressInUse, localEndpoint.ToString()), socketException);
  1880. }
  1881. else
  1882. {
  1883. return new CommunicationException(
  1884. SR.GetString(SR.TcpListenError, socketException.ErrorCode, socketException.Message, localEndpoint.ToString()),
  1885. socketException);
  1886. }
  1887. }
  1888. class AcceptAsyncResult : AsyncResult
  1889. {
  1890. SocketConnectionListener listener;
  1891. Socket socket;
  1892. SocketAsyncEventArgs socketAsyncEventArgs;
  1893. static Action<object> startAccept;
  1894. EventTraceActivity eventTraceActivity;
  1895. //
  1896. static EventHandler<SocketAsyncEventArgs> acceptAsyncCompleted = new EventHandler<SocketAsyncEventArgs>(AcceptAsyncCompleted);
  1897. static Action<AsyncResult, Exception> onCompleting = new Action<AsyncResult, Exception>(OnInternalCompleting);
  1898. public AcceptAsyncResult(SocketConnectionListener listener, AsyncCallback callback, object state)
  1899. : base(callback, state)
  1900. {
  1901. if (TD.SocketAcceptEnqueuedIsEnabled())
  1902. {
  1903. TD.SocketAcceptEnqueued(this.EventTraceActivity);
  1904. }
  1905. Fx.Assert(listener != null, "listener should not be null");
  1906. this.listener = listener;
  1907. this.socketAsyncEventArgs = listener.TakeSocketAsyncEventArgs();
  1908. this.socketAsyncEventArgs.UserToken = this;
  1909. this.socketAsyncEventArgs.Completed += acceptAsyncCompleted;
  1910. this.OnCompleting = onCompleting;
  1911. // If we're going to start up the thread pool eventually anyway, avoid using RegisterWaitForSingleObject
  1912. if (!Thread.CurrentThread.IsThreadPoolThread)
  1913. {
  1914. if (startAccept == null)
  1915. {
  1916. startAccept = new Action<object>(StartAccept);
  1917. }
  1918. ActionItem.Schedule(startAccept, this);
  1919. }
  1920. else
  1921. {
  1922. bool completeSelf;
  1923. bool success = false;
  1924. try
  1925. {
  1926. completeSelf = StartAccept();
  1927. success = true;
  1928. }
  1929. finally
  1930. {
  1931. if (!success)
  1932. {
  1933. // Return the args when an exception is thrown
  1934. ReturnSocketAsyncEventArgs();
  1935. }
  1936. }
  1937. if (completeSelf)
  1938. {
  1939. base.Complete(true);
  1940. }
  1941. }
  1942. }
  1943. public EventTraceActivity EventTraceActivity
  1944. {
  1945. get
  1946. {
  1947. if (this.eventTraceActivity == null)
  1948. {
  1949. this.eventTraceActivity = new EventTraceActivity();
  1950. }
  1951. return this.eventTraceActivity;
  1952. }
  1953. }
  1954. static void StartAccept(object state)
  1955. {
  1956. AcceptAsyncResult thisPtr = (AcceptAsyncResult)state;
  1957. Exception completionException = null;
  1958. bool completeSelf;
  1959. try
  1960. {
  1961. completeSelf = thisPtr.StartAccept();
  1962. }
  1963. #pragma warning suppress 56500 // [....], transferring exception to another thread
  1964. catch (Exception e)
  1965. {
  1966. if (Fx.IsFatal(e))
  1967. {
  1968. throw;
  1969. }
  1970. completeSelf = true;
  1971. completionException = e;
  1972. }
  1973. if (completeSelf)
  1974. {
  1975. thisPtr.Complete(false, completionException);
  1976. }
  1977. }
  1978. bool StartAccept()
  1979. {
  1980. while (true)
  1981. {
  1982. try
  1983. {
  1984. return listener.InternalBeginAccept(DoAcceptAsync);
  1985. }
  1986. catch (SocketException socketException)
  1987. {
  1988. if (ShouldAcceptRecover(socketException))
  1989. {
  1990. continue;
  1991. }
  1992. else
  1993. {
  1994. throw;
  1995. }
  1996. }
  1997. }
  1998. }
  1999. static bool ShouldAcceptRecover(SocketException exception)
  2000. {
  2001. return (
  2002. (exception.ErrorCode == UnsafeNativeMethods.WSAECONNRESET) ||
  2003. (exception.ErrorCode == UnsafeNativeMethods.WSAEMFILE) ||
  2004. (exception.ErrorCode == UnsafeNativeMethods.WSAENOBUFS) ||
  2005. (exception.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
  2006. );
  2007. }
  2008. // Return true means completed synchronously
  2009. bool DoAcceptAsync(Socket listenSocket)
  2010. {
  2011. SocketAsyncEventArgsPool.CleanupAcceptSocket(this.socketAsyncEventArgs);
  2012. if (listenSocket.AcceptAsync(this.socketAsyncEventArgs))
  2013. {
  2014. // AcceptAsync returns true to indicate that the I/O operation is pending (asynchronous)
  2015. return false;
  2016. }
  2017. Exception exception = HandleAcceptAsyncCompleted();
  2018. if (exception != null)
  2019. {
  2020. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
  2021. }
  2022. return true;
  2023. }
  2024. static void AcceptAsyncCompleted(object sender, SocketAsyncEventArgs e)
  2025. {
  2026. AcceptAsyncResult thisPtr = (AcceptAsyncResult)e.UserToken;
  2027. Fx.Assert(thisPtr.socketAsyncEventArgs == e, "Got wrong socketAsyncEventArgs");
  2028. Exception completionException = thisPtr.HandleAcceptAsyncCompleted();
  2029. if (completionException != null && ShouldAcceptRecover((SocketException)completionException))
  2030. {
  2031. DiagnosticUtility.TraceHandledException(completionException, TraceEventType.Warning);
  2032. StartAccept(thisPtr);
  2033. return;
  2034. }
  2035. thisPtr.Complete(false, completionException);
  2036. }
  2037. static void OnInternalCompleting(AsyncResult result, Exception exception)
  2038. {
  2039. AcceptAsyncResult thisPtr = result as AcceptAsyncResult;
  2040. if (TD.SocketAcceptedIsEnabled())
  2041. {
  2042. int hashCode = thisPtr.socket != null ? thisPtr.socket.GetHashCode() : -1;
  2043. if (hashCode != -1)
  2044. {
  2045. TD.SocketAccepted(
  2046. thisPtr.EventTraceActivity,
  2047. thisPtr.listener != null ? thisPtr.listener.GetHashCode() : -1,
  2048. hashCode);
  2049. }
  2050. else
  2051. {
  2052. TD.SocketAcceptClosed(thisPtr.EventTraceActivity);
  2053. }
  2054. }
  2055. Fx.Assert(result != null, "Wrong async result has been passed in to OnInternalCompleting");
  2056. thisPtr.ReturnSocketAsyncEventArgs();
  2057. }
  2058. void ReturnSocketAsyncEventArgs()
  2059. {
  2060. if (this.socketAsyncEventArgs != null)
  2061. {
  2062. this.socketAsyncEventArgs.UserToken = null;
  2063. this.socketAsyncEventArgs.Completed -= acceptAsyncCompleted;
  2064. this.listener.ReturnSocketAsyncEventArgs(this.socketAsyncEventArgs);
  2065. this.socketAsyncEventArgs = null;
  2066. }
  2067. }
  2068. Exception HandleAcceptAsyncCompleted()
  2069. {
  2070. Exception completionException = null;
  2071. if (this.socketAsyncEventArgs.SocketError == SocketError.Success)
  2072. {
  2073. this.socket = this.socketAsyncEventArgs.AcceptSocket;
  2074. this.socketAsyncEventArgs.AcceptSocket = null;
  2075. }
  2076. else
  2077. {
  2078. completionException = new SocketException((int)this.socketAsyncEventArgs.SocketError);
  2079. }
  2080. return completionException;
  2081. }
  2082. public static Socket End(IAsyncResult result)
  2083. {
  2084. AcceptAsyncResult thisPtr = AsyncResult.End<AcceptAsyncResult>(result);
  2085. return thisPtr.socket;
  2086. }
  2087. }
  2088. }
  2089. }