PageRenderTime 131ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/referencesource/System/net/System/Net/Sockets/Socket.cs

http://github.com/mono/mono
C# | 10332 lines | 6761 code | 1552 blank | 2019 comment | 1643 complexity | f3cf07bc4700d0d7e8094627109d65a8 MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Unlicense, Apache-2.0
  1. //------------------------------------------------------------------------------
  2. // <copyright file="Socket.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. //------------------------------------------------------------------------------
  6. #if MONO
  7. #undef FEATURE_PAL
  8. #endif
  9. namespace System.Net.Sockets {
  10. using System.Collections;
  11. using System.Collections.Generic;
  12. using System.Diagnostics;
  13. using System.Globalization;
  14. using System.IO;
  15. using System.Net;
  16. using System.Net.Configuration;
  17. using System.Runtime.InteropServices;
  18. using System.Security.Permissions;
  19. using System.Threading;
  20. using System.Runtime.Versioning;
  21. using System.Diagnostics.Contracts;
  22. using System.ComponentModel;
  23. /// <devdoc>
  24. /// <para>The <see cref='Sockets.Socket'/> class implements the Berkeley sockets
  25. /// interface.</para>
  26. /// </devdoc>
  27. public partial class Socket : IDisposable
  28. {
  29. #if !MONO
  30. internal const int DefaultCloseTimeout = -1; // don't change for default, otherwise breaking change
  31. // AcceptQueue - queued list of accept requests for BeginAccept or async Result for Begin Connect
  32. private object m_AcceptQueueOrConnectResult;
  33. // the following 8 members represent the state of the socket
  34. private SafeCloseSocket m_Handle;
  35. // m_RightEndPoint is null if the socket has not been bound. Otherwise, it is any EndPoint of the
  36. // correct type (IPEndPoint, etc).
  37. internal EndPoint m_RightEndPoint;
  38. internal EndPoint m_RemoteEndPoint;
  39. // this flags monitor if the socket was ever connected at any time and if it still is.
  40. private bool m_IsConnected; // = false;
  41. private bool m_IsDisconnected; // = false;
  42. // when the socket is created it will be in blocking mode
  43. // we'll only be able to Accept or Connect, so we only need
  44. // to handle one of these cases at a time
  45. private bool willBlock = true; // desired state of the socket for the user
  46. private bool willBlockInternal = true; // actual win32 state of the socket
  47. private bool isListening = false;
  48. // Our internal state doesn't automatically get updated after a non-blocking connect
  49. // completes. Keep track of whether we're doing a non-blocking connect, and make sure
  50. // to poll for the real state until we're done connecting.
  51. private bool m_NonBlockingConnectInProgress;
  52. // Keep track of the kind of endpoint used to do a non-blocking connect, so we can set
  53. // it to m_RightEndPoint when we discover we're connected.
  54. private EndPoint m_NonBlockingConnectRightEndPoint;
  55. // These are constants initialized by constructor
  56. private AddressFamily addressFamily;
  57. private SocketType socketType;
  58. private ProtocolType protocolType;
  59. // These caches are one degree off of Socket since they're not used in the sync case/when disabled in config.
  60. private CacheSet m_Caches;
  61. private class CacheSet
  62. {
  63. internal CallbackClosure ConnectClosureCache;
  64. internal CallbackClosure AcceptClosureCache;
  65. internal CallbackClosure SendClosureCache;
  66. internal CallbackClosure ReceiveClosureCache;
  67. internal OverlappedCache SendOverlappedCache;
  68. internal OverlappedCache ReceiveOverlappedCache;
  69. }
  70. //
  71. // Overlapped constants.
  72. //
  73. #if !(FEATURE_PAL && !MONO) || CORIOLIS
  74. internal static volatile bool UseOverlappedIO;
  75. #else
  76. // Disable the I/O completion port for Rotor
  77. internal static volatile bool UseOverlappedIO = true;
  78. #endif // !(FEATURE_PAL && !MONO) || CORIOLIS
  79. private bool useOverlappedIO;
  80. // Bool marked true if the native socket m_Handle was bound to the ThreadPool
  81. private bool m_BoundToThreadPool; // = false;
  82. // Bool marked true if the native socket option IP_PKTINFO or IPV6_PKTINFO has been set
  83. private bool m_ReceivingPacketInformation;
  84. // Event used for async Connect/Accept calls
  85. private ManualResetEvent m_AsyncEvent;
  86. private RegisteredWaitHandle m_RegisteredWait;
  87. private AsyncEventBits m_BlockEventBits = AsyncEventBits.FdNone;
  88. //These members are to cache permission checks
  89. private SocketAddress m_PermittedRemoteAddress;
  90. private DynamicWinsockMethods m_DynamicWinsockMethods;
  91. #endif // !MONO
  92. private static object s_InternalSyncObject;
  93. #if !MONO
  94. private int m_CloseTimeout = Socket.DefaultCloseTimeout;
  95. private int m_IntCleanedUp; // 0 if not completed >0 otherwise.
  96. private const int microcnv = 1000000;
  97. private readonly static int protocolInformationSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
  98. #endif // !MONO
  99. internal static volatile bool s_SupportsIPv4;
  100. internal static volatile bool s_SupportsIPv6;
  101. internal static volatile bool s_OSSupportsIPv6;
  102. internal static volatile bool s_Initialized;
  103. #if !MONO
  104. private static volatile WaitOrTimerCallback s_RegisteredWaitCallback;
  105. #endif
  106. private static volatile bool s_LoggingEnabled;
  107. #if !FEATURE_PAL // perfcounter
  108. internal static volatile bool s_PerfCountersEnabled;
  109. #endif
  110. //************* constructors *************************
  111. //------------------------------------
  112. // Creates a Dual Mode socket for working with both IPv4 and IPv6
  113. public Socket(SocketType socketType, ProtocolType protocolType)
  114. : this(AddressFamily.InterNetworkV6, socketType, protocolType) {
  115. DualMode = true;
  116. }
  117. /// <devdoc>
  118. /// <para>
  119. /// Initializes a new instance of the <see cref='Sockets.Socket'/> class.
  120. /// </para>
  121. /// </devdoc>
  122. public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) {
  123. #if WASM
  124. throw new PlatformNotSupportedException ();
  125. #else
  126. s_LoggingEnabled = Logging.On;
  127. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
  128. InitializeSockets();
  129. #if MONO
  130. int error;
  131. m_Handle = new SafeSocketHandle (Socket_icall (addressFamily, socketType, protocolType, out error), true);
  132. #else
  133. m_Handle = SafeCloseSocket.CreateWSASocket(
  134. addressFamily,
  135. socketType,
  136. protocolType);
  137. #endif
  138. if (m_Handle.IsInvalid) {
  139. //
  140. // failed to create the win32 socket, throw
  141. //
  142. throw new SocketException();
  143. }
  144. this.addressFamily = addressFamily;
  145. this.socketType = socketType;
  146. this.protocolType = protocolType;
  147. IPProtectionLevel defaultProtectionLevel = SettingsSectionInternal.Section.IPProtectionLevel;
  148. if (defaultProtectionLevel != IPProtectionLevel.Unspecified) {
  149. SetIPProtectionLevel(defaultProtectionLevel);
  150. }
  151. #if MONO
  152. SocketDefaults ();
  153. #endif
  154. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
  155. #endif
  156. }
  157. #if !MONO
  158. public Socket(SocketInformation socketInformation) {
  159. s_LoggingEnabled = Logging.On;
  160. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
  161. ExceptionHelper.UnrestrictedSocketPermission.Demand();
  162. InitializeSockets();
  163. if(socketInformation.ProtocolInformation == null || socketInformation.ProtocolInformation.Length < protocolInformationSize){
  164. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation.ProtocolInformation");
  165. }
  166. unsafe{
  167. fixed(byte * pinnedBuffer = socketInformation.ProtocolInformation){
  168. m_Handle = SafeCloseSocket.CreateWSASocket(pinnedBuffer);
  169. UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO protocolInfo = (UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO)Marshal.PtrToStructure((IntPtr)pinnedBuffer, typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
  170. addressFamily = protocolInfo.iAddressFamily;
  171. socketType = (SocketType)protocolInfo.iSocketType;
  172. protocolType = (ProtocolType)protocolInfo.iProtocol;
  173. }
  174. }
  175. if (m_Handle.IsInvalid) {
  176. SocketException e = new SocketException();
  177. if(e.ErrorCode == (int)SocketError.InvalidArgument){
  178. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation");
  179. }
  180. else {
  181. throw e;
  182. }
  183. }
  184. if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
  185. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  186. }
  187. m_IsConnected = socketInformation.IsConnected;
  188. willBlock = !socketInformation.IsNonBlocking;
  189. InternalSetBlocking(willBlock);
  190. isListening = socketInformation.IsListening;
  191. UseOnlyOverlappedIO = socketInformation.UseOnlyOverlappedIO;
  192. //are we bound? if so, what's the local endpoint?
  193. if (socketInformation.RemoteEndPoint != null) {
  194. m_RightEndPoint = socketInformation.RemoteEndPoint;
  195. m_RemoteEndPoint = socketInformation.RemoteEndPoint;
  196. }
  197. else {
  198. EndPoint ep = null;
  199. if (addressFamily == AddressFamily.InterNetwork ) {
  200. ep = IPEndPoint.Any;
  201. }
  202. else if(addressFamily == AddressFamily.InterNetworkV6) {
  203. ep = IPEndPoint.IPv6Any;
  204. }
  205. SocketAddress socketAddress = ep.Serialize();
  206. SocketError errorCode;
  207. try
  208. {
  209. errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
  210. m_Handle,
  211. socketAddress.m_Buffer,
  212. ref socketAddress.m_Size);
  213. }
  214. catch (ObjectDisposedException)
  215. {
  216. errorCode = SocketError.NotSocket;
  217. }
  218. if (errorCode == SocketError.Success) {
  219. try {
  220. //we're bound
  221. m_RightEndPoint = ep.Create(socketAddress);
  222. }
  223. catch {
  224. }
  225. }
  226. }
  227. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
  228. }
  229. /// <devdoc>
  230. /// <para>
  231. /// Called by the class to create a socket to accept an
  232. /// incoming request.
  233. /// </para>
  234. /// </devdoc>
  235. private Socket(SafeCloseSocket fd) {
  236. s_LoggingEnabled = Logging.On;
  237. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", null);
  238. InitializeSockets();
  239. // ExceptionHelper.UnmanagedPermission.Demand();
  240. //<
  241. //
  242. // this should never happen, let's check anyway
  243. //
  244. if (fd == null || fd.IsInvalid) {
  245. throw new ArgumentException(SR.GetString(SR.net_InvalidSocketHandle));
  246. }
  247. m_Handle = fd;
  248. addressFamily = Sockets.AddressFamily.Unknown;
  249. socketType = Sockets.SocketType.Unknown;
  250. protocolType = Sockets.ProtocolType.Unknown;
  251. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
  252. }
  253. #endif
  254. //************* properties *************************
  255. /// <devdoc>
  256. /// <para>Indicates whether IPv4 support is available and enabled on this machine.</para>
  257. /// </devdoc>
  258. [Obsolete("SupportsIPv4 is obsoleted for this type, please use OSSupportsIPv4 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
  259. public static bool SupportsIPv4 {
  260. get {
  261. InitializeSockets();
  262. return s_SupportsIPv4;
  263. }
  264. }
  265. // Renamed to be consistent with OSSupportsIPv6
  266. public static bool OSSupportsIPv4 {
  267. get {
  268. InitializeSockets();
  269. return s_SupportsIPv4;
  270. }
  271. }
  272. /// <devdoc>
  273. /// <para>Indicates whether IPv6 support is available and enabled on this machine.</para>
  274. /// </devdoc>
  275. [Obsolete("SupportsIPv6 is obsoleted for this type, please use OSSupportsIPv6 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
  276. public static bool SupportsIPv6 {
  277. get {
  278. InitializeSockets();
  279. return s_SupportsIPv6;
  280. }
  281. }
  282. internal static bool LegacySupportsIPv6 {
  283. get {
  284. InitializeSockets();
  285. return s_SupportsIPv6;
  286. }
  287. }
  288. public static bool OSSupportsIPv6 {
  289. get {
  290. InitializeSockets();
  291. return s_OSSupportsIPv6;
  292. }
  293. }
  294. #if !MONO
  295. /// <devdoc>
  296. /// <para>
  297. /// Gets the amount of data pending in the network's input buffer that can be
  298. /// read from the socket.
  299. /// </para>
  300. /// </devdoc>
  301. public int Available {
  302. get {
  303. if (CleanedUp) {
  304. throw new ObjectDisposedException(this.GetType().FullName);
  305. }
  306. int argp = 0;
  307. // This may throw ObjectDisposedException.
  308. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
  309. m_Handle,
  310. IoctlSocketConstants.FIONREAD,
  311. ref argp);
  312. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Available_get() UnsafeNclNativeMethods.OSSOCK.ioctlsocket returns errorCode:" + errorCode);
  313. //
  314. // if the native call fails we'll throw a SocketException
  315. //
  316. if (errorCode==SocketError.SocketError) {
  317. //
  318. // update our internal state after this socket error and throw
  319. //
  320. SocketException socketException = new SocketException();
  321. UpdateStatusAfterSocketError(socketException);
  322. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Available", socketException);
  323. throw socketException;
  324. }
  325. return argp;
  326. }
  327. }
  328. /// <devdoc>
  329. /// <para>
  330. /// Gets the local end point.
  331. /// </para>
  332. /// </devdoc>
  333. public EndPoint LocalEndPoint {
  334. get {
  335. if (CleanedUp) {
  336. throw new ObjectDisposedException(this.GetType().FullName);
  337. }
  338. if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
  339. {
  340. // update the state if we've become connected after a non-blocking connect
  341. m_IsConnected = true;
  342. m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
  343. m_NonBlockingConnectInProgress = false;
  344. }
  345. if (m_RightEndPoint == null) {
  346. return null;
  347. }
  348. SocketAddress socketAddress = m_RightEndPoint.Serialize();
  349. // This may throw ObjectDisposedException.
  350. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
  351. m_Handle,
  352. socketAddress.m_Buffer,
  353. ref socketAddress.m_Size);
  354. if (errorCode!=SocketError.Success) {
  355. //
  356. // update our internal state after this socket error and throw
  357. //
  358. SocketException socketException = new SocketException();
  359. UpdateStatusAfterSocketError(socketException);
  360. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "LocalEndPoint", socketException);
  361. throw socketException;
  362. }
  363. return m_RightEndPoint.Create(socketAddress);
  364. }
  365. }
  366. /// <devdoc>
  367. /// <para>
  368. /// Gets the remote end point
  369. /// </para>
  370. /// </devdoc>
  371. public EndPoint RemoteEndPoint {
  372. get {
  373. if (CleanedUp) {
  374. throw new ObjectDisposedException(this.GetType().FullName);
  375. }
  376. if (m_RemoteEndPoint==null) {
  377. if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
  378. {
  379. // update the state if we've become connected after a non-blocking connect
  380. m_IsConnected = true;
  381. m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
  382. m_NonBlockingConnectInProgress = false;
  383. }
  384. if (m_RightEndPoint==null) {
  385. return null;
  386. }
  387. SocketAddress socketAddress = m_RightEndPoint.Serialize();
  388. // This may throw ObjectDisposedException.
  389. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getpeername(
  390. m_Handle,
  391. socketAddress.m_Buffer,
  392. ref socketAddress.m_Size);
  393. if (errorCode!=SocketError.Success) {
  394. //
  395. // update our internal state after this socket error and throw
  396. //
  397. SocketException socketException = new SocketException();
  398. UpdateStatusAfterSocketError(socketException);
  399. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "RemoteEndPoint", socketException);
  400. throw socketException;
  401. }
  402. try {
  403. m_RemoteEndPoint = m_RightEndPoint.Create(socketAddress);
  404. }
  405. catch {
  406. }
  407. }
  408. return m_RemoteEndPoint;
  409. }
  410. }
  411. #endif // !MONO
  412. /// <devdoc>
  413. /// <para>
  414. /// Gets the operating system m_Handle for the socket.
  415. ///YUKON: should we cut this method off, who are the users?
  416. /// </para>
  417. /// </devdoc>
  418. public IntPtr Handle {
  419. get {
  420. #if !MONO
  421. ExceptionHelper.UnmanagedPermission.Demand();
  422. #endif
  423. return m_Handle.DangerousGetHandle();
  424. }
  425. }
  426. #if !MONO
  427. internal SafeCloseSocket SafeHandle {
  428. get {
  429. return m_Handle;
  430. }
  431. }
  432. // Non-blocking I/O control
  433. /// <devdoc>
  434. /// <para>
  435. /// Gets and sets the blocking mode of a socket.
  436. /// </para>
  437. /// </devdoc>
  438. public bool Blocking {
  439. get {
  440. //
  441. // return the user's desired blocking behaviour (not the actual win32 state)
  442. //
  443. return willBlock;
  444. }
  445. set {
  446. if (CleanedUp) {
  447. throw new ObjectDisposedException(this.GetType().FullName);
  448. }
  449. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::set_Blocking() value:" + value.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
  450. bool current;
  451. SocketError errorCode = InternalSetBlocking(value, out current);
  452. if (errorCode!=SocketError.Success) {
  453. //
  454. // update our internal state after this socket error and throw
  455. SocketException socketException = new SocketException(errorCode);
  456. UpdateStatusAfterSocketError(socketException);
  457. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Blocking", socketException);
  458. throw socketException;
  459. }
  460. //
  461. // win32 call succeeded, update desired state
  462. //
  463. willBlock = current;
  464. }
  465. }
  466. #endif // !MONO
  467. public bool UseOnlyOverlappedIO{
  468. get {
  469. //
  470. // return the user's desired blocking behaviour (not the actual win32 state)
  471. //
  472. return useOverlappedIO;
  473. }
  474. set {
  475. #if !MONO
  476. if (m_BoundToThreadPool) {
  477. throw new InvalidOperationException(SR.GetString(SR.net_io_completionportwasbound));
  478. }
  479. #endif
  480. useOverlappedIO = value;
  481. }
  482. }
  483. #if !MONO
  484. /// <devdoc>
  485. /// <para>
  486. /// Gets the connection state of the Socket. This property will return the latest
  487. /// known state of the Socket. When it returns false, the Socket was either never connected
  488. /// or it is not connected anymore. When it returns true, though, there's no guarantee that the Socket
  489. /// is still connected, but only that it was connected at the time of the last IO operation.
  490. /// </para>
  491. /// </devdoc>
  492. public bool Connected {
  493. get {
  494. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connected() m_IsConnected:"+m_IsConnected);
  495. if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
  496. {
  497. // update the state if we've become connected after a non-blocking connect
  498. m_IsConnected = true;
  499. m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
  500. m_NonBlockingConnectInProgress = false;
  501. }
  502. return m_IsConnected;
  503. }
  504. }
  505. #endif // !MONO
  506. /// <devdoc>
  507. /// <para>
  508. /// Gets the socket's address family.
  509. /// </para>
  510. /// </devdoc>
  511. public AddressFamily AddressFamily {
  512. get {
  513. return addressFamily;
  514. }
  515. }
  516. /// <devdoc>
  517. /// <para>
  518. /// Gets the socket's socketType.
  519. /// </para>
  520. /// </devdoc>
  521. public SocketType SocketType {
  522. get {
  523. return socketType;
  524. }
  525. }
  526. /// <devdoc>
  527. /// <para>
  528. /// Gets the socket's protocol socketType.
  529. /// </para>
  530. /// </devdoc>
  531. public ProtocolType ProtocolType {
  532. get {
  533. return protocolType;
  534. }
  535. }
  536. #if !MONO
  537. public bool IsBound{
  538. get{
  539. return (m_RightEndPoint != null);
  540. }
  541. }
  542. #endif // !MONO
  543. public bool ExclusiveAddressUse{
  544. get {
  545. return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse) != 0 ? true : false;
  546. }
  547. set {
  548. if (IsBound) {
  549. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotbebound));
  550. }
  551. SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
  552. }
  553. }
  554. public int ReceiveBufferSize {
  555. get {
  556. return (int)GetSocketOption(SocketOptionLevel.Socket,
  557. SocketOptionName.ReceiveBuffer);
  558. }
  559. set {
  560. if (value<0) {
  561. throw new ArgumentOutOfRangeException("value");
  562. }
  563. SetSocketOption(SocketOptionLevel.Socket,
  564. SocketOptionName.ReceiveBuffer, value);
  565. }
  566. }
  567. public int SendBufferSize {
  568. get {
  569. return (int)GetSocketOption(SocketOptionLevel.Socket,
  570. SocketOptionName.SendBuffer);
  571. }
  572. set {
  573. if (value<0) {
  574. throw new ArgumentOutOfRangeException("value");
  575. }
  576. SetSocketOption(SocketOptionLevel.Socket,
  577. SocketOptionName.SendBuffer, value);
  578. }
  579. }
  580. public int ReceiveTimeout {
  581. get {
  582. return (int)GetSocketOption(SocketOptionLevel.Socket,
  583. SocketOptionName.ReceiveTimeout);
  584. }
  585. set {
  586. if (value< -1) {
  587. throw new ArgumentOutOfRangeException("value");
  588. }
  589. if (value == -1) {
  590. value = 0;
  591. }
  592. SetSocketOption(SocketOptionLevel.Socket,
  593. SocketOptionName.ReceiveTimeout, value);
  594. }
  595. }
  596. public int SendTimeout {
  597. get {
  598. return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
  599. }
  600. set {
  601. if (value< -1) {
  602. throw new ArgumentOutOfRangeException("value");
  603. }
  604. if (value == -1) {
  605. value = 0;
  606. }
  607. SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
  608. }
  609. }
  610. public LingerOption LingerState {
  611. get {
  612. return (LingerOption)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
  613. }
  614. set {
  615. SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value);
  616. }
  617. }
  618. #if !MONO
  619. public bool NoDelay {
  620. get {
  621. return (int)GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) != 0 ? true : false;
  622. }
  623. set {
  624. SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
  625. }
  626. }
  627. #endif // !MONO
  628. public short Ttl{
  629. get {
  630. if (addressFamily == AddressFamily.InterNetwork) {
  631. return (short)(int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
  632. }
  633. else if (addressFamily == AddressFamily.InterNetworkV6) {
  634. return (short)(int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive);
  635. }
  636. else{
  637. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  638. }
  639. }
  640. set {
  641. // valid values are from 0 to 255 since Ttl is really just a byte value on the wire
  642. if (value < 0 || value > 255) {
  643. throw new ArgumentOutOfRangeException("value");
  644. }
  645. if (addressFamily == AddressFamily.InterNetwork) {
  646. SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
  647. }
  648. else if (addressFamily == AddressFamily.InterNetworkV6) {
  649. SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive, value);
  650. }
  651. else{
  652. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  653. }
  654. }
  655. }
  656. public bool DontFragment{
  657. get {
  658. if (addressFamily == AddressFamily.InterNetwork) {
  659. return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment) != 0 ? true : false;
  660. }
  661. else{
  662. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  663. }
  664. }
  665. set {
  666. if (addressFamily == AddressFamily.InterNetwork) {
  667. SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
  668. }
  669. else{
  670. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  671. }
  672. }
  673. }
  674. #if !MONO
  675. public bool MulticastLoopback{
  676. get {
  677. if (addressFamily == AddressFamily.InterNetwork) {
  678. return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback) != 0 ? true : false;
  679. }
  680. else if (addressFamily == AddressFamily.InterNetworkV6) {
  681. return (int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback) != 0 ? true : false;
  682. }
  683. else{
  684. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  685. }
  686. }
  687. set {
  688. if (addressFamily == AddressFamily.InterNetwork) {
  689. SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
  690. }
  691. else if (addressFamily == AddressFamily.InterNetworkV6) {
  692. SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
  693. }
  694. else{
  695. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  696. }
  697. }
  698. }
  699. public bool EnableBroadcast{
  700. get {
  701. return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast) != 0 ? true : false;
  702. }
  703. set {
  704. SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
  705. }
  706. }
  707. #endif // !MONO
  708. public bool DualMode {
  709. get {
  710. if (AddressFamily != AddressFamily.InterNetworkV6) {
  711. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  712. }
  713. return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
  714. }
  715. set {
  716. if (AddressFamily != AddressFamily.InterNetworkV6) {
  717. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  718. }
  719. SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
  720. }
  721. }
  722. private bool IsDualMode {
  723. get {
  724. return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
  725. }
  726. }
  727. internal bool CanTryAddressFamily(AddressFamily family) {
  728. return (family == addressFamily) || (family == AddressFamily.InterNetwork && IsDualMode);
  729. }
  730. //************* public methods *************************
  731. #if !MONO
  732. /// <devdoc>
  733. /// <para>Associates a socket with an end point.</para>
  734. /// </devdoc>
  735. public void Bind(EndPoint localEP) {
  736. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Bind", localEP);
  737. if (CleanedUp) {
  738. throw new ObjectDisposedException(this.GetType().FullName);
  739. }
  740. //
  741. // parameter validation
  742. //
  743. if (localEP==null) {
  744. throw new ArgumentNullException("localEP");
  745. }
  746. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() localEP:" + localEP.ToString());
  747. EndPoint endPointSnapshot = localEP;
  748. IPEndPoint ipSnapshot = localEP as IPEndPoint;
  749. //
  750. // for now security is implemented only on IPEndPoint
  751. // If EndPoint is of other type - unmanaged code permisison is demanded
  752. //
  753. if (ipSnapshot != null)
  754. {
  755. // Take a snapshot that will make it immutable and not derived.
  756. ipSnapshot = ipSnapshot.Snapshot();
  757. // DualMode: Do the security check on the users IPv4 address, but map to IPv6 before binding.
  758. endPointSnapshot = RemapIPEndPoint(ipSnapshot);
  759. //
  760. // create the permissions the user would need for the call
  761. //
  762. SocketPermission socketPermission
  763. = new SocketPermission(
  764. NetworkAccess.Accept,
  765. Transport,
  766. ipSnapshot.Address.ToString(),
  767. ipSnapshot.Port);
  768. //
  769. // demand for them
  770. //
  771. socketPermission.Demand();
  772. // Here the permission check has succeded.
  773. // NB: if local port is 0, then winsock will assign some>1024,
  774. // so assuming that this is safe. We will not check the
  775. // NetworkAccess.Accept permissions in Receive.
  776. }
  777. else {
  778. //<
  779. ExceptionHelper.UnmanagedPermission.Demand();
  780. }
  781. //
  782. // ask the EndPoint to generate a SocketAddress that we
  783. // can pass down to winsock
  784. //
  785. SocketAddress socketAddress = CallSerializeCheckDnsEndPoint(endPointSnapshot);
  786. DoBind(endPointSnapshot, socketAddress);
  787. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Bind", "");
  788. }
  789. internal void InternalBind(EndPoint localEP)
  790. {
  791. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "InternalBind", localEP);
  792. if (CleanedUp)
  793. {
  794. throw new ObjectDisposedException(GetType().FullName);
  795. }
  796. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalBind() localEP:" + localEP.ToString());
  797. GlobalLog.Assert(!(localEP is DnsEndPoint), "Calling InternalBind with a DnsEndPoint, about to get NotImplementedException");
  798. //
  799. // ask the EndPoint to generate a SocketAddress that we
  800. // can pass down to winsock
  801. //
  802. EndPoint endPointSnapshot = localEP;
  803. SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
  804. DoBind(endPointSnapshot, socketAddress);
  805. if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "InternalBind", "");
  806. }
  807. private void DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
  808. {
  809. // Mitigation for Blue Screen of Death (Win7, maybe others)
  810. IPEndPoint ipEndPoint = endPointSnapshot as IPEndPoint;
  811. if (!OSSupportsIPv4 && ipEndPoint != null && ipEndPoint.Address.IsIPv4MappedToIPv6)
  812. {
  813. SocketException socketException = new SocketException(SocketError.InvalidArgument);
  814. UpdateStatusAfterSocketError(socketException);
  815. if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
  816. throw socketException;
  817. }
  818. // This may throw ObjectDisposedException.
  819. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.bind(
  820. m_Handle,
  821. socketAddress.m_Buffer,
  822. socketAddress.m_Size);
  823. #if TRAVE
  824. try
  825. {
  826. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.bind returns errorCode:" + errorCode);
  827. }
  828. catch (ObjectDisposedException) { }
  829. #endif
  830. //
  831. // if the native call fails we'll throw a SocketException
  832. //
  833. if (errorCode != SocketError.Success)
  834. {
  835. //
  836. // update our internal state after this socket error and throw
  837. //
  838. SocketException socketException = new SocketException();
  839. UpdateStatusAfterSocketError(socketException);
  840. if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
  841. throw socketException;
  842. }
  843. if (m_RightEndPoint == null)
  844. {
  845. //
  846. // save a copy of the EndPoint so we can use it for Create()
  847. //
  848. m_RightEndPoint = endPointSnapshot;
  849. }
  850. }
  851. /// <devdoc>
  852. /// <para>Establishes a connection to a remote system.</para>
  853. /// </devdoc>
  854. public void Connect(EndPoint remoteEP) {
  855. if (CleanedUp) {
  856. throw new ObjectDisposedException(this.GetType().FullName);
  857. }
  858. //
  859. // parameter validation
  860. //
  861. if (remoteEP==null) {
  862. throw new ArgumentNullException("remoteEP");
  863. }
  864. if(m_IsDisconnected){
  865. throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedConnect));
  866. }
  867. if (isListening)
  868. {
  869. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
  870. }
  871. ValidateBlockingMode();
  872. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connect() DST:" + ValidationHelper.ToString(remoteEP));
  873. DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
  874. if (dnsEP != null)
  875. {
  876. if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily))
  877. {
  878. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  879. }
  880. Connect(dnsEP.Host, dnsEP.Port);
  881. return;
  882. }
  883. //This will check the permissions for connect
  884. EndPoint endPointSnapshot = remoteEP;
  885. SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true);
  886. if (!Blocking)
  887. {
  888. m_NonBlockingConnectRightEndPoint = endPointSnapshot;
  889. m_NonBlockingConnectInProgress = true;
  890. }
  891. DoConnect(endPointSnapshot, socketAddress);
  892. }
  893. public void Connect(IPAddress address, int port){
  894. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", address);
  895. if (CleanedUp){
  896. throw new ObjectDisposedException(this.GetType().FullName);
  897. }
  898. //if address family isn't the socket address family throw
  899. if (address==null) {
  900. throw new ArgumentNullException("address");
  901. }
  902. if (!ValidationHelper.ValidateTcpPort(port)) {
  903. throw new ArgumentOutOfRangeException("port");
  904. }
  905. if (!CanTryAddressFamily(address.AddressFamily)) {
  906. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  907. }
  908. IPEndPoint remoteEP = new IPEndPoint(address, port);
  909. Connect(remoteEP);
  910. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
  911. }
  912. public void Connect(string host, int port){
  913. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", host);
  914. if (CleanedUp){
  915. throw new ObjectDisposedException(this.GetType().FullName);
  916. }
  917. if (host==null) {
  918. throw new ArgumentNullException("host");
  919. }
  920. if (!ValidationHelper.ValidateTcpPort(port)){
  921. throw new ArgumentOutOfRangeException("port");
  922. }
  923. if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
  924. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  925. }
  926. IPAddress[] addresses = Dns.GetHostAddresses(host);
  927. Connect(addresses,port);
  928. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
  929. }
  930. #endif // !MONO
  931. public void Connect(IPAddress[] addresses, int port){
  932. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", addresses);
  933. if (CleanedUp){
  934. throw new ObjectDisposedException(this.GetType().FullName);
  935. }
  936. if (addresses==null) {
  937. throw new ArgumentNullException("addresses");
  938. }
  939. if (addresses.Length == 0) {
  940. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_ipaddress_length), "addresses");
  941. }
  942. if (!ValidationHelper.ValidateTcpPort(port)) {
  943. throw new ArgumentOutOfRangeException("port");
  944. }
  945. if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
  946. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  947. }
  948. Exception lastex = null;
  949. foreach ( IPAddress address in addresses ) {
  950. if (CanTryAddressFamily(address.AddressFamily)) {
  951. try
  952. {
  953. Connect(new IPEndPoint(address,port) );
  954. lastex = null;
  955. break;
  956. }
  957. catch ( Exception ex )
  958. {
  959. if (NclUtilities.IsFatal(ex)) throw;
  960. lastex = ex;
  961. }
  962. }
  963. }
  964. if ( lastex != null )
  965. throw lastex;
  966. //if we're not connected, then we didn't get a valid ipaddress in the list
  967. if (!Connected) {
  968. throw new ArgumentException(SR.GetString(SR.net_invalidAddressList), "addresses");
  969. }
  970. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
  971. }
  972. #if !MONO
  973. /// <devdoc>
  974. /// <para>
  975. /// Forces a socket connection to close.
  976. /// </para>
  977. /// </devdoc>
  978. public void Close()
  979. {
  980. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
  981. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Close", null);
  982. ((IDisposable)this).Dispose();
  983. if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "Close", null);
  984. }
  985. public void Close(int timeout)
  986. {
  987. if (timeout < -1)
  988. {
  989. throw new ArgumentOutOfRangeException("timeout");
  990. }
  991. m_CloseTimeout = timeout;
  992. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
  993. ((IDisposable)this).Dispose();
  994. }
  995. /// <devdoc>
  996. /// <para>
  997. /// Places a socket in a listening state.
  998. /// </para>
  999. /// </devdoc>
  1000. public void Listen(int backlog) {
  1001. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Listen", backlog);
  1002. if (CleanedUp) {
  1003. throw new ObjectDisposedException(this.GetType().FullName);
  1004. }
  1005. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() backlog:" + backlog.ToString());
  1006. // No access permissions are necessary here because
  1007. // the verification is done for Bind
  1008. // This may throw ObjectDisposedException.
  1009. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.listen(
  1010. m_Handle,
  1011. backlog);
  1012. #if TRAVE
  1013. try
  1014. {
  1015. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.listen returns errorCode:" + errorCode);
  1016. }
  1017. catch (ObjectDisposedException) { }
  1018. #endif
  1019. //
  1020. // if the native call fails we'll throw a SocketException
  1021. //
  1022. if (errorCode!=SocketError.Success) {
  1023. //
  1024. // update our internal state after this socket error and throw
  1025. //
  1026. SocketException socketException = new SocketException();
  1027. UpdateStatusAfterSocketError(socketException);
  1028. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Listen", socketException);
  1029. throw socketException;
  1030. }
  1031. isListening = true;
  1032. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Listen", "");
  1033. }
  1034. /// <devdoc>
  1035. /// <para>
  1036. /// Creates a new <see cref='Sockets.Socket'/> instance to handle an incoming
  1037. /// connection.
  1038. /// </para>
  1039. /// </devdoc>
  1040. public Socket Accept() {
  1041. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Accept", "");
  1042. //
  1043. // parameter validation
  1044. //
  1045. if (CleanedUp) {
  1046. throw new ObjectDisposedException(this.GetType().FullName);
  1047. }
  1048. if (m_RightEndPoint==null) {
  1049. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  1050. }
  1051. if(!isListening){
  1052. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
  1053. }
  1054. if(m_IsDisconnected){
  1055. throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedAccept));
  1056. }
  1057. ValidateBlockingMode();
  1058. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Accept() SRC:" + ValidationHelper.ToString(LocalEndPoint));
  1059. SocketAddress socketAddress = m_RightEndPoint.Serialize();
  1060. // This may throw ObjectDisposedException.
  1061. SafeCloseSocket acceptedSocketHandle = SafeCloseSocket.Accept(
  1062. m_Handle,
  1063. socketAddress.m_Buffer,
  1064. ref socketAddress.m_Size);
  1065. //
  1066. // if the native call fails we'll throw a SocketException
  1067. //
  1068. if (acceptedSocketHandle.IsInvalid) {
  1069. //
  1070. // update our internal state after this socket error and throw
  1071. //
  1072. SocketException socketException = new SocketException();
  1073. UpdateStatusAfterSocketError(socketException);
  1074. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Accept", socketException);
  1075. throw socketException;
  1076. }
  1077. Socket socket = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress), false);
  1078. if (s_LoggingEnabled) {
  1079. Logging.PrintInfo(Logging.Sockets, socket, SR.GetString(SR.net_log_socket_accepted, socket.RemoteEndPoint, socket.LocalEndPoint));
  1080. Logging.Exit(Logging.Sockets, this, "Accept", socket);
  1081. }
  1082. return socket;
  1083. }
  1084. #endif // !MONO
  1085. /// <devdoc>
  1086. /// <para>Sends a data buffer to a connected socket.</para>
  1087. /// </devdoc>
  1088. public int Send(byte[] buffer, int size, SocketFlags socketFlags) {
  1089. return Send(buffer, 0, size, socketFlags);
  1090. }
  1091. /// <devdoc>
  1092. /// <para>[To be supplied.]</para>
  1093. /// </devdoc>
  1094. public int Send(byte[] buffer, SocketFlags socketFlags) {
  1095. return Send(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags);
  1096. }
  1097. /// <devdoc>
  1098. /// <para>[To be supplied.]</para>
  1099. /// </devdoc>
  1100. public int Send(byte[] buffer) {
  1101. return Send(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None);
  1102. }
  1103. #if !FEATURE_PAL
  1104. /// <devdoc>
  1105. /// <para>[To be supplied.]</para>
  1106. /// </devdoc>
  1107. public int Send(IList<ArraySegment<byte>> buffers) {
  1108. return Send(buffers,SocketFlags.None);
  1109. }
  1110. /// <devdoc>
  1111. /// <para>[To be supplied.]</para>
  1112. /// </devdoc>
  1113. public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) {
  1114. SocketError errorCode;
  1115. int bytesTransferred = Send(buffers, socketFlags, out errorCode);
  1116. if(errorCode != SocketError.Success){
  1117. throw new SocketException(errorCode);
  1118. }
  1119. return bytesTransferred;
  1120. }
  1121. #if !MONO
  1122. public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode) {
  1123. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Send", "");
  1124. if (CleanedUp) {
  1125. throw new ObjectDisposedException(this.GetType().FullName);
  1126. }
  1127. if (buffers==null) {
  1128. throw new ArgumentNullException("buffers");
  1129. }
  1130. if(buffers.Count == 0){
  1131. throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
  1132. }
  1133. ValidateBlockingMode();
  1134. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
  1135. //make sure we don't let the app mess up the buffer array enough to cause
  1136. //corruption.
  1137. errorCode = SocketError.Success;
  1138. int count = buffers.Count;
  1139. WSABuffer[] WSABuffers = new WSABuffer[count];
  1140. GCHandle[] objectsToPin = null;
  1141. int bytesTransferred;
  1142. try {
  1143. objectsToPin = new GCHandle[count];
  1144. for (int i = 0; i < count; ++i)
  1145. {
  1146. ArraySegment<byte> buffer = buffers[i];
  1147. ValidationHelper.ValidateSegment(buffer);
  1148. objectsToPin[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
  1149. WSABuffers[i].Length = buffer.Count;
  1150. WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset);
  1151. }
  1152. // This may throw ObjectDisposedException.
  1153. errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend_Blocking(
  1154. m_Handle.DangerousGetHandle(),
  1155. WSABuffers,
  1156. count,
  1157. out bytesTransferred,
  1158. socketFlags,
  1159. SafeNativeOverlapped.Zero,
  1160. IntPtr.Zero);
  1161. if ((SocketError)errorCode==SocketError.SocketError) {
  1162. errorCode = (SocketError)Marshal.GetLastWin32Error();
  1163. }
  1164. #if TRAVE
  1165. try
  1166. {
  1167. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.send returns errorCode:" + errorCode + " bytesTransferred:" + bytesTransferred);
  1168. }
  1169. catch (ObjectDisposedException) { }
  1170. #endif
  1171. }
  1172. finally {
  1173. if (objectsToPin != null)
  1174. for (int i = 0; i < objectsToPin.Length; ++i)
  1175. if (objectsToPin[i].IsAllocated)
  1176. objectsToPin[i].Free();
  1177. }
  1178. if (errorCode != SocketError.Success) {
  1179. //
  1180. // update our internal state after this socket error and throw
  1181. //
  1182. UpdateStatusAfterSocketError(errorCode);
  1183. if(s_LoggingEnabled){
  1184. Logging.Exception(Logging.Sockets, this, "Send", new SocketException(errorCode));
  1185. Logging.Exit(Logging.Sockets, this, "Send", 0);
  1186. }
  1187. return 0;
  1188. }
  1189. #if !FEATURE_PAL // perfcounter
  1190. if (s_PerfCountersEnabled)
  1191. {
  1192. if (bytesTransferred>0) {
  1193. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
  1194. if (Transport==TransportType.Udp) {
  1195. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
  1196. }
  1197. }
  1198. }
  1199. #endif
  1200. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Send", bytesTransferred);
  1201. return bytesTransferred;
  1202. }
  1203. #endif // !MONO
  1204. /// <devdoc>
  1205. /// <para>Sends a file to
  1206. /// a connected socket.</para>
  1207. /// </devdoc>
  1208. [ResourceExposure(ResourceScope.Machine)]
  1209. [ResourceConsumption(ResourceScope.Machine)]
  1210. public void SendFile(string fileName)
  1211. {
  1212. SendFile(fileName,null,null,TransmitFileOptions.UseDefaultWorkerThread);
  1213. }
  1214. #if !MONO
  1215. /// <devdoc>
  1216. /// <para>Sends a file to
  1217. /// a connected socket.</para>
  1218. /// </devdoc>
  1219. [ResourceExposure(ResourceScope.Machine)]
  1220. [ResourceConsumption(ResourceScope.Machine)]
  1221. public void SendFile(string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags) {
  1222. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "SendFile", "");
  1223. if (CleanedUp) {
  1224. throw new ObjectDisposedException(this.GetType().FullName);
  1225. }
  1226. if (!Connected) {
  1227. throw new NotSupportedException(SR.GetString(SR.net_notconnected));
  1228. }
  1229. ValidateBlockingMode();
  1230. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " fileName:" + fileName);
  1231. TransmitFileOverlappedAsyncResult asyncResult = new TransmitFileOverlappedAsyncResult(this);
  1232. FileStream fileStream = null;
  1233. if (fileName != null && fileName.Length>0) {
  1234. fileStream = new FileStream(fileName,FileMode.Open,FileAccess.Read,FileShare.Read);
  1235. }
  1236. SafeHandle fileHandle = null;
  1237. if (fileStream != null) {
  1238. ExceptionHelper.UnmanagedPermission.Assert();
  1239. try {
  1240. fileHandle = fileStream.SafeFileHandle;
  1241. }
  1242. finally {
  1243. SecurityPermission.RevertAssert();
  1244. }
  1245. }
  1246. SocketError errorCode = SocketError.Success;
  1247. try {
  1248. asyncResult.SetUnmanagedStructures(preBuffer, postBuffer, fileStream, 0, true);
  1249. // This can throw ObjectDisposedException.
  1250. if (fileHandle != null ?
  1251. !UnsafeNclNativeMethods.OSSOCK.TransmitFile_Blocking(m_Handle.DangerousGetHandle(), fileHandle, 0, 0, SafeNativeOverlapped.Zero, asyncResult.TransmitFileBuffers, flags) :
  1252. !UnsafeNclNativeMethods.OSSOCK.TransmitFile_Blocking2(m_Handle.DangerousGetHandle(), IntPtr.Zero, 0, 0, SafeNativeOverlapped.Zero, asyncResult.TransmitFileBuffers, flags))
  1253. {
  1254. errorCode = (SocketError) Marshal.GetLastWin32Error();
  1255. }
  1256. }
  1257. finally {
  1258. asyncResult.SyncReleaseUnmanagedStructures();
  1259. }
  1260. #if TRAVE
  1261. try
  1262. {
  1263. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.TransmitFile returns errorCode:" + errorCode);
  1264. }
  1265. catch (ObjectDisposedException) { }
  1266. #endif
  1267. //
  1268. // if the native call fails we'll throw a SocketException
  1269. //
  1270. if (errorCode!=SocketError.Success) {
  1271. //
  1272. // update our internal state after this socket error and throw
  1273. //
  1274. SocketException socketException = new SocketException(errorCode);
  1275. UpdateStatusAfterSocketError(socketException);
  1276. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SendFile", socketException);
  1277. throw socketException;
  1278. }
  1279. if ((asyncResult.Flags & (TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket) )!=0) {
  1280. SetToDisconnected();
  1281. m_RemoteEndPoint = null;
  1282. }
  1283. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "SendFile", errorCode);
  1284. return;
  1285. }
  1286. #endif // !MONO
  1287. #endif // !FEATURE_PAL
  1288. /// <devdoc>
  1289. /// <para>Sends data to
  1290. /// a connected socket, starting at the indicated location in the
  1291. /// data.</para>
  1292. /// </devdoc>
  1293. public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) {
  1294. SocketError errorCode;
  1295. int bytesTransferred = Send(buffer, offset, size, socketFlags, out errorCode);
  1296. if(errorCode != SocketError.Success){
  1297. throw new SocketException(errorCode);
  1298. }
  1299. return bytesTransferred;
  1300. }
  1301. #if !MONO
  1302. public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) {
  1303. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Send", "");
  1304. if (CleanedUp) {
  1305. throw new ObjectDisposedException(this.GetType().FullName);
  1306. }
  1307. //
  1308. // parameter validation
  1309. //
  1310. if (buffer==null) {
  1311. throw new ArgumentNullException("buffer");
  1312. }
  1313. if (offset<0 || offset>buffer.Length) {
  1314. throw new ArgumentOutOfRangeException("offset");
  1315. }
  1316. if (size<0 || size>buffer.Length-offset) {
  1317. throw new ArgumentOutOfRangeException("size");
  1318. }
  1319. errorCode = SocketError.Success;
  1320. ValidateBlockingMode();
  1321. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size);
  1322. // This can throw ObjectDisposedException.
  1323. int bytesTransferred;
  1324. unsafe {
  1325. if (buffer.Length == 0)
  1326. bytesTransferred = UnsafeNclNativeMethods.OSSOCK.send(m_Handle.DangerousGetHandle(), null, 0, socketFlags);
  1327. else{
  1328. fixed (byte* pinnedBuffer = buffer) {
  1329. bytesTransferred = UnsafeNclNativeMethods.OSSOCK.send(
  1330. m_Handle.DangerousGetHandle(),
  1331. pinnedBuffer+offset,
  1332. size,
  1333. socketFlags);
  1334. }
  1335. }
  1336. }
  1337. //
  1338. // if the native call fails we'll throw a SocketException
  1339. //
  1340. if ((SocketError)bytesTransferred==SocketError.SocketError) {
  1341. //
  1342. // update our internal state after this socket error and throw
  1343. //
  1344. errorCode = (SocketError)Marshal.GetLastWin32Error();
  1345. UpdateStatusAfterSocketError(errorCode);
  1346. if(s_LoggingEnabled){
  1347. Logging.Exception(Logging.Sockets, this, "Send", new SocketException(errorCode));
  1348. Logging.Exit(Logging.Sockets, this, "Send", 0);
  1349. }
  1350. return 0;
  1351. }
  1352. #if !FEATURE_PAL // perfcounter
  1353. if (s_PerfCountersEnabled)
  1354. {
  1355. if (bytesTransferred>0) {
  1356. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
  1357. if (Transport==TransportType.Udp) {
  1358. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
  1359. }
  1360. }
  1361. }
  1362. #endif //!FEATURE_PAL
  1363. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() UnsafeNclNativeMethods.OSSOCK.send returns:" + bytesTransferred.ToString());
  1364. GlobalLog.Dump(buffer, offset, bytesTransferred);
  1365. if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "Send", buffer, offset, size);
  1366. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Send", bytesTransferred);
  1367. return bytesTransferred;
  1368. }
  1369. /// <devdoc>
  1370. /// <para>Sends data to a specific end point, starting at the indicated location in the
  1371. /// data.</para>
  1372. /// </devdoc>
  1373. public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP) {
  1374. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "SendTo", "");
  1375. if (CleanedUp) {
  1376. throw new ObjectDisposedException(this.GetType().FullName);
  1377. }
  1378. //
  1379. // parameter validation
  1380. //
  1381. if (buffer==null) {
  1382. throw new ArgumentNullException("buffer");
  1383. }
  1384. if (remoteEP==null) {
  1385. throw new ArgumentNullException("remoteEP");
  1386. }
  1387. if (offset<0 || offset>buffer.Length) {
  1388. throw new ArgumentOutOfRangeException("offset");
  1389. }
  1390. if (size<0 || size>buffer.Length-offset) {
  1391. throw new ArgumentOutOfRangeException("size");
  1392. }
  1393. ValidateBlockingMode();
  1394. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendTo() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " size:" + size + " remoteEP:" + ValidationHelper.ToString(remoteEP));
  1395. //That will check ConnectPermission for remoteEP
  1396. EndPoint endPointSnapshot = remoteEP;
  1397. SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, false);
  1398. // This can throw ObjectDisposedException.
  1399. int bytesTransferred;
  1400. unsafe
  1401. {
  1402. if (buffer.Length == 0)
  1403. {
  1404. bytesTransferred = UnsafeNclNativeMethods.OSSOCK.sendto(
  1405. m_Handle.DangerousGetHandle(),
  1406. null,
  1407. 0,
  1408. socketFlags,
  1409. socketAddress.m_Buffer,
  1410. socketAddress.m_Size);
  1411. }
  1412. else
  1413. {
  1414. fixed (byte* pinnedBuffer = buffer)
  1415. {
  1416. bytesTransferred = UnsafeNclNativeMethods.OSSOCK.sendto(
  1417. m_Handle.DangerousGetHandle(),
  1418. pinnedBuffer+offset,
  1419. size,
  1420. socketFlags,
  1421. socketAddress.m_Buffer,
  1422. socketAddress.m_Size);
  1423. }
  1424. }
  1425. }
  1426. //
  1427. // if the native call fails we'll throw a SocketException
  1428. //
  1429. if ((SocketError)bytesTransferred==SocketError.SocketError) {
  1430. //
  1431. // update our internal state after this socket error and throw
  1432. //
  1433. SocketException socketException = new SocketException();
  1434. UpdateStatusAfterSocketError(socketException);
  1435. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SendTo", socketException);
  1436. throw socketException;
  1437. }
  1438. if (m_RightEndPoint==null) {
  1439. //
  1440. // save a copy of the EndPoint so we can use it for Create()
  1441. //
  1442. m_RightEndPoint = endPointSnapshot;
  1443. }
  1444. #if !FEATURE_PAL // perfcounter
  1445. if (s_PerfCountersEnabled)
  1446. {
  1447. if (bytesTransferred>0) {
  1448. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
  1449. if (Transport==TransportType.Udp) {
  1450. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
  1451. }
  1452. }
  1453. }
  1454. #endif //!FEATURE_PAL
  1455. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendTo() returning bytesTransferred:" + bytesTransferred.ToString());
  1456. GlobalLog.Dump(buffer, offset, bytesTransferred);
  1457. if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "SendTo", buffer, offset, size);
  1458. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "SendTo", bytesTransferred);
  1459. return bytesTransferred;
  1460. }
  1461. #endif // !MONO
  1462. /// <devdoc>
  1463. /// <para>Sends data to a specific end point, starting at the indicated location in the data.</para>
  1464. /// </devdoc>
  1465. public int SendTo(byte[] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP) {
  1466. return SendTo(buffer, 0, size, socketFlags, remoteEP);
  1467. }
  1468. /// <devdoc>
  1469. /// <para>[To be supplied.]</para>
  1470. /// </devdoc>
  1471. public int SendTo(byte[] buffer, SocketFlags socketFlags, EndPoint remoteEP) {
  1472. return SendTo(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags, remoteEP);
  1473. }
  1474. /// <devdoc>
  1475. /// <para>[To be supplied.]</para>
  1476. /// </devdoc>
  1477. public int SendTo(byte[] buffer, EndPoint remoteEP) {
  1478. return SendTo(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None, remoteEP);
  1479. }
  1480. /// <devdoc>
  1481. /// <para>Receives data from a connected socket.</para>
  1482. /// </devdoc>
  1483. public int Receive(byte[] buffer, int size, SocketFlags socketFlags) {
  1484. return Receive(buffer, 0, size, socketFlags);
  1485. }
  1486. /// <devdoc>
  1487. /// <para>[To be supplied.]</para>
  1488. /// </devdoc>
  1489. public int Receive(byte[] buffer, SocketFlags socketFlags) {
  1490. return Receive(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags);
  1491. }
  1492. /// <devdoc>
  1493. /// <para>[To be supplied.]</para>
  1494. /// </devdoc>
  1495. public int Receive(byte[] buffer) {
  1496. return Receive(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None);
  1497. }
  1498. /// <devdoc>
  1499. /// <para>Receives data from a connected socket into a specific location of the receive
  1500. /// buffer.</para>
  1501. /// </devdoc>
  1502. public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags) {
  1503. SocketError errorCode;
  1504. int bytesTransferred = Receive(buffer, offset, size, socketFlags, out errorCode);
  1505. if(errorCode != SocketError.Success){
  1506. throw new SocketException(errorCode);
  1507. }
  1508. return bytesTransferred;
  1509. }
  1510. #if !MONO
  1511. public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) {
  1512. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Receive", "");
  1513. if (CleanedUp) {
  1514. throw new ObjectDisposedException(this.GetType().FullName);
  1515. }
  1516. //
  1517. // parameter validation
  1518. //
  1519. if (buffer==null) {
  1520. throw new ArgumentNullException("buffer");
  1521. }
  1522. if (offset<0 || offset>buffer.Length) {
  1523. throw new ArgumentOutOfRangeException("offset");
  1524. }
  1525. if (size<0 || size>buffer.Length-offset) {
  1526. throw new ArgumentOutOfRangeException("size");
  1527. }
  1528. ValidateBlockingMode();
  1529. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size);
  1530. // This can throw ObjectDisposedException.
  1531. int bytesTransferred;
  1532. errorCode = SocketError.Success;
  1533. unsafe {
  1534. if (buffer.Length == 0)
  1535. {
  1536. bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), null, 0, socketFlags);
  1537. }
  1538. else fixed (byte* pinnedBuffer = buffer) {
  1539. bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), pinnedBuffer+offset, size, socketFlags);
  1540. }
  1541. }
  1542. if ((SocketError)bytesTransferred==SocketError.SocketError) {
  1543. //
  1544. // update our internal state after this socket error and throw
  1545. //
  1546. errorCode = (SocketError)Marshal.GetLastWin32Error();
  1547. UpdateStatusAfterSocketError(errorCode);
  1548. if(s_LoggingEnabled){
  1549. Logging.Exception(Logging.Sockets, this, "Receive", new SocketException(errorCode));
  1550. Logging.Exit(Logging.Sockets, this, "Receive", 0);
  1551. }
  1552. return 0;
  1553. }
  1554. #if !FEATURE_PAL // perfcounter
  1555. if (s_PerfCountersEnabled)
  1556. {
  1557. bool peek = ((int)socketFlags & (int)SocketFlags.Peek)!=0;
  1558. if (bytesTransferred>0 && !peek) {
  1559. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
  1560. if (Transport==TransportType.Udp) {
  1561. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
  1562. }
  1563. }
  1564. }
  1565. #endif //!FEATURE_PAL
  1566. #if TRAVE
  1567. try
  1568. {
  1569. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred);
  1570. }
  1571. catch (ObjectDisposedException) { }
  1572. #endif
  1573. GlobalLog.Dump(buffer, offset, bytesTransferred);
  1574. if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "Receive", buffer, offset, bytesTransferred);
  1575. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Receive", bytesTransferred);
  1576. return bytesTransferred;
  1577. }
  1578. #endif // !MONO
  1579. public int Receive(IList<ArraySegment<byte>> buffers) {
  1580. return Receive(buffers,SocketFlags.None);
  1581. }
  1582. public int Receive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) {
  1583. SocketError errorCode;
  1584. int bytesTransferred = Receive(buffers, socketFlags, out errorCode);
  1585. if(errorCode != SocketError.Success){
  1586. throw new SocketException(errorCode);
  1587. }
  1588. return bytesTransferred;
  1589. }
  1590. #if !MONO
  1591. public int Receive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode) {
  1592. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Receive", "");
  1593. if (CleanedUp) {
  1594. throw new ObjectDisposedException(this.GetType().FullName);
  1595. }
  1596. if (buffers==null) {
  1597. throw new ArgumentNullException("buffers");
  1598. }
  1599. if(buffers.Count == 0){
  1600. throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
  1601. }
  1602. ValidateBlockingMode();
  1603. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
  1604. //make sure we don't let the app mess up the buffer array enough to cause
  1605. //corruption.
  1606. int count = buffers.Count;
  1607. WSABuffer[] WSABuffers = new WSABuffer[count];
  1608. GCHandle[] objectsToPin = null;
  1609. int bytesTransferred;
  1610. errorCode = SocketError.Success;
  1611. try {
  1612. objectsToPin = new GCHandle[count];
  1613. for (int i = 0; i < count; ++i)
  1614. {
  1615. ArraySegment<byte> buffer = buffers[i];
  1616. ValidationHelper.ValidateSegment(buffer);
  1617. objectsToPin[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
  1618. WSABuffers[i].Length = buffer.Count;
  1619. WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset);
  1620. }
  1621. // This can throw ObjectDisposedException.
  1622. errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv_Blocking(
  1623. m_Handle.DangerousGetHandle(),
  1624. WSABuffers,
  1625. count,
  1626. out bytesTransferred,
  1627. ref socketFlags,
  1628. SafeNativeOverlapped.Zero,
  1629. IntPtr.Zero );
  1630. if ((SocketError)errorCode==SocketError.SocketError) {
  1631. errorCode = (SocketError)Marshal.GetLastWin32Error();
  1632. }
  1633. #if TRAVE
  1634. try
  1635. {
  1636. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.send returns errorCode:" + errorCode + " bytesTransferred:" + bytesTransferred);
  1637. }
  1638. catch (ObjectDisposedException) { }
  1639. #endif
  1640. }
  1641. finally {
  1642. if (objectsToPin != null)
  1643. for (int i = 0; i < objectsToPin.Length; ++i)
  1644. if (objectsToPin[i].IsAllocated)
  1645. objectsToPin[i].Free();
  1646. }
  1647. if (errorCode != SocketError.Success) {
  1648. //
  1649. // update our internal state after this socket error and throw
  1650. //
  1651. UpdateStatusAfterSocketError(errorCode);
  1652. if(s_LoggingEnabled){
  1653. Logging.Exception(Logging.Sockets, this, "Receive", new SocketException(errorCode));
  1654. Logging.Exit(Logging.Sockets, this, "Receive", 0);
  1655. }
  1656. return 0;
  1657. }
  1658. #if !FEATURE_PAL // perfcounter
  1659. if (s_PerfCountersEnabled)
  1660. {
  1661. bool peek = ((int)socketFlags & (int)SocketFlags.Peek)!=0;
  1662. if (bytesTransferred>0 && !peek) {
  1663. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
  1664. if (Transport==TransportType.Udp) {
  1665. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
  1666. }
  1667. }
  1668. }
  1669. #endif //!FEATURE_PAL
  1670. #if TRAVE
  1671. try
  1672. {
  1673. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred);
  1674. }
  1675. catch (ObjectDisposedException) { }
  1676. #endif
  1677. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Receive", bytesTransferred);
  1678. return bytesTransferred;
  1679. }
  1680. /// <devdoc>
  1681. /// <para>Receives a datagram into a specific location in the data buffer and stores
  1682. /// the end point.</para>
  1683. /// </devdoc>
  1684. public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation) {
  1685. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "ReceiveMessageFrom", "");
  1686. if (CleanedUp) {
  1687. throw new ObjectDisposedException(this.GetType().FullName);
  1688. }
  1689. if (buffer==null) {
  1690. throw new ArgumentNullException("buffer");
  1691. }
  1692. if (remoteEP==null) {
  1693. throw new ArgumentNullException("remoteEP");
  1694. }
  1695. if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
  1696. throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
  1697. remoteEP.AddressFamily, addressFamily), "remoteEP");
  1698. }
  1699. if (offset<0 || offset>buffer.Length) {
  1700. throw new ArgumentOutOfRangeException("offset");
  1701. }
  1702. if (size<0 || size>buffer.Length-offset) {
  1703. throw new ArgumentOutOfRangeException("size");
  1704. }
  1705. if (m_RightEndPoint==null) {
  1706. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  1707. }
  1708. ValidateBlockingMode();
  1709. // We don't do a CAS demand here because the contents of remoteEP aren't used by
  1710. // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
  1711. // with the right address family
  1712. EndPoint endPointSnapshot = remoteEP;
  1713. SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
  1714. ReceiveMessageOverlappedAsyncResult asyncResult = new ReceiveMessageOverlappedAsyncResult(this,null,null);
  1715. asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, socketFlags);
  1716. // save a copy of the original EndPoint
  1717. SocketAddress socketAddressOriginal = endPointSnapshot.Serialize();
  1718. //setup structure
  1719. int bytesTransfered = 0;
  1720. SocketError errorCode = SocketError.Success;
  1721. SetReceivingPacketInformation();
  1722. try
  1723. {
  1724. // This can throw ObjectDisposedException (retrieving the delegate AND resolving the handle).
  1725. if (WSARecvMsg_Blocking(
  1726. m_Handle.DangerousGetHandle(),
  1727. Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.m_MessageBuffer,0),
  1728. out bytesTransfered,
  1729. IntPtr.Zero,
  1730. IntPtr.Zero) == SocketError.SocketError)
  1731. {
  1732. errorCode = (SocketError)Marshal.GetLastWin32Error();
  1733. }
  1734. }
  1735. finally {
  1736. asyncResult.SyncReleaseUnmanagedStructures();
  1737. }
  1738. //
  1739. // if the native call fails we'll throw a SocketException
  1740. //
  1741. if (errorCode!=SocketError.Success && errorCode != SocketError.MessageSize) {
  1742. //
  1743. // update our internal state after this socket error and throw
  1744. //
  1745. SocketException socketException = new SocketException(errorCode);
  1746. UpdateStatusAfterSocketError(socketException);
  1747. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "ReceiveMessageFrom", socketException);
  1748. throw socketException;
  1749. }
  1750. if (!socketAddressOriginal.Equals(asyncResult.m_SocketAddress))
  1751. {
  1752. try {
  1753. remoteEP = endPointSnapshot.Create(asyncResult.m_SocketAddress);
  1754. }
  1755. catch {
  1756. }
  1757. if (m_RightEndPoint==null) {
  1758. //
  1759. // save a copy of the EndPoint so we can use it for Create()
  1760. //
  1761. m_RightEndPoint = endPointSnapshot;
  1762. }
  1763. }
  1764. socketFlags = asyncResult.m_flags;
  1765. ipPacketInformation = asyncResult.m_IPPacketInformation;
  1766. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "ReceiveMessageFrom", errorCode);
  1767. return bytesTransfered;
  1768. }
  1769. /// <devdoc>
  1770. /// <para>Receives a datagram into a specific location in the data buffer and stores
  1771. /// the end point.</para>
  1772. /// </devdoc>
  1773. public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP) {
  1774. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "ReceiveFrom", "");
  1775. if (CleanedUp) {
  1776. throw new ObjectDisposedException(this.GetType().FullName);
  1777. }
  1778. //
  1779. // parameter validation
  1780. //
  1781. if (buffer==null) {
  1782. throw new ArgumentNullException("buffer");
  1783. }
  1784. if (remoteEP==null) {
  1785. throw new ArgumentNullException("remoteEP");
  1786. }
  1787. if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
  1788. throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
  1789. remoteEP.AddressFamily, addressFamily), "remoteEP");
  1790. }
  1791. if (offset<0 || offset>buffer.Length) {
  1792. throw new ArgumentOutOfRangeException("offset");
  1793. }
  1794. if (size<0 || size>buffer.Length-offset) {
  1795. throw new ArgumentOutOfRangeException("size");
  1796. }
  1797. if (m_RightEndPoint==null) {
  1798. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  1799. }
  1800. ValidateBlockingMode();
  1801. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ReceiveFrom() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " size:" + size + " remoteEP:" + remoteEP.ToString());
  1802. // We don't do a CAS demand here because the contents of remoteEP aren't used by
  1803. // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
  1804. // with the right address family
  1805. EndPoint endPointSnapshot = remoteEP;
  1806. SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
  1807. SocketAddress socketAddressOriginal = endPointSnapshot.Serialize();
  1808. // This can throw ObjectDisposedException.
  1809. int bytesTransferred;
  1810. unsafe {
  1811. if (buffer.Length == 0)
  1812. bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recvfrom(m_Handle.DangerousGetHandle(), null, 0, socketFlags, socketAddress.m_Buffer, ref socketAddress.m_Size );
  1813. else fixed (byte* pinnedBuffer = buffer) {
  1814. bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recvfrom(m_Handle.DangerousGetHandle(), pinnedBuffer+offset, size, socketFlags, socketAddress.m_Buffer, ref socketAddress.m_Size );
  1815. }
  1816. }
  1817. // If the native call fails we'll throw a SocketException.
  1818. // Must do this immediately after the native call so that the SocketException() constructor can pick up the error code.
  1819. SocketException socketException = null;
  1820. if ((SocketError) bytesTransferred == SocketError.SocketError)
  1821. {
  1822. socketException = new SocketException();
  1823. UpdateStatusAfterSocketError(socketException);
  1824. if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "ReceiveFrom", socketException);
  1825. if(socketException.ErrorCode != (int)SocketError.MessageSize){
  1826. throw socketException;
  1827. }
  1828. }
  1829. if (!socketAddressOriginal.Equals(socketAddress)) {
  1830. try {
  1831. remoteEP = endPointSnapshot.Create(socketAddress);
  1832. }
  1833. catch {
  1834. }
  1835. if (m_RightEndPoint==null) {
  1836. //
  1837. // save a copy of the EndPoint so we can use it for Create()
  1838. //
  1839. m_RightEndPoint = endPointSnapshot;
  1840. }
  1841. }
  1842. if(socketException != null){
  1843. throw socketException;
  1844. }
  1845. #if !FEATURE_PAL // perfcounter
  1846. if (s_PerfCountersEnabled)
  1847. {
  1848. if (bytesTransferred>0) {
  1849. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
  1850. if (Transport==TransportType.Udp) {
  1851. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
  1852. }
  1853. }
  1854. }
  1855. #endif //!FEATURE_PAL
  1856. GlobalLog.Dump(buffer, offset, bytesTransferred);
  1857. if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "ReceiveFrom", buffer, offset, size);
  1858. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "ReceiveFrom", bytesTransferred);
  1859. return bytesTransferred;
  1860. }
  1861. #endif // !MONO
  1862. /// <devdoc>
  1863. /// <para>Receives a datagram and stores the source end point.</para>
  1864. /// </devdoc>
  1865. public int ReceiveFrom(byte[] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP) {
  1866. return ReceiveFrom(buffer, 0, size, socketFlags, ref remoteEP);
  1867. }
  1868. /// <devdoc>
  1869. /// <para>[To be supplied.]</para>
  1870. /// </devdoc>
  1871. public int ReceiveFrom(byte[] buffer, SocketFlags socketFlags, ref EndPoint remoteEP) {
  1872. return ReceiveFrom(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags, ref remoteEP);
  1873. }
  1874. /// <devdoc>
  1875. /// <para>[To be supplied.]</para>
  1876. /// </devdoc>
  1877. public int ReceiveFrom(byte[] buffer, ref EndPoint remoteEP) {
  1878. return ReceiveFrom(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None, ref remoteEP);
  1879. }
  1880. #if !MONO
  1881. // UE
  1882. /// <devdoc>
  1883. /// <para>[To be supplied.]</para>
  1884. /// </devdoc>
  1885. public int IOControl(int ioControlCode, byte[] optionInValue, byte[] optionOutValue) {
  1886. if (CleanedUp) {
  1887. throw new ObjectDisposedException(this.GetType().FullName);
  1888. }
  1889. if (ioControlCode==IoctlSocketConstants.FIONBIO) {
  1890. throw new InvalidOperationException(SR.GetString(SR.net_sockets_useblocking));
  1891. }
  1892. ExceptionHelper.UnmanagedPermission.Demand();
  1893. int realOptionLength = 0;
  1894. // This can throw ObjectDisposedException.
  1895. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
  1896. m_Handle.DangerousGetHandle(),
  1897. ioControlCode,
  1898. optionInValue,
  1899. optionInValue!=null ? optionInValue.Length : 0,
  1900. optionOutValue,
  1901. optionOutValue!=null ? optionOutValue.Length : 0,
  1902. out realOptionLength,
  1903. SafeNativeOverlapped.Zero,
  1904. IntPtr.Zero);
  1905. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::IOControl() UnsafeNclNativeMethods.OSSOCK.WSAIoctl returns errorCode:" + errorCode);
  1906. //
  1907. // if the native call fails we'll throw a SocketException
  1908. //
  1909. if (errorCode==SocketError.SocketError) {
  1910. //
  1911. // update our internal state after this socket error and throw
  1912. //
  1913. SocketException socketException = new SocketException();
  1914. UpdateStatusAfterSocketError(socketException);
  1915. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "IOControl", socketException);
  1916. throw socketException;
  1917. }
  1918. return realOptionLength;
  1919. }
  1920. #endif // !MONO
  1921. // UE
  1922. /// <devdoc>
  1923. /// <para>[To be supplied.]</para>
  1924. /// </devdoc>
  1925. public int IOControl(IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue) {
  1926. return IOControl(unchecked((int)ioControlCode),optionInValue,optionOutValue);
  1927. }
  1928. #if !MONO
  1929. internal int IOControl( IOControlCode ioControlCode,
  1930. IntPtr optionInValue,
  1931. int inValueSize,
  1932. IntPtr optionOutValue,
  1933. int outValueSize)
  1934. {
  1935. if (CleanedUp) {
  1936. throw new ObjectDisposedException(this.GetType().FullName);
  1937. }
  1938. if ( (unchecked((int)ioControlCode)) ==IoctlSocketConstants.FIONBIO) {
  1939. throw new InvalidOperationException(SR.GetString(SR.net_sockets_useblocking));
  1940. }
  1941. int realOptionLength = 0;
  1942. // This can throw ObjectDisposedException.
  1943. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking_Internal(
  1944. m_Handle.DangerousGetHandle(),
  1945. (uint)ioControlCode,
  1946. optionInValue,
  1947. inValueSize,
  1948. optionOutValue,
  1949. outValueSize,
  1950. out realOptionLength,
  1951. SafeNativeOverlapped.Zero,
  1952. IntPtr.Zero);
  1953. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::IOControl() UnsafeNclNativeMethods.OSSOCK.WSAIoctl returns errorCode:" + errorCode);
  1954. //
  1955. // if the native call fails we'll throw a SocketException
  1956. //
  1957. if (errorCode==SocketError.SocketError) {
  1958. //
  1959. // update our internal state after this socket error and throw
  1960. //
  1961. SocketException socketException = new SocketException();
  1962. UpdateStatusAfterSocketError(socketException);
  1963. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "IOControl", socketException);
  1964. throw socketException;
  1965. }
  1966. return realOptionLength;
  1967. }
  1968. #endif // !MONO
  1969. public void SetIPProtectionLevel(IPProtectionLevel level) {
  1970. if (level == IPProtectionLevel.Unspecified) {
  1971. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue_all), "level");
  1972. }
  1973. if (addressFamily == AddressFamily.InterNetworkV6) {
  1974. SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPProtectionLevel, (int)level);
  1975. }
  1976. else if (addressFamily == AddressFamily.InterNetwork) {
  1977. SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IPProtectionLevel, (int)level);
  1978. }
  1979. else {
  1980. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  1981. }
  1982. }
  1983. #if !MONO
  1984. /// <devdoc>
  1985. /// <para>
  1986. /// Sets the specified option to the specified value.
  1987. /// </para>
  1988. /// </devdoc>
  1989. public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue) {
  1990. if (CleanedUp) {
  1991. throw new ObjectDisposedException(this.GetType().FullName);
  1992. }
  1993. CheckSetOptionPermissions(optionLevel, optionName);
  1994. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
  1995. SetSocketOption(optionLevel, optionName, optionValue, false);
  1996. }
  1997. /// <devdoc>
  1998. /// <para>[To be supplied.]</para>
  1999. /// </devdoc>
  2000. public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue) {
  2001. if (CleanedUp) {
  2002. throw new ObjectDisposedException(this.GetType().FullName);
  2003. }
  2004. CheckSetOptionPermissions(optionLevel, optionName);
  2005. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
  2006. // This can throw ObjectDisposedException.
  2007. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
  2008. m_Handle,
  2009. optionLevel,
  2010. optionName,
  2011. optionValue,
  2012. optionValue != null ? optionValue.Length : 0);
  2013. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
  2014. //
  2015. // if the native call fails we'll throw a SocketException
  2016. //
  2017. if (errorCode==SocketError.SocketError) {
  2018. //
  2019. // update our internal state after this socket error and throw
  2020. //
  2021. SocketException socketException = new SocketException();
  2022. UpdateStatusAfterSocketError(socketException);
  2023. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SetSocketOption", socketException);
  2024. throw socketException;
  2025. }
  2026. }
  2027. /// <devdoc>
  2028. /// <para>Sets the specified option to the specified value.</para>
  2029. /// </devdoc>
  2030. public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue) {
  2031. SetSocketOption(optionLevel,optionName,(optionValue?1:0));
  2032. }
  2033. /// <devdoc>
  2034. /// <para>Sets the specified option to the specified value.</para>
  2035. /// </devdoc>
  2036. public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue) {
  2037. if (CleanedUp) {
  2038. throw new ObjectDisposedException(this.GetType().FullName);
  2039. }
  2040. //
  2041. // parameter validation
  2042. //
  2043. if (optionValue==null) {
  2044. throw new ArgumentNullException("optionValue");
  2045. }
  2046. CheckSetOptionPermissions(optionLevel, optionName);
  2047. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
  2048. if (optionLevel==SocketOptionLevel.Socket && optionName==SocketOptionName.Linger) {
  2049. LingerOption lingerOption = optionValue as LingerOption;
  2050. if (lingerOption==null) {
  2051. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "LingerOption"), "optionValue");
  2052. }
  2053. if (lingerOption.LingerTime < 0 || lingerOption.LingerTime>(int)UInt16.MaxValue) {
  2054. throw new ArgumentException(SR.GetString(SR.ArgumentOutOfRange_Bounds_Lower_Upper, 0, (int)UInt16.MaxValue), "optionValue.LingerTime");
  2055. }
  2056. setLingerOption(lingerOption);
  2057. }
  2058. else if (optionLevel==SocketOptionLevel.IP && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
  2059. MulticastOption multicastOption = optionValue as MulticastOption;
  2060. if (multicastOption==null) {
  2061. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "MulticastOption"), "optionValue");
  2062. }
  2063. setMulticastOption(optionName, multicastOption);
  2064. }
  2065. //
  2066. // IPv6 Changes: Handle IPv6 Multicast Add / Drop
  2067. //
  2068. else if (optionLevel==SocketOptionLevel.IPv6 && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
  2069. IPv6MulticastOption multicastOption = optionValue as IPv6MulticastOption;
  2070. if (multicastOption==null) {
  2071. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "IPv6MulticastOption"), "optionValue");
  2072. }
  2073. setIPv6MulticastOption(optionName, multicastOption);
  2074. }
  2075. else {
  2076. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue_all), "optionValue");
  2077. }
  2078. }
  2079. /// <devdoc>
  2080. /// <para>
  2081. /// Gets the value of a socket option.
  2082. /// </para>
  2083. /// </devdoc>
  2084. // UE
  2085. public object GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName) {
  2086. if (CleanedUp) {
  2087. throw new ObjectDisposedException(this.GetType().FullName);
  2088. }
  2089. if (optionLevel==SocketOptionLevel.Socket && optionName==SocketOptionName.Linger) {
  2090. return getLingerOpt();
  2091. }
  2092. else if (optionLevel==SocketOptionLevel.IP && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
  2093. return getMulticastOpt(optionName);
  2094. }
  2095. //
  2096. // Handle IPv6 case
  2097. //
  2098. else if (optionLevel==SocketOptionLevel.IPv6 && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
  2099. return getIPv6MulticastOpt(optionName);
  2100. }
  2101. else {
  2102. int optionValue = 0;
  2103. int optionLength = 4;
  2104. // This can throw ObjectDisposedException.
  2105. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
  2106. m_Handle,
  2107. optionLevel,
  2108. optionName,
  2109. out optionValue,
  2110. ref optionLength);
  2111. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
  2112. //
  2113. // if the native call fails we'll throw a SocketException
  2114. //
  2115. if (errorCode==SocketError.SocketError) {
  2116. //
  2117. // update our internal state after this socket error and throw
  2118. //
  2119. SocketException socketException = new SocketException();
  2120. UpdateStatusAfterSocketError(socketException);
  2121. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
  2122. throw socketException;
  2123. }
  2124. return optionValue;
  2125. }
  2126. }
  2127. // UE
  2128. /// <devdoc>
  2129. /// <para>[To be supplied.]</para>
  2130. /// </devdoc>
  2131. public void GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue) {
  2132. if (CleanedUp) {
  2133. throw new ObjectDisposedException(this.GetType().FullName);
  2134. }
  2135. int optionLength = optionValue!=null ? optionValue.Length : 0;
  2136. // This can throw ObjectDisposedException.
  2137. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
  2138. m_Handle,
  2139. optionLevel,
  2140. optionName,
  2141. optionValue,
  2142. ref optionLength);
  2143. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
  2144. //
  2145. // if the native call fails we'll throw a SocketException
  2146. //
  2147. if (errorCode==SocketError.SocketError) {
  2148. //
  2149. // update our internal state after this socket error and throw
  2150. //
  2151. SocketException socketException = new SocketException();
  2152. UpdateStatusAfterSocketError(socketException);
  2153. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
  2154. throw socketException;
  2155. }
  2156. }
  2157. // UE
  2158. /// <devdoc>
  2159. /// <para>[To be supplied.]</para>
  2160. /// </devdoc>
  2161. public byte[] GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength) {
  2162. if (CleanedUp) {
  2163. throw new ObjectDisposedException(this.GetType().FullName);
  2164. }
  2165. byte[] optionValue = new byte[optionLength];
  2166. int realOptionLength = optionLength;
  2167. // This can throw ObjectDisposedException.
  2168. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
  2169. m_Handle,
  2170. optionLevel,
  2171. optionName,
  2172. optionValue,
  2173. ref realOptionLength);
  2174. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
  2175. //
  2176. // if the native call fails we'll throw a SocketException
  2177. //
  2178. if (errorCode==SocketError.SocketError) {
  2179. //
  2180. // update our internal state after this socket error and throw
  2181. //
  2182. SocketException socketException = new SocketException();
  2183. UpdateStatusAfterSocketError(socketException);
  2184. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
  2185. throw socketException;
  2186. }
  2187. if (optionLength!=realOptionLength) {
  2188. byte[] newOptionValue = new byte[realOptionLength];
  2189. Buffer.BlockCopy(optionValue, 0, newOptionValue, 0, realOptionLength);
  2190. optionValue = newOptionValue;
  2191. }
  2192. return optionValue;
  2193. }
  2194. /// <devdoc>
  2195. /// <para>
  2196. /// Determines the status of the socket.
  2197. /// </para>
  2198. /// </devdoc>
  2199. public bool Poll(int microSeconds, SelectMode mode) {
  2200. if (CleanedUp) {
  2201. throw new ObjectDisposedException(this.GetType().FullName);
  2202. }
  2203. IntPtr handle = m_Handle.DangerousGetHandle();
  2204. IntPtr[] fileDescriptorSet = new IntPtr[2] { (IntPtr) 1, handle };
  2205. TimeValue IOwait = new TimeValue();
  2206. //
  2207. // negative timeout value implies indefinite wait
  2208. //
  2209. int socketCount;
  2210. if (microSeconds != -1) {
  2211. MicrosecondsToTimeValue((long)(uint)microSeconds, ref IOwait);
  2212. socketCount =
  2213. UnsafeNclNativeMethods.OSSOCK.select(
  2214. 0,
  2215. mode==SelectMode.SelectRead ? fileDescriptorSet : null,
  2216. mode==SelectMode.SelectWrite ? fileDescriptorSet : null,
  2217. mode==SelectMode.SelectError ? fileDescriptorSet : null,
  2218. ref IOwait);
  2219. }
  2220. else {
  2221. socketCount =
  2222. UnsafeNclNativeMethods.OSSOCK.select(
  2223. 0,
  2224. mode==SelectMode.SelectRead ? fileDescriptorSet : null,
  2225. mode==SelectMode.SelectWrite ? fileDescriptorSet : null,
  2226. mode==SelectMode.SelectError ? fileDescriptorSet : null,
  2227. IntPtr.Zero);
  2228. }
  2229. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Poll() UnsafeNclNativeMethods.OSSOCK.select returns socketCount:" + socketCount);
  2230. //
  2231. // if the native call fails we'll throw a SocketException
  2232. //
  2233. if ((SocketError)socketCount==SocketError.SocketError) {
  2234. //
  2235. // update our internal state after this socket error and throw
  2236. //
  2237. SocketException socketException = new SocketException();
  2238. UpdateStatusAfterSocketError(socketException);
  2239. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Poll", socketException);
  2240. throw socketException;
  2241. }
  2242. if ((int)fileDescriptorSet[0]==0) {
  2243. return false;
  2244. }
  2245. return fileDescriptorSet[1] == handle;
  2246. }
  2247. /// <devdoc>
  2248. /// <para>Determines the status of a socket.</para>
  2249. /// </devdoc>
  2250. public static void Select(IList checkRead, IList checkWrite, IList checkError, int microSeconds) {
  2251. // parameter validation
  2252. if ((checkRead==null || checkRead.Count==0) && (checkWrite==null || checkWrite.Count==0) && (checkError==null || checkError.Count==0)) {
  2253. throw new ArgumentNullException(SR.GetString(SR.net_sockets_empty_select));
  2254. }
  2255. const int MaxSelect = 65536;
  2256. if (checkRead!=null && checkRead.Count>MaxSelect) {
  2257. throw new ArgumentOutOfRangeException("checkRead", SR.GetString(SR.net_sockets_toolarge_select, "checkRead", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
  2258. }
  2259. if (checkWrite!=null && checkWrite.Count>MaxSelect) {
  2260. throw new ArgumentOutOfRangeException("checkWrite", SR.GetString(SR.net_sockets_toolarge_select, "checkWrite", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
  2261. }
  2262. if (checkError!=null && checkError.Count>MaxSelect) {
  2263. throw new ArgumentOutOfRangeException("checkError", SR.GetString(SR.net_sockets_toolarge_select, "checkError", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
  2264. }
  2265. IntPtr[] readfileDescriptorSet = SocketListToFileDescriptorSet(checkRead);
  2266. IntPtr[] writefileDescriptorSet = SocketListToFileDescriptorSet(checkWrite);
  2267. IntPtr[] errfileDescriptorSet = SocketListToFileDescriptorSet(checkError);
  2268. // This code used to erroneously pass a non-null timeval structure containing zeroes
  2269. // to select() when the caller specified (-1) for the microseconds parameter. That
  2270. // caused select to actually have a *zero* timeout instead of an infinite timeout
  2271. // turning the operation into a non-blocking poll.
  2272. //
  2273. // Now we pass a null timeval struct when microseconds is (-1).
  2274. //
  2275. // Negative microsecond values that weren't exactly (-1) were originally successfully
  2276. // converted to a timeval struct containing unsigned non-zero integers. This code
  2277. // retains that behavior so that any app working around the original bug with,
  2278. // for example, (-2) specified for microseconds, will continue to get the same behavior.
  2279. int socketCount;
  2280. if (microSeconds != -1) {
  2281. TimeValue IOwait = new TimeValue();
  2282. MicrosecondsToTimeValue((long)(uint)microSeconds, ref IOwait);
  2283. socketCount =
  2284. UnsafeNclNativeMethods.OSSOCK.select(
  2285. 0, // ignored value
  2286. readfileDescriptorSet,
  2287. writefileDescriptorSet,
  2288. errfileDescriptorSet,
  2289. ref IOwait);
  2290. }
  2291. else {
  2292. socketCount =
  2293. UnsafeNclNativeMethods.OSSOCK.select(
  2294. 0, // ignored value
  2295. readfileDescriptorSet,
  2296. writefileDescriptorSet,
  2297. errfileDescriptorSet,
  2298. IntPtr.Zero);
  2299. }
  2300. GlobalLog.Print("Socket::Select() UnsafeNclNativeMethods.OSSOCK.select returns socketCount:" + socketCount);
  2301. //
  2302. // if the native call fails we'll throw a SocketException
  2303. //
  2304. if ((SocketError)socketCount==SocketError.SocketError) {
  2305. throw new SocketException();
  2306. }
  2307. SelectFileDescriptor(checkRead, readfileDescriptorSet);
  2308. SelectFileDescriptor(checkWrite, writefileDescriptorSet);
  2309. SelectFileDescriptor(checkError, errfileDescriptorSet);
  2310. }
  2311. #endif // !MONO
  2312. #if !FEATURE_PAL
  2313. /// <devdoc>
  2314. /// <para>[To be supplied.]</para>
  2315. /// </devdoc>
  2316. [HostProtection(ExternalThreading=true)]
  2317. [ResourceExposure(ResourceScope.Machine)]
  2318. [ResourceConsumption(ResourceScope.Machine)]
  2319. public IAsyncResult BeginSendFile(
  2320. string fileName,
  2321. AsyncCallback callback,
  2322. object state)
  2323. {
  2324. return BeginSendFile(fileName,null,null,TransmitFileOptions.UseDefaultWorkerThread,callback,state);
  2325. }
  2326. #endif
  2327. #if !MONO
  2328. //
  2329. // Async Winsock Support, the following functions use either
  2330. // the Async Winsock support to do overlapped I/O WSASend/WSARecv
  2331. // or a WSAEventSelect call to enable selection and non-blocking mode
  2332. // of otherwise normal Winsock calls.
  2333. //
  2334. // Currently the following Async Socket calls are supported:
  2335. // Send, Recv, SendTo, RecvFrom, Connect, Accept
  2336. //
  2337. /*++
  2338. Routine Description:
  2339. BeginConnect - Does a async winsock connect, by calling
  2340. WSAEventSelect to enable Connect Events to signal an event and
  2341. wake up a callback which involkes a callback.
  2342. So note: This routine may go pending at which time,
  2343. but any case the callback Delegate will be called upon completion
  2344. Arguments:
  2345. remoteEP - status line that we wish to parse
  2346. Callback - Async Callback Delegate that is called upon Async Completion
  2347. State - State used to track callback, set by caller, not required
  2348. Return Value:
  2349. IAsyncResult - Async result used to retreive result
  2350. --*/
  2351. /// <devdoc>
  2352. /// <para>[To be supplied.]</para>
  2353. /// </devdoc>
  2354. [HostProtection(ExternalThreading=true)]
  2355. public IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)
  2356. {
  2357. //
  2358. // parameter validation
  2359. //
  2360. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", remoteEP);
  2361. if (CleanedUp) {
  2362. throw new ObjectDisposedException(this.GetType().FullName);
  2363. }
  2364. if (remoteEP==null) {
  2365. throw new ArgumentNullException("remoteEP");
  2366. }
  2367. if (isListening)
  2368. {
  2369. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
  2370. }
  2371. DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
  2372. if (dnsEP != null)
  2373. {
  2374. if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily))
  2375. {
  2376. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  2377. }
  2378. return BeginConnect(dnsEP.Host, dnsEP.Port, callback, state);
  2379. }
  2380. if (CanUseConnectEx(remoteEP))
  2381. {
  2382. return BeginConnectEx(remoteEP, true, callback, state);
  2383. }
  2384. // This will check the permissions for connect.
  2385. EndPoint endPointSnapshot = remoteEP;
  2386. SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true);
  2387. // Flow the context. No need to lock it since we don't use it until the callback.
  2388. ConnectAsyncResult asyncResult = new ConnectAsyncResult(this, endPointSnapshot, state, callback);
  2389. asyncResult.StartPostingAsyncOp(false);
  2390. // Post the connect.
  2391. DoBeginConnect(endPointSnapshot, socketAddress, asyncResult);
  2392. // We didn't throw, so finish the posting op. This will call the callback if the operation already completed.
  2393. asyncResult.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
  2394. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", asyncResult);
  2395. return asyncResult;
  2396. }
  2397. public SocketInformation DuplicateAndClose(int targetProcessId){
  2398. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "DuplicateAndClose", null);
  2399. if (CleanedUp)
  2400. {
  2401. throw new ObjectDisposedException(GetType().FullName);
  2402. }
  2403. ExceptionHelper.UnrestrictedSocketPermission.Demand();
  2404. SocketInformation info = new SocketInformation();
  2405. info.ProtocolInformation = new byte[protocolInformationSize];
  2406. // This can throw ObjectDisposedException.
  2407. SocketError errorCode;
  2408. #if !FEATURE_PAL
  2409. unsafe {
  2410. fixed (byte* pinnedBuffer = info.ProtocolInformation) {
  2411. errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSADuplicateSocket(m_Handle, (uint)targetProcessId, pinnedBuffer);
  2412. }
  2413. }
  2414. #else
  2415. errorCode = SocketError.SocketError;
  2416. #endif // !FEATURE_PAL
  2417. if (errorCode!=SocketError.Success) {
  2418. SocketException socketException = new SocketException();
  2419. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "DuplicateAndClose", socketException);
  2420. throw socketException;
  2421. }
  2422. info.IsConnected = Connected;
  2423. info.IsNonBlocking = !Blocking;
  2424. info.IsListening = isListening;
  2425. info.UseOnlyOverlappedIO = UseOnlyOverlappedIO;
  2426. info.RemoteEndPoint = m_RemoteEndPoint;
  2427. //make sure we don't shutdown, etc.
  2428. Close(-1);
  2429. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "DuplicateAndClose", null);
  2430. return info;
  2431. }
  2432. internal IAsyncResult UnsafeBeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)
  2433. {
  2434. if (CanUseConnectEx(remoteEP))
  2435. {
  2436. return BeginConnectEx(remoteEP, false, callback, state);
  2437. }
  2438. EndPoint endPointSnapshot = remoteEP;
  2439. SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
  2440. // No context flow here. Can use Lazy.
  2441. ConnectAsyncResult asyncResult = new ConnectAsyncResult(this, endPointSnapshot, state, callback);
  2442. DoBeginConnect(endPointSnapshot, socketAddress, asyncResult);
  2443. return asyncResult;
  2444. }
  2445. // Leaving the public logging as "BeginConnect" since that makes sense to the people looking at the output.
  2446. // Private logging can remain "DoBeginConnect".
  2447. private void DoBeginConnect(EndPoint endPointSnapshot, SocketAddress socketAddress, LazyAsyncResult asyncResult)
  2448. {
  2449. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() endPointSnapshot:" + endPointSnapshot.ToString());
  2450. EndPoint oldEndPoint = m_RightEndPoint;
  2451. // get async going
  2452. if (m_AcceptQueueOrConnectResult != null)
  2453. {
  2454. throw new InvalidOperationException(SR.GetString(SR.net_sockets_no_duplicate_async));
  2455. }
  2456. m_AcceptQueueOrConnectResult = asyncResult;
  2457. if (!SetAsyncEventSelect(AsyncEventBits.FdConnect)){
  2458. m_AcceptQueueOrConnectResult = null;
  2459. throw new ObjectDisposedException(this.GetType().FullName);
  2460. }
  2461. // This can throw ObjectDisposedException.
  2462. IntPtr handle = m_Handle.DangerousGetHandle();
  2463. //we should fix this in Whidbey.
  2464. if (m_RightEndPoint == null) {
  2465. m_RightEndPoint = endPointSnapshot;
  2466. }
  2467. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAConnect(
  2468. handle,
  2469. socketAddress.m_Buffer,
  2470. socketAddress.m_Size,
  2471. IntPtr.Zero,
  2472. IntPtr.Zero,
  2473. IntPtr.Zero,
  2474. IntPtr.Zero);
  2475. if (errorCode!=SocketError.Success) {
  2476. errorCode = (SocketError)Marshal.GetLastWin32Error();
  2477. }
  2478. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() UnsafeNclNativeMethods.OSSOCK.WSAConnect returns errorCode:" + errorCode);
  2479. if (errorCode != SocketError.WouldBlock)
  2480. {
  2481. bool completeSynchronously = true;
  2482. if (errorCode == SocketError.Success)
  2483. {
  2484. SetToConnected();
  2485. }
  2486. else
  2487. {
  2488. asyncResult.ErrorCode = (int) errorCode;
  2489. }
  2490. // Using interlocked to avoid a race condition with RegisteredWaitCallback
  2491. // Although UnsetAsyncEventSelect() below should cancel the callback, but
  2492. // it may already be in progress and therefore resulting in simultaneous
  2493. // registeredWaitCallback calling ConnectCallback() and the synchronous
  2494. // completion here.
  2495. if (Interlocked.Exchange(ref m_RegisteredWait, null) == null)
  2496. completeSynchronously = false;
  2497. //
  2498. // Cancel async event and go back to blocking mode.
  2499. //
  2500. UnsetAsyncEventSelect();
  2501. if (errorCode == SocketError.Success)
  2502. {
  2503. //
  2504. // synchronously complete the IO and call the user's callback.
  2505. //
  2506. if (completeSynchronously)
  2507. asyncResult.InvokeCallback();
  2508. }
  2509. else
  2510. {
  2511. //
  2512. // if the asynchronous native call fails synchronously
  2513. // we'll throw a SocketException
  2514. //
  2515. m_RightEndPoint = oldEndPoint;
  2516. SocketException socketException = new SocketException(errorCode);
  2517. UpdateStatusAfterSocketError(socketException);
  2518. m_AcceptQueueOrConnectResult = null;
  2519. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginConnect", socketException);
  2520. throw socketException;
  2521. }
  2522. }
  2523. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() to:" + endPointSnapshot.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  2524. }
  2525. // Begin ConnectEx is only supported for connection oriented protocols
  2526. // for now this is only supported on win32 platforms. We need to fix this
  2527. // when the getdelegatefrom function methods are available on 64bit.
  2528. // to use this, the endpoint must either be an IP endpoint, or the
  2529. // socket must already be bound.
  2530. private bool CanUseConnectEx(EndPoint remoteEP)
  2531. {
  2532. #if !FEATURE_PAL
  2533. return socketType == SocketType.Stream &&
  2534. (m_RightEndPoint != null || remoteEP.GetType() == typeof(IPEndPoint)) &&
  2535. (Thread.CurrentThread.IsThreadPoolThread || SettingsSectionInternal.Section.AlwaysUseCompletionPortsForConnect || m_IsDisconnected);
  2536. #else
  2537. return false;
  2538. #endif
  2539. }
  2540. //
  2541. // This is the internal callback that will be called when
  2542. // the IO we issued for the user to winsock has completed.
  2543. // when this function gets called it must:
  2544. // 1) update the AsyncResult object with the results of the completed IO
  2545. // 2) signal events that the user might be waiting on
  2546. // 3) call the callback function that the user might have specified
  2547. //
  2548. // This method was copied from a ConnectAsyncResult class that became useless.
  2549. private void ConnectCallback()
  2550. {
  2551. LazyAsyncResult asyncResult = (LazyAsyncResult) m_AcceptQueueOrConnectResult;
  2552. GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback");
  2553. //
  2554. // If we came here due to a ---- between BeginConnect and Dispose
  2555. //
  2556. if (asyncResult.InternalPeekCompleted)
  2557. {
  2558. GlobalLog.Assert(CleanedUp, "Socket#{0}::ConnectCallback()|asyncResult is compelted but the socket does not have CleanedUp set.", ValidationHelper.HashString(this));
  2559. GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback", "Already completed, socket must be closed");
  2560. return;
  2561. }
  2562. //<
  2563. //
  2564. // get async completion
  2565. //
  2566. /*
  2567. int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
  2568. GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString());
  2569. */
  2570. NetworkEvents networkEvents = new NetworkEvents();
  2571. networkEvents.Events = AsyncEventBits.FdConnect;
  2572. SocketError errorCode = SocketError.OperationAborted;
  2573. object result = null;
  2574. try
  2575. {
  2576. if (!CleanedUp)
  2577. {
  2578. try
  2579. {
  2580. errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents(
  2581. m_Handle,
  2582. m_AsyncEvent.SafeWaitHandle,
  2583. ref networkEvents);
  2584. if (errorCode != SocketError.Success)
  2585. {
  2586. errorCode = (SocketError) Marshal.GetLastWin32Error();
  2587. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString());
  2588. }
  2589. else
  2590. {
  2591. errorCode = (SocketError) networkEvents.ErrorCodes[(int) AsyncEventBitsPos.FdConnectBit];
  2592. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString());
  2593. }
  2594. //
  2595. // Cancel async event and go back to blocking mode.
  2596. //
  2597. UnsetAsyncEventSelect();
  2598. }
  2599. catch (ObjectDisposedException)
  2600. {
  2601. errorCode = SocketError.OperationAborted;
  2602. }
  2603. }
  2604. //
  2605. // if the native non-blocking call failed we'll throw a SocketException in EndConnect()
  2606. //
  2607. if (errorCode == SocketError.Success)
  2608. {
  2609. //
  2610. // the Socket is connected, update our state and performance counter
  2611. //
  2612. SetToConnected();
  2613. }
  2614. }
  2615. catch (Exception exception)
  2616. {
  2617. if (NclUtilities.IsFatal(exception)) throw;
  2618. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() caught exception:" + exception.Message + ", CleanedUp:" + CleanedUp);
  2619. result = exception;
  2620. }
  2621. if (!asyncResult.InternalPeekCompleted)
  2622. {
  2623. // A "ErrorCode" concept is questionable, for ex. below lines are subject to a race condition
  2624. asyncResult.ErrorCode = (int) errorCode;
  2625. asyncResult.InvokeCallback(result);
  2626. }
  2627. GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback", errorCode.ToString());
  2628. }
  2629. [HostProtection(ExternalThreading=true)]
  2630. public IAsyncResult BeginConnect(string host, int port, AsyncCallback requestCallback, object state){
  2631. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", host);
  2632. if (CleanedUp){
  2633. throw new ObjectDisposedException(this.GetType().FullName);
  2634. }
  2635. if (host==null) {
  2636. throw new ArgumentNullException("host");
  2637. }
  2638. if (!ValidationHelper.ValidateTcpPort(port)){
  2639. throw new ArgumentOutOfRangeException("port");
  2640. }
  2641. if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
  2642. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  2643. }
  2644. if (isListening)
  2645. {
  2646. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
  2647. }
  2648. // Here, want to flow the context. No need to lock.
  2649. MultipleAddressConnectAsyncResult result = new MultipleAddressConnectAsyncResult(null, port, this, state, requestCallback);
  2650. result.StartPostingAsyncOp(false);
  2651. IAsyncResult dnsResult = Dns.UnsafeBeginGetHostAddresses(host, new AsyncCallback(DnsCallback), result);
  2652. if (dnsResult.CompletedSynchronously)
  2653. {
  2654. if (DoDnsCallback(dnsResult, result))
  2655. {
  2656. result.InvokeCallback();
  2657. }
  2658. }
  2659. // Done posting.
  2660. result.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
  2661. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
  2662. return result;
  2663. }
  2664. #endif // !MONO
  2665. [HostProtection(ExternalThreading=true)]
  2666. public IAsyncResult BeginConnect(IPAddress address, int port, AsyncCallback requestCallback, object state){
  2667. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", address);
  2668. if (CleanedUp){
  2669. throw new ObjectDisposedException(this.GetType().FullName);
  2670. }
  2671. if (address==null) {
  2672. throw new ArgumentNullException("address");
  2673. }
  2674. if (!ValidationHelper.ValidateTcpPort(port)){
  2675. throw new ArgumentOutOfRangeException("port");
  2676. }
  2677. //if address family isn't the socket address family throw
  2678. if (!CanTryAddressFamily(address.AddressFamily)) {
  2679. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  2680. }
  2681. IAsyncResult result = BeginConnect(new IPEndPoint(address,port),requestCallback,state);
  2682. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
  2683. return result;
  2684. }
  2685. #if !MONO
  2686. [HostProtection(ExternalThreading=true)]
  2687. public IAsyncResult BeginConnect(IPAddress[] addresses, int port, AsyncCallback requestCallback, object state)
  2688. {
  2689. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", addresses);
  2690. if (CleanedUp){
  2691. throw new ObjectDisposedException(this.GetType().FullName);
  2692. }
  2693. if (addresses==null) {
  2694. throw new ArgumentNullException("addresses");
  2695. }
  2696. if (addresses.Length == 0) {
  2697. throw new ArgumentException(SR.GetString(SR.net_invalidAddressList), "addresses");
  2698. }
  2699. if (!ValidationHelper.ValidateTcpPort(port)) {
  2700. throw new ArgumentOutOfRangeException("port");
  2701. }
  2702. if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
  2703. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  2704. }
  2705. if (isListening)
  2706. {
  2707. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
  2708. }
  2709. // Set up the result to capture the context. No need for a lock.
  2710. MultipleAddressConnectAsyncResult result = new MultipleAddressConnectAsyncResult(addresses, port, this, state, requestCallback);
  2711. result.StartPostingAsyncOp(false);
  2712. if (DoMultipleAddressConnectCallback(PostOneBeginConnect(result), result))
  2713. {
  2714. // if it completes synchronously, invoke the callback from here
  2715. result.InvokeCallback();
  2716. }
  2717. // Finished posting async op. Possibly will call callback.
  2718. result.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
  2719. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
  2720. return result;
  2721. }
  2722. // Supports DisconnectEx - this provides completion port IO and support for
  2723. //disconnect and reconnects
  2724. [HostProtection(ExternalThreading=true)]
  2725. public IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback callback, object state)
  2726. {
  2727. // Start context-flowing op. No need to lock - we don't use the context till the callback.
  2728. DisconnectOverlappedAsyncResult asyncResult = new DisconnectOverlappedAsyncResult(this, state, callback);
  2729. asyncResult.StartPostingAsyncOp(false);
  2730. // Post the disconnect.
  2731. DoBeginDisconnect(reuseSocket, asyncResult);
  2732. // Finish flowing (or call the callback), and return.
  2733. asyncResult.FinishPostingAsyncOp();
  2734. return asyncResult;
  2735. }
  2736. private void DoBeginDisconnect(bool reuseSocket, DisconnectOverlappedAsyncResult asyncResult)
  2737. {
  2738. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginDisconnect",null);
  2739. if (CleanedUp) {
  2740. throw new ObjectDisposedException(this.GetType().FullName);
  2741. }
  2742. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() ");
  2743. #if FEATURE_PAL && !MONO
  2744. throw new PlatformNotSupportedException(SR.GetString(SR.WinXPRequired));
  2745. #endif
  2746. asyncResult.SetUnmanagedStructures(null);
  2747. SocketError errorCode=SocketError.Success;
  2748. // This can throw ObjectDisposedException (handle, and retrieving the delegate).
  2749. if (!DisconnectEx(m_Handle,asyncResult.OverlappedHandle, (int)(reuseSocket?TransmitFileOptions.ReuseSocket:0),0)) {
  2750. errorCode = (SocketError)Marshal.GetLastWin32Error();
  2751. }
  2752. if (errorCode == SocketError.Success) {
  2753. SetToDisconnected();
  2754. m_RemoteEndPoint = null;
  2755. }
  2756. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() UnsafeNclNativeMethods.OSSOCK.DisConnectEx returns:" + errorCode.ToString());
  2757. // if the asynchronous native call fails synchronously
  2758. // we'll throw a SocketException
  2759. //
  2760. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  2761. if (errorCode!= SocketError.Success) {
  2762. //
  2763. // update our internal state after this socket error and throw
  2764. //
  2765. SocketException socketException = new SocketException(errorCode);
  2766. UpdateStatusAfterSocketError(socketException);
  2767. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"BeginDisconnect", socketException);
  2768. throw socketException;
  2769. }
  2770. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  2771. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginDisconnect", asyncResult);
  2772. }
  2773. // Supports DisconnectEx - this provides support for disconnect and reconnects
  2774. public void Disconnect(bool reuseSocket) {
  2775. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Disconnect",null);
  2776. if (CleanedUp) {
  2777. throw new ObjectDisposedException(this.GetType().FullName);
  2778. }
  2779. #if FEATURE_PAL && !MONO
  2780. throw new PlatformNotSupportedException(SR.GetString(SR.WinXPRequired));
  2781. #endif // FEATURE_PAL && !MONO
  2782. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Disconnect() ");
  2783. SocketError errorCode = SocketError.Success;
  2784. // This can throw ObjectDisposedException (handle, and retrieving the delegate).
  2785. if (!DisconnectEx_Blocking(m_Handle.DangerousGetHandle(), IntPtr.Zero, (int) (reuseSocket ? TransmitFileOptions.ReuseSocket : 0), 0))
  2786. {
  2787. errorCode = (SocketError)Marshal.GetLastWin32Error();
  2788. }
  2789. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Disconnect() UnsafeNclNativeMethods.OSSOCK.DisConnectEx returns:" + errorCode.ToString());
  2790. if (errorCode!= SocketError.Success) {
  2791. //
  2792. // update our internal state after this socket error and throw
  2793. //
  2794. SocketException socketException = new SocketException(errorCode);
  2795. UpdateStatusAfterSocketError(socketException);
  2796. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"Disconnect", socketException);
  2797. throw socketException;
  2798. }
  2799. SetToDisconnected();
  2800. m_RemoteEndPoint = null;
  2801. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Disconnect", null);
  2802. }
  2803. /*++
  2804. Routine Description:
  2805. EndConnect - Called addressFamilyter receiving callback from BeginConnect,
  2806. in order to retrive the result of async call
  2807. Arguments:
  2808. AsyncResult - the AsyncResult Returned fron BeginConnect call
  2809. Return Value:
  2810. int - Return code from aync Connect, 0 for success, SocketError.NotConnected otherwise
  2811. --*/
  2812. /// <devdoc>
  2813. /// <para>[To be supplied.]</para>
  2814. /// </devdoc>
  2815. public void EndConnect(IAsyncResult asyncResult) {
  2816. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndConnect", asyncResult);
  2817. if (CleanedUp) {
  2818. throw new ObjectDisposedException(this.GetType().FullName);
  2819. }
  2820. //
  2821. // parameter validation
  2822. //
  2823. if (asyncResult==null) {
  2824. throw new ArgumentNullException("asyncResult");
  2825. }
  2826. LazyAsyncResult castedAsyncResult = null;
  2827. EndPoint remoteEndPoint = null;
  2828. ConnectOverlappedAsyncResult coar;
  2829. MultipleAddressConnectAsyncResult macar;
  2830. ConnectAsyncResult car;
  2831. coar = asyncResult as ConnectOverlappedAsyncResult;
  2832. if (coar == null) {
  2833. macar = asyncResult as MultipleAddressConnectAsyncResult;
  2834. if (macar == null) {
  2835. car = asyncResult as ConnectAsyncResult;
  2836. if (car != null) {
  2837. remoteEndPoint = car.RemoteEndPoint;
  2838. castedAsyncResult = car;
  2839. }
  2840. } else {
  2841. remoteEndPoint = macar.RemoteEndPoint;
  2842. castedAsyncResult = macar;
  2843. }
  2844. } else {
  2845. remoteEndPoint = coar.RemoteEndPoint;
  2846. castedAsyncResult = coar;
  2847. }
  2848. if (castedAsyncResult == null || castedAsyncResult.AsyncObject!=this) {
  2849. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  2850. }
  2851. if (castedAsyncResult.EndCalled) {
  2852. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndConnect"));
  2853. }
  2854. castedAsyncResult.InternalWaitForCompletion();
  2855. castedAsyncResult.EndCalled = true;
  2856. m_AcceptQueueOrConnectResult = null;
  2857. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndConnect() asyncResult:" + ValidationHelper.HashString(asyncResult));
  2858. if (castedAsyncResult.Result is Exception) {
  2859. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndConnect", (Exception)castedAsyncResult.Result);
  2860. throw (Exception)castedAsyncResult.Result;
  2861. }
  2862. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
  2863. //
  2864. // update our internal state after this socket error and throw
  2865. //
  2866. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode, remoteEndPoint);
  2867. UpdateStatusAfterSocketError(socketException);
  2868. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndConnect", socketException);
  2869. throw socketException;
  2870. }
  2871. if (s_LoggingEnabled) {
  2872. Logging.PrintInfo(Logging.Sockets, this, SR.GetString(SR.net_log_socket_connected, LocalEndPoint, RemoteEndPoint));
  2873. Logging.Exit(Logging.Sockets, this, "EndConnect", "");
  2874. }
  2875. }
  2876. public void EndDisconnect(IAsyncResult asyncResult) {
  2877. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndDisconnect", asyncResult);
  2878. if (CleanedUp) {
  2879. throw new ObjectDisposedException(this.GetType().FullName);
  2880. }
  2881. #if FEATURE_PAL && !MONO
  2882. throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
  2883. #endif // FEATURE_PAL && !MONO
  2884. if (asyncResult==null) {
  2885. throw new ArgumentNullException("asyncResult");
  2886. }
  2887. //get async result and check for errors
  2888. LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
  2889. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  2890. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  2891. }
  2892. if (castedAsyncResult.EndCalled) {
  2893. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndDisconnect"));
  2894. }
  2895. //wait for completion if it hasn't occured
  2896. castedAsyncResult.InternalWaitForCompletion();
  2897. castedAsyncResult.EndCalled = true;
  2898. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndDisconnect()");
  2899. //
  2900. // if the asynchronous native call failed asynchronously
  2901. // we'll throw a SocketException
  2902. //
  2903. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
  2904. //
  2905. // update our internal state after this socket error and throw
  2906. //
  2907. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
  2908. UpdateStatusAfterSocketError(socketException);
  2909. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"EndDisconnect", socketException);
  2910. throw socketException;
  2911. }
  2912. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndDisconnect", null);
  2913. return;
  2914. }
  2915. #endif // !MONO
  2916. /*++
  2917. Routine Description:
  2918. BeginSend - Async implimentation of Send call, mirrored addressFamilyter BeginReceive
  2919. This routine may go pending at which time,
  2920. but any case the callback Delegate will be called upon completion
  2921. Arguments:
  2922. WriteBuffer - status line that we wish to parse
  2923. Index - Offset into WriteBuffer to begin sending from
  2924. Size - Size of Buffer to transmit
  2925. Callback - Delegate function that holds callback, called on completeion of I/O
  2926. State - State used to track callback, set by caller, not required
  2927. Return Value:
  2928. IAsyncResult - Async result used to retreive result
  2929. --*/
  2930. /// <devdoc>
  2931. /// <para>[To be supplied.]</para>
  2932. /// </devdoc>
  2933. [HostProtection(ExternalThreading=true)]
  2934. public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
  2935. {
  2936. SocketError errorCode;
  2937. IAsyncResult result = BeginSend(buffer, offset, size, socketFlags, out errorCode, callback, state);
  2938. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  2939. throw new SocketException(errorCode);
  2940. }
  2941. return result;
  2942. }
  2943. #if !MONO
  2944. [HostProtection(ExternalThreading=true)]
  2945. public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
  2946. {
  2947. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSend", "");
  2948. if (CleanedUp) {
  2949. throw new ObjectDisposedException(this.GetType().FullName);
  2950. }
  2951. //
  2952. // parameter validation
  2953. //
  2954. if (buffer == null)
  2955. {
  2956. throw new ArgumentNullException("buffer");
  2957. }
  2958. if (offset < 0 || offset > buffer.Length)
  2959. {
  2960. throw new ArgumentOutOfRangeException("offset");
  2961. }
  2962. if (size < 0 || size > buffer.Length - offset)
  2963. {
  2964. throw new ArgumentOutOfRangeException("size");
  2965. }
  2966. // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
  2967. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  2968. asyncResult.StartPostingAsyncOp(false);
  2969. // Run the send with this asyncResult.
  2970. errorCode = DoBeginSend(buffer, offset, size, socketFlags, asyncResult);
  2971. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  2972. asyncResult = null;
  2973. }
  2974. else
  2975. {
  2976. // We're not throwing, so finish the async op posting code so we can return to the user.
  2977. // If the operation already finished, the callback will be called from here.
  2978. asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
  2979. }
  2980. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSend", asyncResult);
  2981. return asyncResult;
  2982. }
  2983. internal IAsyncResult UnsafeBeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
  2984. {
  2985. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "UnsafeBeginSend", "");
  2986. if (CleanedUp) {
  2987. throw new ObjectDisposedException(this.GetType().FullName);
  2988. }
  2989. // No need to flow the context.
  2990. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  2991. SocketError errorCode = DoBeginSend(buffer, offset, size, socketFlags, asyncResult);
  2992. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  2993. throw new SocketException(errorCode);
  2994. }
  2995. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "UnsafeBeginSend", asyncResult);
  2996. return asyncResult;
  2997. }
  2998. private SocketError DoBeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
  2999. {
  3000. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size.ToString());
  3001. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  3002. // avoid a Socket leak in case of error.
  3003. SocketError errorCode = SocketError.SocketError;
  3004. try
  3005. {
  3006. // Set up asyncResult for overlapped WSASend.
  3007. // This call will use completion ports on WinNT and Overlapped IO on Win9x.
  3008. asyncResult.SetUnmanagedStructures(buffer, offset, size, null, false /*don't pin null remoteEP*/, ref Caches.SendOverlappedCache);
  3009. //
  3010. // Get the Send going.
  3011. //
  3012. GlobalLog.Print("BeginSend: asyncResult:" + ValidationHelper.HashString(asyncResult) + " size:" + size.ToString());
  3013. int bytesTransferred;
  3014. // This can throw ObjectDisposedException.
  3015. errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
  3016. m_Handle,
  3017. ref asyncResult.m_SingleBuffer,
  3018. 1, // only ever 1 buffer being sent
  3019. out bytesTransferred,
  3020. socketFlags,
  3021. asyncResult.OverlappedHandle,
  3022. IntPtr.Zero);
  3023. if (errorCode!=SocketError.Success) {
  3024. errorCode = (SocketError)Marshal.GetLastWin32Error();
  3025. }
  3026. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  3027. }
  3028. finally
  3029. {
  3030. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  3031. }
  3032. //
  3033. // if the asynchronous native call fails synchronously
  3034. // we'll throw a SocketException
  3035. //
  3036. if (errorCode != SocketError.Success)
  3037. {
  3038. asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  3039. UpdateStatusAfterSocketError(errorCode);
  3040. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSend", new SocketException(errorCode));
  3041. }
  3042. return errorCode;
  3043. }
  3044. /// <devdoc>
  3045. /// <para>[To be supplied.]</para>
  3046. /// </devdoc>
  3047. #if !FEATURE_PAL
  3048. [HostProtection(ExternalThreading=true)]
  3049. [ResourceExposure(ResourceScope.Machine)]
  3050. [ResourceConsumption(ResourceScope.Machine)]
  3051. public IAsyncResult BeginSendFile(
  3052. string fileName,
  3053. byte[] preBuffer,
  3054. byte[] postBuffer,
  3055. TransmitFileOptions flags,
  3056. AsyncCallback callback,
  3057. object state)
  3058. {
  3059. // Start the context flowing. No lock necessary.
  3060. TransmitFileOverlappedAsyncResult asyncResult = new TransmitFileOverlappedAsyncResult(this,state,callback);
  3061. asyncResult.StartPostingAsyncOp(false);
  3062. // Start the operation.
  3063. DoBeginSendFile(fileName, preBuffer, postBuffer, flags, asyncResult);
  3064. // Finish the op, collect the context or maybe call the callback.
  3065. asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
  3066. return asyncResult;
  3067. }
  3068. [ResourceExposure(ResourceScope.Machine)]
  3069. [ResourceConsumption(ResourceScope.Machine)]
  3070. private void DoBeginSendFile(
  3071. string fileName,
  3072. byte[] preBuffer,
  3073. byte[] postBuffer,
  3074. TransmitFileOptions flags,
  3075. TransmitFileOverlappedAsyncResult asyncResult)
  3076. {
  3077. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSendFile", "");
  3078. if (CleanedUp) {
  3079. throw new ObjectDisposedException(this.GetType().FullName);
  3080. }
  3081. if (CleanedUp) {
  3082. throw new ObjectDisposedException(this.GetType().FullName);
  3083. }
  3084. #if FEATURE_PAL && !MONO
  3085. throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
  3086. #endif // FEATURE_PAL && !MONO
  3087. if (!Connected) {
  3088. throw new NotSupportedException(SR.GetString(SR.net_notconnected));
  3089. }
  3090. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " fileName:" + fileName);
  3091. FileStream fileStream = null;
  3092. if (fileName != null && fileName.Length>0) {
  3093. fileStream = new FileStream(fileName,FileMode.Open,FileAccess.Read,FileShare.Read);
  3094. }
  3095. SafeHandle fileHandle = null;
  3096. if (fileStream != null) {
  3097. ExceptionHelper.UnmanagedPermission.Assert();
  3098. try {
  3099. fileHandle = fileStream.SafeFileHandle;
  3100. }
  3101. finally {
  3102. SecurityPermission.RevertAssert();
  3103. }
  3104. }
  3105. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  3106. // avoid a Socket leak in case of error.
  3107. SocketError errorCode = SocketError.SocketError;
  3108. try
  3109. {
  3110. asyncResult.SetUnmanagedStructures(preBuffer, postBuffer, fileStream, flags, ref Caches.SendOverlappedCache);
  3111. bool result = false;
  3112. // This can throw ObjectDisposedException.
  3113. if (fileHandle != null){
  3114. result = UnsafeNclNativeMethods.OSSOCK.TransmitFile(m_Handle,fileHandle,0,0,asyncResult.OverlappedHandle,asyncResult.TransmitFileBuffers,flags);
  3115. }
  3116. else{
  3117. result = UnsafeNclNativeMethods.OSSOCK.TransmitFile2(m_Handle,IntPtr.Zero,0,0,asyncResult.OverlappedHandle,asyncResult.TransmitFileBuffers,flags);
  3118. }
  3119. if(!result)
  3120. {
  3121. errorCode = (SocketError)Marshal.GetLastWin32Error();
  3122. }
  3123. else
  3124. {
  3125. errorCode = SocketError.Success;
  3126. }
  3127. }
  3128. finally
  3129. {
  3130. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  3131. }
  3132. //
  3133. // if the native call fails we'll throw a SocketException
  3134. //
  3135. if (errorCode!=SocketError.Success) {
  3136. //
  3137. // update our internal state after this socket error and throw
  3138. //
  3139. asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  3140. SocketException socketException = new SocketException(errorCode);
  3141. UpdateStatusAfterSocketError(socketException);
  3142. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSendFile", socketException);
  3143. throw socketException;
  3144. }
  3145. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendFile() UnsafeNclNativeMethods.OSSOCK.send returns:" + errorCode.ToString());
  3146. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSendFile", errorCode);
  3147. }
  3148. #endif // !FEATURE_PAL
  3149. #endif // !MONO
  3150. /// <devdoc>
  3151. /// <para>[To be supplied.]</para>
  3152. /// </devdoc>
  3153. [HostProtection(ExternalThreading=true)]
  3154. public IAsyncResult BeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
  3155. {
  3156. SocketError errorCode;
  3157. IAsyncResult result = BeginSend(buffers, socketFlags, out errorCode, callback, state);
  3158. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  3159. throw new SocketException(errorCode);
  3160. }
  3161. return result;
  3162. }
  3163. #if !MONO
  3164. [HostProtection(ExternalThreading=true)]
  3165. public IAsyncResult BeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
  3166. {
  3167. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSend", "");
  3168. if (CleanedUp) {
  3169. throw new ObjectDisposedException(this.GetType().FullName);
  3170. }
  3171. //
  3172. // parameter validation
  3173. //
  3174. if (buffers==null) {
  3175. throw new ArgumentNullException("buffers");
  3176. }
  3177. if(buffers.Count == 0){
  3178. throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
  3179. }
  3180. // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
  3181. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  3182. asyncResult.StartPostingAsyncOp(false);
  3183. // Run the send with this asyncResult.
  3184. errorCode = DoBeginSend(buffers, socketFlags, asyncResult);
  3185. // We're not throwing, so finish the async op posting code so we can return to the user.
  3186. // If the operation already finished, the callback will be called from here.
  3187. asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
  3188. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  3189. asyncResult = null;
  3190. }
  3191. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSend", asyncResult);
  3192. return asyncResult;
  3193. }
  3194. private SocketError DoBeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
  3195. {
  3196. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " buffers:" + buffers);
  3197. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  3198. // avoid a Socket leak in case of error.
  3199. SocketError errorCode = SocketError.SocketError;
  3200. try
  3201. {
  3202. // Set up asyncResult for overlapped WSASend.
  3203. // This call will use completion ports on WinNT and Overlapped IO on Win9x.
  3204. asyncResult.SetUnmanagedStructures(buffers, ref Caches.SendOverlappedCache);
  3205. GlobalLog.Print("BeginSend: asyncResult:" + ValidationHelper.HashString(asyncResult));
  3206. // This can throw ObjectDisposedException.
  3207. int bytesTransferred;
  3208. errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
  3209. m_Handle,
  3210. asyncResult.m_WSABuffers,
  3211. asyncResult.m_WSABuffers.Length,
  3212. out bytesTransferred,
  3213. socketFlags,
  3214. asyncResult.OverlappedHandle,
  3215. IntPtr.Zero);
  3216. if (errorCode!=SocketError.Success) {
  3217. errorCode = (SocketError)Marshal.GetLastWin32Error();
  3218. }
  3219. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  3220. }
  3221. finally
  3222. {
  3223. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  3224. }
  3225. //
  3226. // if the asynchronous native call fails synchronously
  3227. // we'll throw a SocketException
  3228. //
  3229. if (errorCode != SocketError.Success)
  3230. {
  3231. asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  3232. UpdateStatusAfterSocketError(errorCode);
  3233. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSend", new SocketException(errorCode));
  3234. }
  3235. return errorCode;
  3236. }
  3237. #endif // !MONO
  3238. /*++
  3239. Routine Description:
  3240. EndSend - Called by user code addressFamilyter I/O is done or the user wants to wait.
  3241. until Async completion, needed to retrieve error result from call
  3242. Arguments:
  3243. AsyncResult - the AsyncResult Returned fron BeginSend call
  3244. Return Value:
  3245. int - Number of bytes transferred
  3246. --*/
  3247. /// <devdoc>
  3248. /// <para>[To be supplied.]</para>
  3249. /// </devdoc>
  3250. public int EndSend(IAsyncResult asyncResult) {
  3251. SocketError errorCode;
  3252. int bytesTransferred = EndSend(asyncResult, out errorCode);
  3253. if(errorCode != SocketError.Success){
  3254. throw new SocketException(errorCode);
  3255. }
  3256. return bytesTransferred;
  3257. }
  3258. #if !MONO
  3259. public int EndSend(IAsyncResult asyncResult, out SocketError errorCode) {
  3260. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSend", asyncResult);
  3261. if (CleanedUp) {
  3262. throw new ObjectDisposedException(this.GetType().FullName);
  3263. }
  3264. //
  3265. // parameter validation
  3266. //
  3267. if (asyncResult==null) {
  3268. throw new ArgumentNullException("asyncResult");
  3269. }
  3270. OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
  3271. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  3272. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  3273. }
  3274. if (castedAsyncResult.EndCalled) {
  3275. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSend"));
  3276. }
  3277. int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
  3278. castedAsyncResult.EndCalled = true;
  3279. castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  3280. #if !FEATURE_PAL // perfcounter
  3281. if (s_PerfCountersEnabled)
  3282. {
  3283. if (bytesTransferred>0) {
  3284. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
  3285. if (Transport==TransportType.Udp) {
  3286. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
  3287. }
  3288. }
  3289. }
  3290. #endif //!FEATURE_PAL
  3291. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSend() bytesTransferred:" + bytesTransferred.ToString());
  3292. //
  3293. // if the asynchronous native call failed asynchronously
  3294. // we'll throw a SocketException
  3295. //
  3296. errorCode = (SocketError)castedAsyncResult.ErrorCode;
  3297. if (errorCode != SocketError.Success) {
  3298. //
  3299. // update our internal state after this socket error and throw
  3300. //
  3301. UpdateStatusAfterSocketError(errorCode);
  3302. if(s_LoggingEnabled){
  3303. Logging.Exception(Logging.Sockets, this, "EndSend", new SocketException(errorCode));
  3304. Logging.Exit(Logging.Sockets, this, "EndSend", 0);
  3305. }
  3306. return 0;
  3307. }
  3308. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSend", bytesTransferred);
  3309. return bytesTransferred;
  3310. }
  3311. #if !FEATURE_PAL
  3312. /// <devdoc>
  3313. /// <para>[To be supplied.]</para>
  3314. /// </devdoc>
  3315. public void EndSendFile(IAsyncResult asyncResult) {
  3316. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSendFile", asyncResult);
  3317. if (CleanedUp) {
  3318. throw new ObjectDisposedException(this.GetType().FullName);
  3319. }
  3320. #if FEATURE_PAL && !MONO
  3321. throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
  3322. #endif // FEATURE_PAL && !MONO
  3323. //
  3324. // parameter validation
  3325. //
  3326. if (asyncResult==null) {
  3327. throw new ArgumentNullException("asyncResult");
  3328. }
  3329. TransmitFileOverlappedAsyncResult castedAsyncResult = asyncResult as TransmitFileOverlappedAsyncResult;
  3330. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  3331. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  3332. }
  3333. if (castedAsyncResult.EndCalled) {
  3334. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSendFile"));
  3335. }
  3336. castedAsyncResult.InternalWaitForCompletion();
  3337. castedAsyncResult.EndCalled = true;
  3338. castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  3339. if ((castedAsyncResult.Flags & (TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket) )!=0) {
  3340. SetToDisconnected();
  3341. m_RemoteEndPoint = null;
  3342. }
  3343. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSendFile()");
  3344. //
  3345. // if the asynchronous native call failed asynchronously
  3346. // we'll throw a SocketException
  3347. //
  3348. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
  3349. //
  3350. // update our internal state after this socket error and throw
  3351. //
  3352. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
  3353. UpdateStatusAfterSocketError(socketException);
  3354. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndSendFile", socketException);
  3355. throw socketException;
  3356. }
  3357. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSendFile","");
  3358. }
  3359. #endif // !FEATURE_PAL
  3360. /*++
  3361. Routine Description:
  3362. BeginSendTo - Async implimentation of SendTo,
  3363. This routine may go pending at which time,
  3364. but any case the callback Delegate will be called upon completion
  3365. Arguments:
  3366. WriteBuffer - Buffer to transmit
  3367. Index - Offset into WriteBuffer to begin sending from
  3368. Size - Size of Buffer to transmit
  3369. Flags - Specific Socket flags to pass to winsock
  3370. remoteEP - EndPoint to transmit To
  3371. Callback - Delegate function that holds callback, called on completeion of I/O
  3372. State - State used to track callback, set by caller, not required
  3373. Return Value:
  3374. IAsyncResult - Async result used to retreive result
  3375. --*/
  3376. /// <devdoc>
  3377. /// <para>[To be supplied.]</para>
  3378. /// </devdoc>
  3379. [HostProtection(ExternalThreading=true)]
  3380. public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP, AsyncCallback callback, object state)
  3381. {
  3382. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSendTo", "");
  3383. if (CleanedUp) {
  3384. throw new ObjectDisposedException(this.GetType().FullName);
  3385. }
  3386. //
  3387. // parameter validation
  3388. //
  3389. if (buffer==null) {
  3390. throw new ArgumentNullException("buffer");
  3391. }
  3392. if (remoteEP==null) {
  3393. throw new ArgumentNullException("remoteEP");
  3394. }
  3395. if (offset<0 || offset>buffer.Length) {
  3396. throw new ArgumentOutOfRangeException("offset");
  3397. }
  3398. if (size<0 || size>buffer.Length-offset) {
  3399. throw new ArgumentOutOfRangeException("size");
  3400. }
  3401. // This will check the permissions for connect.
  3402. EndPoint endPointSnapshot = remoteEP;
  3403. SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, false);
  3404. // Set up the async result and indicate to flow the context.
  3405. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  3406. asyncResult.StartPostingAsyncOp(false);
  3407. // Post the send.
  3408. DoBeginSendTo(buffer, offset, size, socketFlags, endPointSnapshot, socketAddress, asyncResult);
  3409. // Finish, possibly posting the callback. The callback won't be posted before this point is reached.
  3410. asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
  3411. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSendTo", asyncResult);
  3412. return asyncResult;
  3413. }
  3414. private void DoBeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint endPointSnapshot, SocketAddress socketAddress, OverlappedAsyncResult asyncResult)
  3415. {
  3416. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() size:" + size.ToString());
  3417. EndPoint oldEndPoint = m_RightEndPoint;
  3418. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  3419. // avoid a Socket leak in case of error.
  3420. SocketError errorCode = SocketError.SocketError;
  3421. try
  3422. {
  3423. // Set up asyncResult for overlapped WSASendTo.
  3424. // This call will use completion ports on WinNT and Overlapped IO on Win9x.
  3425. asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, false /* don't pin RemoteEP*/, ref Caches.SendOverlappedCache);
  3426. if (m_RightEndPoint == null)
  3427. {
  3428. m_RightEndPoint = endPointSnapshot;
  3429. }
  3430. int bytesTransferred;
  3431. errorCode = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
  3432. m_Handle,
  3433. ref asyncResult.m_SingleBuffer,
  3434. 1, // only ever 1 buffer being sent
  3435. out bytesTransferred,
  3436. socketFlags,
  3437. asyncResult.GetSocketAddressPtr(),
  3438. asyncResult.SocketAddress.Size,
  3439. asyncResult.OverlappedHandle,
  3440. IntPtr.Zero);
  3441. if (errorCode!=SocketError.Success) {
  3442. errorCode = (SocketError)Marshal.GetLastWin32Error();
  3443. }
  3444. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + size + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  3445. }
  3446. catch (ObjectDisposedException)
  3447. {
  3448. m_RightEndPoint = oldEndPoint;
  3449. throw;
  3450. }
  3451. finally
  3452. {
  3453. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  3454. }
  3455. //
  3456. // if the asynchronous native call fails synchronously
  3457. // we'll throw a SocketException
  3458. //
  3459. if (errorCode!=SocketError.Success) {
  3460. //
  3461. // update our internal state after this socket error and throw
  3462. //
  3463. m_RightEndPoint = oldEndPoint;
  3464. asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  3465. SocketException socketException = new SocketException(errorCode);
  3466. UpdateStatusAfterSocketError(socketException);
  3467. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSendTo", socketException);
  3468. throw socketException;
  3469. }
  3470. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  3471. }
  3472. /*++
  3473. Routine Description:
  3474. EndSendTo - Called by user code addressFamilyter I/O is done or the user wants to wait.
  3475. until Async completion, needed to retrieve error result from call
  3476. Arguments:
  3477. AsyncResult - the AsyncResult Returned fron BeginSend call
  3478. Return Value:
  3479. int - Number of bytes transferred
  3480. --*/
  3481. /// <devdoc>
  3482. /// <para>[To be supplied.]</para>
  3483. /// </devdoc>
  3484. public int EndSendTo(IAsyncResult asyncResult) {
  3485. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSendTo", asyncResult);
  3486. if (CleanedUp) {
  3487. throw new ObjectDisposedException(this.GetType().FullName);
  3488. }
  3489. //
  3490. // parameter validation
  3491. //
  3492. if (asyncResult==null) {
  3493. throw new ArgumentNullException("asyncResult");
  3494. }
  3495. OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
  3496. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  3497. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  3498. }
  3499. if (castedAsyncResult.EndCalled) {
  3500. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSendTo"));
  3501. }
  3502. int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
  3503. castedAsyncResult.EndCalled = true;
  3504. castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  3505. #if !FEATURE_PAL // perfcounter
  3506. if (s_PerfCountersEnabled)
  3507. {
  3508. if (bytesTransferred>0) {
  3509. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
  3510. if (Transport==TransportType.Udp) {
  3511. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
  3512. }
  3513. }
  3514. }
  3515. #endif //!FEATURE_PAL
  3516. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSendTo() bytesTransferred:" + bytesTransferred.ToString());
  3517. //
  3518. // if the asynchronous native call failed asynchronously
  3519. // we'll throw a SocketException
  3520. //
  3521. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
  3522. //
  3523. // update our internal state after this socket error and throw
  3524. //
  3525. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
  3526. UpdateStatusAfterSocketError(socketException);
  3527. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndSendTo", socketException);
  3528. throw socketException;
  3529. }
  3530. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSendTo", bytesTransferred);
  3531. return bytesTransferred;
  3532. }
  3533. #endif // !MONO
  3534. /*++
  3535. Routine Description:
  3536. BeginReceive - Async implimentation of Recv call,
  3537. Called when we want to start an async receive.
  3538. We kick off the receive, and if it completes synchronously we'll
  3539. call the callback. Otherwise we'll return an IASyncResult, which
  3540. the caller can use to wait on or retrieve the final status, as needed.
  3541. Uses Winsock 2 overlapped I/O.
  3542. Arguments:
  3543. ReadBuffer - status line that we wish to parse
  3544. Index - Offset into ReadBuffer to begin reading from
  3545. Size - Size of Buffer to recv
  3546. Callback - Delegate function that holds callback, called on completeion of I/O
  3547. State - State used to track callback, set by caller, not required
  3548. Return Value:
  3549. IAsyncResult - Async result used to retreive result
  3550. --*/
  3551. /// <devdoc>
  3552. /// <para>[To be supplied.]</para>
  3553. /// </devdoc>
  3554. [HostProtection(ExternalThreading=true)]
  3555. public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
  3556. {
  3557. SocketError errorCode;
  3558. IAsyncResult result = BeginReceive(buffer, offset, size, socketFlags, out errorCode, callback, state);
  3559. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  3560. throw new SocketException(errorCode);
  3561. }
  3562. return result;
  3563. }
  3564. #if !MONO
  3565. [HostProtection(ExternalThreading=true)]
  3566. public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
  3567. {
  3568. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginReceive", "");
  3569. if (CleanedUp) {
  3570. throw new ObjectDisposedException(this.GetType().FullName);
  3571. }
  3572. //
  3573. // parameter validation
  3574. //
  3575. if (buffer==null) {
  3576. throw new ArgumentNullException("buffer");
  3577. }
  3578. if (offset<0 || offset>buffer.Length) {
  3579. throw new ArgumentOutOfRangeException("offset");
  3580. }
  3581. if (size<0 || size>buffer.Length-offset) {
  3582. throw new ArgumentOutOfRangeException("size");
  3583. }
  3584. // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
  3585. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  3586. asyncResult.StartPostingAsyncOp(false);
  3587. // Run the receive with this asyncResult.
  3588. errorCode = DoBeginReceive(buffer, offset, size, socketFlags, asyncResult);
  3589. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  3590. asyncResult = null;
  3591. }
  3592. else
  3593. {
  3594. // We're not throwing, so finish the async op posting code so we can return to the user.
  3595. // If the operation already finished, the callback will be called from here.
  3596. asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
  3597. }
  3598. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceive", asyncResult);
  3599. return asyncResult;
  3600. }
  3601. internal IAsyncResult UnsafeBeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
  3602. {
  3603. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "UnsafeBeginReceive", "");
  3604. if (CleanedUp) {
  3605. throw new ObjectDisposedException(this.GetType().FullName);
  3606. }
  3607. // No need to flow the context.
  3608. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  3609. DoBeginReceive(buffer, offset, size, socketFlags, asyncResult);
  3610. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "UnsafeBeginReceive", asyncResult);
  3611. return asyncResult;
  3612. }
  3613. private SocketError DoBeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
  3614. {
  3615. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() size:" + size.ToString());
  3616. #if DEBUG
  3617. IntPtr lastHandle = m_Handle.DangerousGetHandle();
  3618. #endif
  3619. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  3620. // avoid a Socket leak in case of error.
  3621. SocketError errorCode = SocketError.SocketError;
  3622. try
  3623. {
  3624. // Set up asyncResult for overlapped WSARecv.
  3625. // This call will use completion ports on WinNT and Overlapped IO on Win9x.
  3626. asyncResult.SetUnmanagedStructures(buffer, offset, size, null, false /* don't pin null RemoteEP*/, ref Caches.ReceiveOverlappedCache);
  3627. // This can throw ObjectDisposedException.
  3628. int bytesTransferred;
  3629. errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv(
  3630. m_Handle,
  3631. ref asyncResult.m_SingleBuffer,
  3632. 1,
  3633. out bytesTransferred,
  3634. ref socketFlags,
  3635. asyncResult.OverlappedHandle,
  3636. IntPtr.Zero);
  3637. if (errorCode!=SocketError.Success) {
  3638. errorCode = (SocketError)Marshal.GetLastWin32Error();
  3639. GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
  3640. }
  3641. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " bytesTransferred:" + bytesTransferred.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  3642. }
  3643. finally
  3644. {
  3645. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  3646. }
  3647. //
  3648. // if the asynchronous native call fails synchronously
  3649. // we'll throw a SocketException
  3650. //
  3651. if (errorCode != SocketError.Success)
  3652. {
  3653. //
  3654. // update our internal state after this socket error and throw
  3655. asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
  3656. UpdateStatusAfterSocketError(errorCode);
  3657. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
  3658. asyncResult.InvokeCallback(new SocketException(errorCode));
  3659. }
  3660. #if DEBUG
  3661. else
  3662. {
  3663. m_LastReceiveHandle = lastHandle;
  3664. m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
  3665. m_LastReceiveTick = Environment.TickCount;
  3666. }
  3667. #endif
  3668. return errorCode;
  3669. }
  3670. #endif // !MONO
  3671. [HostProtection(ExternalThreading=true)]
  3672. public IAsyncResult BeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
  3673. {
  3674. SocketError errorCode;
  3675. IAsyncResult result = BeginReceive(buffers, socketFlags, out errorCode, callback, state);
  3676. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  3677. throw new SocketException(errorCode);
  3678. }
  3679. return result;
  3680. }
  3681. #if !MONO
  3682. [HostProtection(ExternalThreading=true)]
  3683. public IAsyncResult BeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
  3684. {
  3685. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginReceive", "");
  3686. if (CleanedUp) {
  3687. throw new ObjectDisposedException(this.GetType().FullName);
  3688. }
  3689. //
  3690. // parameter validation
  3691. //
  3692. if (buffers==null) {
  3693. throw new ArgumentNullException("buffers");
  3694. }
  3695. if(buffers.Count == 0){
  3696. throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
  3697. }
  3698. // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
  3699. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  3700. asyncResult.StartPostingAsyncOp(false);
  3701. // Run the receive with this asyncResult.
  3702. errorCode = DoBeginReceive(buffers, socketFlags, asyncResult);
  3703. if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  3704. asyncResult = null;
  3705. }
  3706. else
  3707. {
  3708. // We're not throwing, so finish the async op posting code so we can return to the user.
  3709. // If the operation already finished, the callback will be called from here.
  3710. asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
  3711. }
  3712. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceive", asyncResult);
  3713. return asyncResult;
  3714. }
  3715. private SocketError DoBeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
  3716. {
  3717. #if DEBUG
  3718. IntPtr lastHandle = m_Handle.DangerousGetHandle();
  3719. #endif
  3720. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  3721. // avoid a Socket leak in case of error.
  3722. SocketError errorCode = SocketError.SocketError;
  3723. try
  3724. {
  3725. // Set up asyncResult for overlapped WSASend.
  3726. // This call will use completion ports on WinNT and Overlapped IO on Win9x.
  3727. asyncResult.SetUnmanagedStructures(buffers, ref Caches.ReceiveOverlappedCache);
  3728. // This can throw ObjectDisposedException.
  3729. int bytesTransferred;
  3730. errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv(
  3731. m_Handle,
  3732. asyncResult.m_WSABuffers,
  3733. asyncResult.m_WSABuffers.Length,
  3734. out bytesTransferred,
  3735. ref socketFlags,
  3736. asyncResult.OverlappedHandle,
  3737. IntPtr.Zero);
  3738. if (errorCode!=SocketError.Success) {
  3739. errorCode = (SocketError)Marshal.GetLastWin32Error();
  3740. GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
  3741. }
  3742. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  3743. }
  3744. finally
  3745. {
  3746. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  3747. }
  3748. //
  3749. // if the asynchronous native call fails synchronously
  3750. // we'll throw a SocketException
  3751. //
  3752. if (errorCode != SocketError.Success)
  3753. {
  3754. //
  3755. // update our internal state after this socket error and throw
  3756. asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
  3757. UpdateStatusAfterSocketError(errorCode);
  3758. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
  3759. }
  3760. #if DEBUG
  3761. else
  3762. {
  3763. m_LastReceiveHandle = lastHandle;
  3764. m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
  3765. m_LastReceiveTick = Environment.TickCount;
  3766. }
  3767. #endif
  3768. return errorCode;
  3769. }
  3770. #if DEBUG
  3771. private IntPtr m_LastReceiveHandle;
  3772. private int m_LastReceiveThread;
  3773. private int m_LastReceiveTick;
  3774. #endif
  3775. #endif // !MONO
  3776. /*++
  3777. Routine Description:
  3778. EndReceive - Called when I/O is done or the user wants to wait. If
  3779. the I/O isn't done, we'll wait for it to complete, and then we'll return
  3780. the bytes of I/O done.
  3781. Arguments:
  3782. AsyncResult - the AsyncResult Returned fron BeginSend call
  3783. Return Value:
  3784. int - Number of bytes transferred
  3785. --*/
  3786. /// <devdoc>
  3787. /// <para>[To be supplied.]</para>
  3788. /// </devdoc>
  3789. public int EndReceive(IAsyncResult asyncResult) {
  3790. SocketError errorCode;
  3791. int bytesTransferred = EndReceive(asyncResult, out errorCode);
  3792. if(errorCode != SocketError.Success){
  3793. throw new SocketException(errorCode);
  3794. }
  3795. return bytesTransferred;
  3796. }
  3797. #if !MONO
  3798. public int EndReceive(IAsyncResult asyncResult, out SocketError errorCode) {
  3799. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceive", asyncResult);
  3800. if (CleanedUp) {
  3801. throw new ObjectDisposedException(this.GetType().FullName);
  3802. }
  3803. //
  3804. // parameter validation
  3805. //
  3806. if (asyncResult==null) {
  3807. throw new ArgumentNullException("asyncResult");
  3808. }
  3809. OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
  3810. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  3811. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  3812. }
  3813. if (castedAsyncResult.EndCalled) {
  3814. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceive"));
  3815. }
  3816. int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
  3817. castedAsyncResult.EndCalled = true;
  3818. castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
  3819. #if !FEATURE_PAL // perfcounter
  3820. if (s_PerfCountersEnabled)
  3821. {
  3822. if (bytesTransferred>0) {
  3823. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
  3824. if (Transport==TransportType.Udp) {
  3825. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
  3826. }
  3827. }
  3828. }
  3829. #endif //!FEATURE_PAL
  3830. #if TRAVE
  3831. try
  3832. {
  3833. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred.ToString());
  3834. }
  3835. catch (ObjectDisposedException) { }
  3836. #endif
  3837. //
  3838. // if the asynchronous native call failed asynchronously
  3839. // we'll throw a SocketException
  3840. //
  3841. errorCode = (SocketError)castedAsyncResult.ErrorCode;
  3842. if (errorCode!=SocketError.Success) {
  3843. //
  3844. // update our internal state after this socket error and throw
  3845. //
  3846. UpdateStatusAfterSocketError(errorCode);
  3847. if(s_LoggingEnabled){
  3848. Logging.Exception(Logging.Sockets, this, "EndReceive", new SocketException(errorCode));
  3849. Logging.Exit(Logging.Sockets, this, "EndReceive", 0);
  3850. }
  3851. return 0;
  3852. }
  3853. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceive", bytesTransferred);
  3854. return bytesTransferred;
  3855. }
  3856. public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state) {
  3857. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "BeginReceiveMessageFrom", "");
  3858. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() size:" + size.ToString());
  3859. if (CleanedUp) {
  3860. throw new ObjectDisposedException(this.GetType().FullName);
  3861. }
  3862. if (buffer==null) {
  3863. throw new ArgumentNullException("buffer");
  3864. }
  3865. if (remoteEP==null) {
  3866. throw new ArgumentNullException("remoteEP");
  3867. }
  3868. if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
  3869. throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
  3870. remoteEP.AddressFamily, addressFamily), "remoteEP");
  3871. }
  3872. if (offset<0 || offset>buffer.Length) {
  3873. throw new ArgumentOutOfRangeException("offset");
  3874. }
  3875. if (size<0 || size>buffer.Length-offset) {
  3876. throw new ArgumentOutOfRangeException("size");
  3877. }
  3878. if (m_RightEndPoint==null) {
  3879. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  3880. }
  3881. // Set up the result and set it to collect the context.
  3882. ReceiveMessageOverlappedAsyncResult asyncResult = new ReceiveMessageOverlappedAsyncResult(this, state, callback);
  3883. asyncResult.StartPostingAsyncOp(false);
  3884. // Start the ReceiveFrom.
  3885. EndPoint oldEndPoint = m_RightEndPoint;
  3886. // We don't do a CAS demand here because the contents of remoteEP aren't used by
  3887. // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
  3888. // with the right address family
  3889. SocketAddress socketAddress = SnapshotAndSerialize(ref remoteEP);
  3890. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  3891. // avoid a Socket leak in case of error.
  3892. SocketError errorCode = SocketError.SocketError;
  3893. try
  3894. {
  3895. asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, socketFlags, ref Caches.ReceiveOverlappedCache);
  3896. // save a copy of the original EndPoint in the asyncResult
  3897. asyncResult.SocketAddressOriginal = remoteEP.Serialize();
  3898. int bytesTransfered;
  3899. SetReceivingPacketInformation();
  3900. if (m_RightEndPoint == null)
  3901. {
  3902. m_RightEndPoint = remoteEP;
  3903. }
  3904. errorCode = (SocketError) WSARecvMsg(
  3905. m_Handle,
  3906. Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.m_MessageBuffer,0),
  3907. out bytesTransfered,
  3908. asyncResult.OverlappedHandle,
  3909. IntPtr.Zero);
  3910. if (errorCode!=SocketError.Success) {
  3911. errorCode = (SocketError)Marshal.GetLastWin32Error();
  3912. // I have guarantees from Brad Williamson that WSARecvMsg() will never return WSAEMSGSIZE directly, since a completion
  3913. // is queued in this case. We wouldn't be able to handle this easily because of assumptions OverlappedAsyncResult
  3914. // makes about whether there would be a completion or not depending on the error code. If WSAEMSGSIZE would have been
  3915. // normally returned, it returns WSA_IO_PENDING instead. That same map is implemented here just in case.
  3916. if (errorCode == SocketError.MessageSize)
  3917. {
  3918. GlobalLog.Assert("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom()|Returned WSAEMSGSIZE!");
  3919. errorCode = SocketError.IOPending;
  3920. }
  3921. }
  3922. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() UnsafeNclNativeMethods.OSSOCK.WSARecvMsg returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  3923. }
  3924. catch (ObjectDisposedException)
  3925. {
  3926. m_RightEndPoint = oldEndPoint;
  3927. throw;
  3928. }
  3929. finally
  3930. {
  3931. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  3932. }
  3933. //
  3934. // if the asynchronous native call fails synchronously
  3935. // we'll throw a SocketException
  3936. //
  3937. if (errorCode!=SocketError.Success)
  3938. {
  3939. //
  3940. // update our internal state after this socket error and throw
  3941. //
  3942. m_RightEndPoint = oldEndPoint;
  3943. asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
  3944. SocketException socketException = new SocketException(errorCode);
  3945. UpdateStatusAfterSocketError(socketException);
  3946. if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "BeginReceiveMessageFrom", socketException);
  3947. throw socketException;
  3948. }
  3949. // Capture the context, maybe call the callback, and return.
  3950. asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
  3951. if (asyncResult.CompletedSynchronously && !asyncResult.SocketAddressOriginal.Equals(asyncResult.SocketAddress)) {
  3952. try {
  3953. remoteEP = remoteEP.Create(asyncResult.SocketAddress);
  3954. }
  3955. catch {
  3956. }
  3957. }
  3958. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  3959. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceiveMessageFrom", asyncResult);
  3960. return asyncResult;
  3961. }
  3962. public int EndReceiveMessageFrom(IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation) {
  3963. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceiveMessageFrom", asyncResult);
  3964. if (CleanedUp) {
  3965. throw new ObjectDisposedException(this.GetType().FullName);
  3966. }
  3967. if (endPoint==null) {
  3968. throw new ArgumentNullException("endPoint");
  3969. }
  3970. if (!CanTryAddressFamily(endPoint.AddressFamily)) {
  3971. throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
  3972. endPoint.AddressFamily, addressFamily), "endPoint");
  3973. }
  3974. if (asyncResult==null) {
  3975. throw new ArgumentNullException("asyncResult");
  3976. }
  3977. ReceiveMessageOverlappedAsyncResult castedAsyncResult = asyncResult as ReceiveMessageOverlappedAsyncResult;
  3978. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  3979. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  3980. }
  3981. if (castedAsyncResult.EndCalled) {
  3982. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceiveMessageFrom"));
  3983. }
  3984. SocketAddress socketAddressOriginal = SnapshotAndSerialize(ref endPoint);
  3985. int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
  3986. castedAsyncResult.EndCalled = true;
  3987. castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
  3988. // Update socket address size
  3989. castedAsyncResult.SocketAddress.SetSize(castedAsyncResult.GetSocketAddressSizePtr());
  3990. if (!socketAddressOriginal.Equals(castedAsyncResult.SocketAddress)) {
  3991. try {
  3992. endPoint = endPoint.Create(castedAsyncResult.SocketAddress);
  3993. }
  3994. catch {
  3995. }
  3996. }
  3997. #if !FEATURE_PAL // perfcounter
  3998. if (s_PerfCountersEnabled)
  3999. {
  4000. if (bytesTransferred>0) {
  4001. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
  4002. if (Transport==TransportType.Udp) {
  4003. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
  4004. }
  4005. }
  4006. }
  4007. #endif //!FEATURE_PAL
  4008. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceiveMessageFrom() bytesTransferred:" + bytesTransferred.ToString());
  4009. //
  4010. // if the asynchronous native call failed asynchronously
  4011. // we'll throw a SocketException
  4012. //
  4013. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success && (SocketError)castedAsyncResult.ErrorCode != SocketError.MessageSize) {
  4014. //
  4015. // update our internal state after this socket error and throw
  4016. //
  4017. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
  4018. UpdateStatusAfterSocketError(socketException);
  4019. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndReceiveMessageFrom", socketException);
  4020. throw socketException;
  4021. }
  4022. socketFlags = castedAsyncResult.m_flags;
  4023. ipPacketInformation = castedAsyncResult.m_IPPacketInformation;
  4024. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceiveMessageFrom", bytesTransferred);
  4025. return bytesTransferred;
  4026. }
  4027. /*++
  4028. Routine Description:
  4029. BeginReceiveFrom - Async implimentation of RecvFrom call,
  4030. Called when we want to start an async receive.
  4031. We kick off the receive, and if it completes synchronously we'll
  4032. call the callback. Otherwise we'll return an IASyncResult, which
  4033. the caller can use to wait on or retrieve the final status, as needed.
  4034. Uses Winsock 2 overlapped I/O.
  4035. Arguments:
  4036. ReadBuffer - status line that we wish to parse
  4037. Index - Offset into ReadBuffer to begin reading from
  4038. Request - Size of Buffer to recv
  4039. Flags - Additonal Flags that may be passed to the underlying winsock call
  4040. remoteEP - EndPoint that are to receive from
  4041. Callback - Delegate function that holds callback, called on completeion of I/O
  4042. State - State used to track callback, set by caller, not required
  4043. Return Value:
  4044. IAsyncResult - Async result used to retreive result
  4045. --*/
  4046. /// <devdoc>
  4047. /// <para>[To be supplied.]</para>
  4048. /// </devdoc>
  4049. [HostProtection(ExternalThreading=true)]
  4050. public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state) {
  4051. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "BeginReceiveFrom", "");
  4052. if (CleanedUp) {
  4053. throw new ObjectDisposedException(this.GetType().FullName);
  4054. }
  4055. //
  4056. // parameter validation
  4057. //
  4058. if (buffer==null) {
  4059. throw new ArgumentNullException("buffer");
  4060. }
  4061. if (remoteEP==null) {
  4062. throw new ArgumentNullException("remoteEP");
  4063. }
  4064. if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
  4065. throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
  4066. remoteEP.AddressFamily, addressFamily), "remoteEP");
  4067. }
  4068. if (offset<0 || offset>buffer.Length) {
  4069. throw new ArgumentOutOfRangeException("offset");
  4070. }
  4071. if (size<0 || size>buffer.Length-offset) {
  4072. throw new ArgumentOutOfRangeException("size");
  4073. }
  4074. if (m_RightEndPoint==null) {
  4075. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  4076. }
  4077. // We don't do a CAS demand here because the contents of remoteEP aren't used by
  4078. // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
  4079. // with the right address family
  4080. SocketAddress socketAddress = SnapshotAndSerialize(ref remoteEP);
  4081. // Set up the result and set it to collect the context.
  4082. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  4083. asyncResult.StartPostingAsyncOp(false);
  4084. // Start the ReceiveFrom.
  4085. DoBeginReceiveFrom(buffer, offset, size, socketFlags, remoteEP, socketAddress, asyncResult);
  4086. // Capture the context, maybe call the callback, and return.
  4087. asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
  4088. if (asyncResult.CompletedSynchronously && !asyncResult.SocketAddressOriginal.Equals(asyncResult.SocketAddress)) {
  4089. try {
  4090. remoteEP = remoteEP.Create(asyncResult.SocketAddress);
  4091. }
  4092. catch {
  4093. }
  4094. }
  4095. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceiveFrom", asyncResult);
  4096. return asyncResult;
  4097. }
  4098. private void DoBeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint endPointSnapshot, SocketAddress socketAddress, OverlappedAsyncResult asyncResult)
  4099. {
  4100. EndPoint oldEndPoint = m_RightEndPoint;
  4101. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() size:" + size.ToString());
  4102. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  4103. // avoid a Socket leak in case of error.
  4104. SocketError errorCode = SocketError.SocketError;
  4105. try
  4106. {
  4107. // Set up asyncResult for overlapped WSARecvFrom.
  4108. // This call will use completion ports on WinNT and Overlapped IO on Win9x.
  4109. asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, true /* pin remoteEP*/, ref Caches.ReceiveOverlappedCache);
  4110. // save a copy of the original EndPoint in the asyncResult
  4111. asyncResult.SocketAddressOriginal = endPointSnapshot.Serialize();
  4112. if (m_RightEndPoint == null) {
  4113. m_RightEndPoint = endPointSnapshot;
  4114. }
  4115. int bytesTransferred;
  4116. errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
  4117. m_Handle,
  4118. ref asyncResult.m_SingleBuffer,
  4119. 1,
  4120. out bytesTransferred,
  4121. ref socketFlags,
  4122. asyncResult.GetSocketAddressPtr(),
  4123. asyncResult.GetSocketAddressSizePtr(),
  4124. asyncResult.OverlappedHandle,
  4125. IntPtr.Zero );
  4126. if (errorCode!=SocketError.Success) {
  4127. errorCode = (SocketError)Marshal.GetLastWin32Error();
  4128. }
  4129. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() UnsafeNclNativeMethods.OSSOCK.WSARecvFrom returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  4130. }
  4131. catch (ObjectDisposedException)
  4132. {
  4133. m_RightEndPoint = oldEndPoint;
  4134. throw;
  4135. }
  4136. finally
  4137. {
  4138. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  4139. }
  4140. //
  4141. // if the asynchronous native call fails synchronously
  4142. // we'll throw a SocketException
  4143. //
  4144. if (errorCode!=SocketError.Success) {
  4145. //
  4146. // update our internal state after this socket error and throw
  4147. //
  4148. m_RightEndPoint = oldEndPoint;
  4149. asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
  4150. SocketException socketException = new SocketException(errorCode);
  4151. UpdateStatusAfterSocketError(socketException);
  4152. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceiveFrom", socketException);
  4153. throw socketException;
  4154. }
  4155. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  4156. }
  4157. /*++
  4158. Routine Description:
  4159. EndReceiveFrom - Called when I/O is done or the user wants to wait. If
  4160. the I/O isn't done, we'll wait for it to complete, and then we'll return
  4161. the bytes of I/O done.
  4162. Arguments:
  4163. AsyncResult - the AsyncResult Returned fron BeginReceiveFrom call
  4164. Return Value:
  4165. int - Number of bytes transferred
  4166. --*/
  4167. /// <devdoc>
  4168. /// <para>[To be supplied.]</para>
  4169. /// </devdoc>
  4170. public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint) {
  4171. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceiveFrom", asyncResult);
  4172. if (CleanedUp) {
  4173. throw new ObjectDisposedException(this.GetType().FullName);
  4174. }
  4175. //
  4176. // parameter validation
  4177. //
  4178. if (endPoint==null) {
  4179. throw new ArgumentNullException("endPoint");
  4180. }
  4181. if (!CanTryAddressFamily(endPoint.AddressFamily)) {
  4182. throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
  4183. endPoint.AddressFamily, addressFamily), "endPoint");
  4184. }
  4185. if (asyncResult==null) {
  4186. throw new ArgumentNullException("asyncResult");
  4187. }
  4188. OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
  4189. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  4190. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  4191. }
  4192. if (castedAsyncResult.EndCalled) {
  4193. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceiveFrom"));
  4194. }
  4195. SocketAddress socketAddressOriginal = SnapshotAndSerialize(ref endPoint);
  4196. int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
  4197. castedAsyncResult.EndCalled = true;
  4198. castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
  4199. // Update socket address size
  4200. castedAsyncResult.SocketAddress.SetSize(castedAsyncResult.GetSocketAddressSizePtr());
  4201. if (!socketAddressOriginal.Equals(castedAsyncResult.SocketAddress)) {
  4202. try {
  4203. endPoint = endPoint.Create(castedAsyncResult.SocketAddress);
  4204. }
  4205. catch {
  4206. }
  4207. }
  4208. #if !FEATURE_PAL // perfcounter
  4209. if (s_PerfCountersEnabled)
  4210. {
  4211. if (bytesTransferred>0) {
  4212. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
  4213. if (Transport==TransportType.Udp) {
  4214. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
  4215. }
  4216. }
  4217. }
  4218. #endif //!FEATURE_PAL
  4219. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceiveFrom() bytesTransferred:" + bytesTransferred.ToString());
  4220. //
  4221. // if the asynchronous native call failed asynchronously
  4222. // we'll throw a SocketException
  4223. //
  4224. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
  4225. //
  4226. // update our internal state after this socket error and throw
  4227. //
  4228. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
  4229. UpdateStatusAfterSocketError(socketException);
  4230. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndReceiveFrom", socketException);
  4231. throw socketException;
  4232. }
  4233. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceiveFrom", bytesTransferred);
  4234. return bytesTransferred;
  4235. }
  4236. /*++
  4237. Routine Description:
  4238. BeginAccept - Does a async winsock accept, creating a new socket on success
  4239. Works by creating a pending accept request the first time,
  4240. and subsequent calls are queued so that when the first accept completes,
  4241. the next accept can be resubmitted in the callback.
  4242. this routine may go pending at which time,
  4243. but any case the callback Delegate will be called upon completion
  4244. Arguments:
  4245. Callback - Async Callback Delegate that is called upon Async Completion
  4246. State - State used to track callback, set by caller, not required
  4247. Return Value:
  4248. IAsyncResult - Async result used to retreive resultant new socket
  4249. --*/
  4250. /// <devdoc>
  4251. /// <para>[To be supplied.]</para>
  4252. /// </devdoc>
  4253. [HostProtection(ExternalThreading=true)]
  4254. public IAsyncResult BeginAccept(AsyncCallback callback, object state) {
  4255. #if !FEATURE_PAL
  4256. if (CanUseAcceptEx)
  4257. {
  4258. return BeginAccept(0,callback,state);
  4259. }
  4260. #endif
  4261. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginAccept", "");
  4262. if (CleanedUp) {
  4263. throw new ObjectDisposedException(this.GetType().FullName);
  4264. }
  4265. // Set up the context flow.
  4266. AcceptAsyncResult asyncResult = new AcceptAsyncResult(this, state, callback);
  4267. asyncResult.StartPostingAsyncOp(false);
  4268. // Do the accept.
  4269. DoBeginAccept(asyncResult);
  4270. // Set up for return.
  4271. asyncResult.FinishPostingAsyncOp(ref Caches.AcceptClosureCache);
  4272. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginAccept", asyncResult);
  4273. return asyncResult;
  4274. }
  4275. private void DoBeginAccept(LazyAsyncResult asyncResult)
  4276. {
  4277. if (m_RightEndPoint==null) {
  4278. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  4279. }
  4280. if(!isListening){
  4281. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
  4282. }
  4283. //
  4284. // We keep a queue, which lists the set of requests that want to
  4285. // be called when an accept queue completes. We call accept
  4286. // once, and then as it completes asyncrounsly we pull the
  4287. // requests out of the queue and call their callback.
  4288. //
  4289. // We start by grabbing Critical Section, then attempt to
  4290. // determine if we haven an empty Queue of Accept Sockets
  4291. // or if its in a Callback on the Callback thread.
  4292. //
  4293. // If its in the callback thread proocessing of the callback, then we
  4294. // just need to notify the callback by adding an additional request
  4295. // to the queue.
  4296. //
  4297. // If its an empty queue, and its not in the callback, then
  4298. // we just need to get the Accept going, make it go async
  4299. // and leave.
  4300. //
  4301. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept()");
  4302. bool needFinishedCall = false;
  4303. SocketError errorCode = 0;
  4304. Queue acceptQueue = GetAcceptQueue();
  4305. lock(this)
  4306. {
  4307. if (acceptQueue.Count == 0)
  4308. {
  4309. SocketAddress socketAddress = m_RightEndPoint.Serialize();
  4310. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() queue is empty calling UnsafeNclNativeMethods.OSSOCK.accept");
  4311. // Check if a socket is already available. We need to be non-blocking to do this.
  4312. InternalSetBlocking(false);
  4313. SafeCloseSocket acceptedSocketHandle = null;
  4314. try
  4315. {
  4316. acceptedSocketHandle = SafeCloseSocket.Accept(
  4317. m_Handle,
  4318. socketAddress.m_Buffer,
  4319. ref socketAddress.m_Size);
  4320. errorCode = acceptedSocketHandle.IsInvalid ? (SocketError) Marshal.GetLastWin32Error() : SocketError.Success;
  4321. }
  4322. catch (ObjectDisposedException)
  4323. {
  4324. errorCode = SocketError.NotSocket;
  4325. }
  4326. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() UnsafeNclNativeMethods.OSSOCK.accept returns:" + errorCode.ToString());
  4327. if (errorCode != SocketError.WouldBlock)
  4328. {
  4329. if (errorCode == SocketError.Success)
  4330. {
  4331. asyncResult.Result = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress), false);
  4332. }
  4333. else
  4334. {
  4335. asyncResult.ErrorCode = (int) errorCode;
  4336. }
  4337. // Reset the blocking.
  4338. InternalSetBlocking(true);
  4339. // Continue outside the lock.
  4340. needFinishedCall = true;
  4341. }
  4342. else
  4343. {
  4344. // It would block. Start listening for accepts, and add ourselves to the queue.
  4345. acceptQueue.Enqueue(asyncResult);
  4346. if (!SetAsyncEventSelect(AsyncEventBits.FdAccept))
  4347. {
  4348. acceptQueue.Dequeue();
  4349. throw new ObjectDisposedException(this.GetType().FullName);
  4350. }
  4351. }
  4352. }
  4353. else {
  4354. acceptQueue.Enqueue(asyncResult);
  4355. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() queue is not empty Count:" + acceptQueue.Count.ToString());
  4356. }
  4357. }
  4358. if (needFinishedCall) {
  4359. if (errorCode == SocketError.Success)
  4360. {
  4361. // Completed synchronously, invoke the callback.
  4362. asyncResult.InvokeCallback();
  4363. }
  4364. else
  4365. {
  4366. //
  4367. // update our internal state after this socket error and throw
  4368. //
  4369. SocketException socketException = new SocketException(errorCode);
  4370. UpdateStatusAfterSocketError(socketException);
  4371. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginAccept", socketException);
  4372. throw socketException;
  4373. }
  4374. }
  4375. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  4376. }
  4377. //
  4378. // This is a shortcut to AcceptCallback when called from dispose.
  4379. // The only business is lock and complete all results with an error
  4380. //
  4381. private void CompleteAcceptResults(object nullState)
  4382. {
  4383. Queue acceptQueue = GetAcceptQueue();
  4384. bool acceptNeeded = true;
  4385. while (acceptNeeded)
  4386. {
  4387. LazyAsyncResult asyncResult = null;
  4388. lock (this)
  4389. {
  4390. // If the queue is empty, cancel the select and indicate not to loop anymore.
  4391. if (acceptQueue.Count == 0)
  4392. break;
  4393. asyncResult = (LazyAsyncResult) acceptQueue.Dequeue();
  4394. if (acceptQueue.Count == 0)
  4395. acceptNeeded = false;
  4396. }
  4397. // Notify about the completion outside the lock.
  4398. try {
  4399. asyncResult.InvokeCallback(new SocketException(SocketError.OperationAborted));
  4400. }
  4401. catch {
  4402. // Exception from the user callback,
  4403. // If we need to loop, offload to a different thread and re-throw for debugging
  4404. if (acceptNeeded)
  4405. ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(CompleteAcceptResults), null);
  4406. throw;
  4407. }
  4408. }
  4409. }
  4410. // This method was originally in an AcceptAsyncResult class but that class got useless.
  4411. private void AcceptCallback(object nullState)
  4412. {
  4413. // We know we need to try completing an accept at first. Keep going until the queue is empty (inside the lock).
  4414. // At that point, BeginAccept() takes control of restarting the pump if necessary.
  4415. bool acceptNeeded = true;
  4416. Queue acceptQueue = GetAcceptQueue();
  4417. while (acceptNeeded)
  4418. {
  4419. LazyAsyncResult asyncResult = null;
  4420. SocketError errorCode = SocketError.OperationAborted;
  4421. SocketAddress socketAddress = null;
  4422. SafeCloseSocket acceptedSocket = null;
  4423. Exception otherException = null;
  4424. object result = null;
  4425. lock (this)
  4426. {
  4427. //
  4428. // Accept Callback - called on the callback path, when we expect to release
  4429. // an accept socket that winsock says has completed.
  4430. //
  4431. // While we still have items in our Queued list of Accept Requests,
  4432. // we recall the Winsock accept, to attempt to gather new
  4433. // results, and then match them again the queued items,
  4434. // when accept call returns would_block, we reinvoke ourselves
  4435. // and rewait for the next asyc callback.
  4436. //
  4437. //
  4438. // We may not have items in the queue because of possible ----
  4439. // between re-entering this callback manually and from the thread pool.
  4440. //
  4441. if (acceptQueue.Count == 0)
  4442. break;
  4443. // pick an element from the head of the list
  4444. asyncResult = (LazyAsyncResult) acceptQueue.Peek();
  4445. if (!CleanedUp)
  4446. {
  4447. socketAddress = m_RightEndPoint.Serialize();
  4448. try
  4449. {
  4450. // We know we're in non-blocking because of SetAsyncEventSelect().
  4451. GlobalLog.Assert(!willBlockInternal, "Socket#{0}::AcceptCallback|Socket should be in non-blocking state.", ValidationHelper.HashString(this));
  4452. acceptedSocket = SafeCloseSocket.Accept(
  4453. m_Handle,
  4454. socketAddress.m_Buffer,
  4455. ref socketAddress.m_Size);
  4456. errorCode = acceptedSocket.IsInvalid ? (SocketError) Marshal.GetLastWin32Error() : SocketError.Success;
  4457. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::AcceptCallback() UnsafeNclNativeMethods.OSSOCK.accept returns:" + errorCode.ToString());
  4458. }
  4459. catch (ObjectDisposedException)
  4460. {
  4461. // Listener socket was closed.
  4462. errorCode = SocketError.OperationAborted;
  4463. }
  4464. catch (Exception exception)
  4465. {
  4466. if (NclUtilities.IsFatal(exception)) throw;
  4467. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::AcceptCallback() caught exception:" + exception.Message + " CleanedUp:" + CleanedUp);
  4468. otherException = exception;
  4469. }
  4470. }
  4471. if (errorCode == SocketError.WouldBlock && otherException == null)
  4472. {
  4473. // The accept found no waiting connections, so start listening for more.
  4474. try
  4475. {
  4476. m_AsyncEvent.Reset(); // reset event to wait for the next client.
  4477. if (SetAsyncEventSelect(AsyncEventBits.FdAccept))
  4478. break;
  4479. }
  4480. catch (ObjectDisposedException)
  4481. {
  4482. // Handle ---- with Dispose, m_AsyncEvent may have been Close()'d already.
  4483. }
  4484. otherException = new ObjectDisposedException(this.GetType().FullName);
  4485. }
  4486. // CreateAcceptSocket() must be done before InternalSetBlocking() so that the fixup is correct inside
  4487. // UpdateAcceptSocket(). InternalSetBlocking() must happen in the lock.
  4488. if (otherException != null)
  4489. {
  4490. result = otherException;
  4491. }
  4492. else if (errorCode == SocketError.Success)
  4493. {
  4494. result = CreateAcceptSocket(acceptedSocket, m_RightEndPoint.Create(socketAddress), true);
  4495. }
  4496. else
  4497. {
  4498. asyncResult.ErrorCode = (int) errorCode;
  4499. }
  4500. // This request completed, so it can be taken off the queue.
  4501. acceptQueue.Dequeue();
  4502. // If the queue is empty, cancel the select and indicate not to loop anymore.
  4503. if (acceptQueue.Count == 0)
  4504. {
  4505. if (!CleanedUp)
  4506. UnsetAsyncEventSelect();
  4507. acceptNeeded = false;
  4508. }
  4509. }
  4510. // Notify about the completion outside the lock.
  4511. try {
  4512. asyncResult.InvokeCallback(result);
  4513. }
  4514. catch {
  4515. // Exception from the user callback,
  4516. // If we need to loop, offload to a different thread and re-throw for debugging
  4517. if (acceptNeeded)
  4518. ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(AcceptCallback), nullState);
  4519. throw;
  4520. }
  4521. }
  4522. }
  4523. #endif // !MONO
  4524. #if !FEATURE_PAL
  4525. #if !MONO
  4526. private bool CanUseAcceptEx
  4527. {
  4528. get
  4529. {
  4530. return
  4531. (Thread.CurrentThread.IsThreadPoolThread || SettingsSectionInternal.Section.AlwaysUseCompletionPortsForAccept || m_IsDisconnected);
  4532. }
  4533. }
  4534. #endif // !MONO
  4535. /// <devdoc>
  4536. /// <para>[To be supplied.]</para>
  4537. /// </devdoc>
  4538. [HostProtection(ExternalThreading=true)]
  4539. public IAsyncResult BeginAccept(int receiveSize, AsyncCallback callback, object state) {
  4540. return BeginAccept(null,receiveSize,callback,state);
  4541. }
  4542. /// This is the true async version that uses AcceptEx
  4543. #if !MONO
  4544. /// <devdoc>
  4545. /// <para>[To be supplied.]</para>
  4546. /// </devdoc>
  4547. [HostProtection(ExternalThreading=true)]
  4548. public IAsyncResult BeginAccept(Socket acceptSocket, int receiveSize, AsyncCallback callback, object state) {
  4549. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginAccept", "");
  4550. if (CleanedUp) {
  4551. throw new ObjectDisposedException(this.GetType().FullName);
  4552. }
  4553. //
  4554. // parameter validation
  4555. //
  4556. if (receiveSize<0) {
  4557. throw new ArgumentOutOfRangeException("size");
  4558. }
  4559. // Set up the async result with flowing.
  4560. AcceptOverlappedAsyncResult asyncResult = new AcceptOverlappedAsyncResult(this, state, callback);
  4561. asyncResult.StartPostingAsyncOp(false);
  4562. // Start the accept.
  4563. DoBeginAccept(acceptSocket, receiveSize, asyncResult);
  4564. // Finish the flow capture, maybe complete here.
  4565. asyncResult.FinishPostingAsyncOp(ref Caches.AcceptClosureCache);
  4566. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginAccept", asyncResult);
  4567. return asyncResult;
  4568. }
  4569. private void DoBeginAccept(Socket acceptSocket, int receiveSize, AcceptOverlappedAsyncResult asyncResult)
  4570. {
  4571. if (m_RightEndPoint==null) {
  4572. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  4573. }
  4574. if(!isListening){
  4575. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
  4576. }
  4577. // if a acceptSocket isn't specified, then we need to create it.
  4578. if (acceptSocket == null) {
  4579. acceptSocket = new Socket(addressFamily,socketType,protocolType);
  4580. }
  4581. else
  4582. {
  4583. if (acceptSocket.m_RightEndPoint != null) {
  4584. throw new InvalidOperationException(SR.GetString(SR.net_sockets_namedmustnotbebound, "acceptSocket"));
  4585. }
  4586. }
  4587. asyncResult.AcceptSocket = acceptSocket;
  4588. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() AcceptSocket:" + ValidationHelper.HashString(acceptSocket));
  4589. //the buffer needs to contain the requested data plus room for two sockaddrs and 16 bytes
  4590. //of associated data for each.
  4591. int addressBufferSize = m_RightEndPoint.Serialize().Size + 16;
  4592. byte[] buffer = new byte[receiveSize + ((addressBufferSize) * 2)];
  4593. //
  4594. // Set up asyncResult for overlapped AcceptEx.
  4595. // This call will use
  4596. // completion ports on WinNT
  4597. //
  4598. asyncResult.SetUnmanagedStructures(buffer, addressBufferSize);
  4599. // This can throw ObjectDisposedException.
  4600. int bytesTransferred;
  4601. SocketError errorCode = SocketError.Success;
  4602. if (!AcceptEx(
  4603. m_Handle,
  4604. acceptSocket.m_Handle,
  4605. Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.Buffer, 0),
  4606. receiveSize,
  4607. addressBufferSize,
  4608. addressBufferSize,
  4609. out bytesTransferred,
  4610. asyncResult.OverlappedHandle))
  4611. {
  4612. errorCode = (SocketError)Marshal.GetLastWin32Error();
  4613. }
  4614. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  4615. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() UnsafeNclNativeMethods.OSSOCK.AcceptEx returns:" + errorCode.ToString() + ValidationHelper.HashString(asyncResult));
  4616. //
  4617. // if the asynchronous native call fails synchronously
  4618. // we'll throw a SocketException
  4619. //
  4620. if (errorCode!=SocketError.Success) {
  4621. SocketException socketException = new SocketException(errorCode);
  4622. UpdateStatusAfterSocketError(socketException);
  4623. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginAccept", socketException);
  4624. throw socketException;
  4625. }
  4626. }
  4627. #endif // !MONO
  4628. #endif // !FEATURE_PAL
  4629. /*++
  4630. Routine Description:
  4631. EndAccept - Called by user code addressFamilyter I/O is done or the user wants to wait.
  4632. until Async completion, so it provides End handling for aync Accept calls,
  4633. and retrieves new Socket object
  4634. Arguments:
  4635. AsyncResult - the AsyncResult Returned fron BeginAccept call
  4636. Return Value:
  4637. Socket - a valid socket if successful
  4638. --*/
  4639. #if !MONO
  4640. /// <devdoc>
  4641. /// <para>[To be supplied.]</para>
  4642. /// </devdoc>
  4643. public Socket EndAccept(IAsyncResult asyncResult) {
  4644. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndAccept", asyncResult);
  4645. if (CleanedUp) {
  4646. throw new ObjectDisposedException(this.GetType().FullName);
  4647. }
  4648. #if !FEATURE_PAL
  4649. if (asyncResult != null && (asyncResult is AcceptOverlappedAsyncResult)) {
  4650. int bytesTransferred;
  4651. byte[] buffer;
  4652. return EndAccept(out buffer, out bytesTransferred, asyncResult);
  4653. }
  4654. #endif // !FEATURE_PAL
  4655. //
  4656. // parameter validation
  4657. //
  4658. if (asyncResult==null) {
  4659. throw new ArgumentNullException("asyncResult");
  4660. }
  4661. AcceptAsyncResult castedAsyncResult = asyncResult as AcceptAsyncResult;
  4662. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  4663. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  4664. }
  4665. if (castedAsyncResult.EndCalled) {
  4666. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndAccept"));
  4667. }
  4668. object result = castedAsyncResult.InternalWaitForCompletion();
  4669. castedAsyncResult.EndCalled = true;
  4670. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndAccept() acceptedSocket:" + ValidationHelper.HashString(result));
  4671. //
  4672. // if the asynchronous native call failed asynchronously
  4673. // we'll throw a SocketException
  4674. //
  4675. Exception exception = result as Exception;
  4676. if (exception != null)
  4677. {
  4678. throw exception;
  4679. }
  4680. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
  4681. //
  4682. // update our internal state after this socket error and throw
  4683. //
  4684. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
  4685. UpdateStatusAfterSocketError(socketException);
  4686. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndAccept", socketException);
  4687. throw socketException;
  4688. }
  4689. Socket acceptedSocket = (Socket)result;
  4690. if (s_LoggingEnabled) {
  4691. Logging.PrintInfo(Logging.Sockets, acceptedSocket,
  4692. SR.GetString(SR.net_log_socket_accepted, acceptedSocket.RemoteEndPoint, acceptedSocket.LocalEndPoint));
  4693. Logging.Exit(Logging.Sockets, this, "EndAccept", result);
  4694. }
  4695. return acceptedSocket;
  4696. }
  4697. #endif // !MONO
  4698. #if !FEATURE_PAL
  4699. /// <devdoc>
  4700. /// <para>[To be supplied.]</para>
  4701. /// </devdoc>
  4702. public Socket EndAccept( out byte[] buffer, IAsyncResult asyncResult) {
  4703. int bytesTransferred;
  4704. byte[] innerBuffer;
  4705. Socket socket = EndAccept(out innerBuffer,out bytesTransferred, asyncResult);
  4706. buffer = new byte[bytesTransferred];
  4707. Array.Copy(innerBuffer,buffer,bytesTransferred);
  4708. return socket;
  4709. }
  4710. #if !MONO
  4711. /// <devdoc>
  4712. /// <para>[To be supplied.]</para>
  4713. /// </devdoc>
  4714. public Socket EndAccept( out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) {
  4715. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndAccept", asyncResult);
  4716. if (CleanedUp) {
  4717. throw new ObjectDisposedException(this.GetType().FullName);
  4718. }
  4719. //
  4720. // parameter validation
  4721. //
  4722. if (asyncResult==null) {
  4723. throw new ArgumentNullException("asyncResult");
  4724. }
  4725. AcceptOverlappedAsyncResult castedAsyncResult = asyncResult as AcceptOverlappedAsyncResult;
  4726. if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
  4727. throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  4728. }
  4729. if (castedAsyncResult.EndCalled) {
  4730. throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndAccept"));
  4731. }
  4732. Socket socket = (Socket)castedAsyncResult.InternalWaitForCompletion();
  4733. bytesTransferred = (int)castedAsyncResult.BytesTransferred;
  4734. buffer = castedAsyncResult.Buffer;
  4735. castedAsyncResult.EndCalled = true;
  4736. #if !FEATURE_PAL // perfcounter
  4737. if (s_PerfCountersEnabled)
  4738. {
  4739. if (bytesTransferred>0) {
  4740. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
  4741. }
  4742. }
  4743. #endif
  4744. //
  4745. // if the asynchronous native call failed asynchronously
  4746. // we'll throw a SocketException
  4747. //
  4748. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
  4749. //
  4750. // update our internal state after this socket error and throw
  4751. //
  4752. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
  4753. UpdateStatusAfterSocketError(socketException);
  4754. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndAccept", socketException);
  4755. throw socketException;
  4756. }
  4757. #if TRAVE
  4758. try
  4759. {
  4760. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndAccept() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " acceptedSocket:" + ValidationHelper.HashString(socket) + " acceptedSocket.SRC:" + ValidationHelper.ToString(socket.LocalEndPoint) + " acceptedSocket.DST:" + ValidationHelper.ToString(socket.RemoteEndPoint) + " bytesTransferred:" + bytesTransferred.ToString());
  4761. }
  4762. catch (ObjectDisposedException) { }
  4763. #endif
  4764. if (s_LoggingEnabled) {
  4765. Logging.PrintInfo(Logging.Sockets, socket, SR.GetString(SR.net_log_socket_accepted, socket.RemoteEndPoint, socket.LocalEndPoint));
  4766. Logging.Exit(Logging.Sockets, this, "EndAccept", socket);
  4767. }
  4768. return socket;
  4769. }
  4770. #endif // !MONO
  4771. #endif // !FEATURE_PAL
  4772. #if !MONO
  4773. /// <devdoc>
  4774. /// <para>
  4775. /// Disables sends and receives on a socket.
  4776. /// </para>
  4777. /// </devdoc>
  4778. public void Shutdown(SocketShutdown how) {
  4779. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Shutdown", how);
  4780. if (CleanedUp) {
  4781. throw new ObjectDisposedException(this.GetType().FullName);
  4782. }
  4783. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Shutdown() how:" + how.ToString());
  4784. // This can throw ObjectDisposedException.
  4785. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int) how);
  4786. //
  4787. // if the native call fails we'll throw a SocketException
  4788. //
  4789. errorCode = errorCode!=SocketError.SocketError ? SocketError.Success : (SocketError)Marshal.GetLastWin32Error();
  4790. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Shutdown() UnsafeNclNativeMethods.OSSOCK.shutdown returns errorCode:" + errorCode);
  4791. //
  4792. // skip good cases: success, socket already closed
  4793. //
  4794. if (errorCode!=SocketError.Success && errorCode!=SocketError.NotSocket) {
  4795. //
  4796. // update our internal state after this socket error and throw
  4797. //
  4798. SocketException socketException = new SocketException(errorCode);
  4799. UpdateStatusAfterSocketError(socketException);
  4800. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Shutdown", socketException );
  4801. throw socketException;
  4802. }
  4803. SetToDisconnected();
  4804. InternalSetBlocking(willBlockInternal);
  4805. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Shutdown", "");
  4806. }
  4807. #endif
  4808. //************* internal and private properties *************************
  4809. private static object InternalSyncObject {
  4810. get {
  4811. if (s_InternalSyncObject == null) {
  4812. object o = new object();
  4813. Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  4814. }
  4815. return s_InternalSyncObject;
  4816. }
  4817. }
  4818. #if !MONO
  4819. private CacheSet Caches
  4820. {
  4821. get
  4822. {
  4823. if (m_Caches == null)
  4824. {
  4825. // It's not too bad if extra of these are created and lost.
  4826. m_Caches = new CacheSet();
  4827. }
  4828. return m_Caches;
  4829. }
  4830. }
  4831. private void EnsureDynamicWinsockMethods()
  4832. {
  4833. if (m_DynamicWinsockMethods == null)
  4834. {
  4835. m_DynamicWinsockMethods = DynamicWinsockMethods.GetMethods(addressFamily, socketType, protocolType);
  4836. }
  4837. }
  4838. private bool AcceptEx(SafeCloseSocket listenSocketHandle,
  4839. SafeCloseSocket acceptSocketHandle,
  4840. IntPtr buffer,
  4841. int len,
  4842. int localAddressLength,
  4843. int remoteAddressLength,
  4844. out int bytesReceived,
  4845. SafeHandle overlapped)
  4846. {
  4847. EnsureDynamicWinsockMethods();
  4848. AcceptExDelegate acceptEx = m_DynamicWinsockMethods.GetDelegate<AcceptExDelegate>(listenSocketHandle);
  4849. return acceptEx(listenSocketHandle,
  4850. acceptSocketHandle,
  4851. buffer,
  4852. len,
  4853. localAddressLength,
  4854. remoteAddressLength,
  4855. out bytesReceived,
  4856. overlapped);
  4857. }
  4858. internal void GetAcceptExSockaddrs(IntPtr buffer,
  4859. int receiveDataLength,
  4860. int localAddressLength,
  4861. int remoteAddressLength,
  4862. out IntPtr localSocketAddress,
  4863. out int localSocketAddressLength,
  4864. out IntPtr remoteSocketAddress,
  4865. out int remoteSocketAddressLength)
  4866. {
  4867. EnsureDynamicWinsockMethods();
  4868. GetAcceptExSockaddrsDelegate getAcceptExSockaddrs = m_DynamicWinsockMethods.GetDelegate<GetAcceptExSockaddrsDelegate>(m_Handle);
  4869. getAcceptExSockaddrs(buffer,
  4870. receiveDataLength,
  4871. localAddressLength,
  4872. remoteAddressLength,
  4873. out localSocketAddress,
  4874. out localSocketAddressLength,
  4875. out remoteSocketAddress,
  4876. out remoteSocketAddressLength);
  4877. }
  4878. private bool DisconnectEx(SafeCloseSocket socketHandle, SafeHandle overlapped, int flags, int reserved)
  4879. {
  4880. EnsureDynamicWinsockMethods();
  4881. DisconnectExDelegate disconnectEx = m_DynamicWinsockMethods.GetDelegate<DisconnectExDelegate>(socketHandle);
  4882. return disconnectEx(socketHandle, overlapped, flags, reserved);
  4883. }
  4884. private bool DisconnectEx_Blocking(IntPtr socketHandle, IntPtr overlapped, int flags, int reserved)
  4885. {
  4886. EnsureDynamicWinsockMethods();
  4887. DisconnectExDelegate_Blocking disconnectEx_Blocking = m_DynamicWinsockMethods.GetDelegate<DisconnectExDelegate_Blocking>(m_Handle);
  4888. return disconnectEx_Blocking(socketHandle, overlapped, flags, reserved);
  4889. }
  4890. private bool ConnectEx(SafeCloseSocket socketHandle,
  4891. IntPtr socketAddress,
  4892. int socketAddressSize,
  4893. IntPtr buffer,
  4894. int dataLength,
  4895. out int bytesSent,
  4896. SafeHandle overlapped)
  4897. {
  4898. EnsureDynamicWinsockMethods();
  4899. ConnectExDelegate connectEx = m_DynamicWinsockMethods.GetDelegate<ConnectExDelegate>(socketHandle);
  4900. return connectEx(socketHandle, socketAddress, socketAddressSize, buffer, dataLength, out bytesSent, overlapped);
  4901. }
  4902. private SocketError WSARecvMsg(SafeCloseSocket socketHandle, IntPtr msg, out int bytesTransferred, SafeHandle overlapped, IntPtr completionRoutine)
  4903. {
  4904. EnsureDynamicWinsockMethods();
  4905. WSARecvMsgDelegate recvMsg = m_DynamicWinsockMethods.GetDelegate<WSARecvMsgDelegate>(socketHandle);
  4906. return recvMsg(socketHandle, msg, out bytesTransferred, overlapped, completionRoutine);
  4907. }
  4908. private SocketError WSARecvMsg_Blocking(IntPtr socketHandle, IntPtr msg, out int bytesTransferred, IntPtr overlapped, IntPtr completionRoutine)
  4909. {
  4910. EnsureDynamicWinsockMethods();
  4911. WSARecvMsgDelegate_Blocking recvMsg_Blocking = m_DynamicWinsockMethods.GetDelegate<WSARecvMsgDelegate_Blocking>(m_Handle);
  4912. return recvMsg_Blocking(socketHandle, msg, out bytesTransferred, overlapped, completionRoutine);
  4913. }
  4914. private bool TransmitPackets(SafeCloseSocket socketHandle, IntPtr packetArray, int elementCount, int sendSize, SafeNativeOverlapped overlapped, TransmitFileOptions flags)
  4915. {
  4916. EnsureDynamicWinsockMethods();
  4917. TransmitPacketsDelegate transmitPackets = m_DynamicWinsockMethods.GetDelegate<TransmitPacketsDelegate>(socketHandle);
  4918. return transmitPackets(socketHandle, packetArray, elementCount, sendSize, overlapped, flags);
  4919. }
  4920. private Queue GetAcceptQueue() {
  4921. if (m_AcceptQueueOrConnectResult == null)
  4922. Interlocked.CompareExchange(ref m_AcceptQueueOrConnectResult, new Queue(16), null);
  4923. return (Queue)m_AcceptQueueOrConnectResult;
  4924. }
  4925. #endif // !MONO
  4926. internal bool CleanedUp {
  4927. get {
  4928. return (m_IntCleanedUp == 1);
  4929. }
  4930. }
  4931. #if !MONO
  4932. internal TransportType Transport {
  4933. get {
  4934. return
  4935. protocolType==Sockets.ProtocolType.Tcp ?
  4936. TransportType.Tcp :
  4937. protocolType==Sockets.ProtocolType.Udp ?
  4938. TransportType.Udp :
  4939. TransportType.All;
  4940. }
  4941. }
  4942. //************* internal and private methods *************************
  4943. private void CheckSetOptionPermissions(SocketOptionLevel optionLevel, SocketOptionName optionName) {
  4944. // freely allow only those below
  4945. if ( !(optionLevel == SocketOptionLevel.Tcp &&
  4946. (optionName == SocketOptionName.NoDelay ||
  4947. optionName == SocketOptionName.BsdUrgent ||
  4948. optionName == SocketOptionName.Expedited))
  4949. &&
  4950. !(optionLevel == SocketOptionLevel.Udp &&
  4951. (optionName == SocketOptionName.NoChecksum||
  4952. optionName == SocketOptionName.ChecksumCoverage))
  4953. &&
  4954. !(optionLevel == SocketOptionLevel.Socket &&
  4955. (optionName == SocketOptionName.KeepAlive ||
  4956. optionName == SocketOptionName.Linger ||
  4957. optionName == SocketOptionName.DontLinger ||
  4958. optionName == SocketOptionName.SendBuffer ||
  4959. optionName == SocketOptionName.ReceiveBuffer ||
  4960. optionName == SocketOptionName.SendTimeout ||
  4961. optionName == SocketOptionName.ExclusiveAddressUse ||
  4962. optionName == SocketOptionName.ReceiveTimeout))
  4963. &&
  4964. //ipv6 protection level
  4965. !(optionLevel == SocketOptionLevel.IPv6 &&
  4966. optionName == (SocketOptionName)23)){
  4967. ExceptionHelper.UnmanagedPermission.Demand();
  4968. }
  4969. }
  4970. private SocketAddress SnapshotAndSerialize(ref EndPoint remoteEP)
  4971. {
  4972. IPEndPoint ipSnapshot = remoteEP as IPEndPoint;
  4973. if (ipSnapshot != null)
  4974. {
  4975. ipSnapshot = ipSnapshot.Snapshot();
  4976. remoteEP = RemapIPEndPoint(ipSnapshot);
  4977. }
  4978. return CallSerializeCheckDnsEndPoint(remoteEP);
  4979. }
  4980. // Give a nicer exception for DnsEndPoint in cases where it is not supported
  4981. private SocketAddress CallSerializeCheckDnsEndPoint(EndPoint remoteEP)
  4982. {
  4983. if (remoteEP is DnsEndPoint)
  4984. {
  4985. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_dnsendpoint, "remoteEP"), "remoteEP");
  4986. }
  4987. return remoteEP.Serialize();
  4988. }
  4989. // DualMode: Automatically re-map IPv4 addresses to IPv6 addresses
  4990. private IPEndPoint RemapIPEndPoint(IPEndPoint input)
  4991. {
  4992. if (input.AddressFamily == AddressFamily.InterNetwork && IsDualMode)
  4993. {
  4994. return new IPEndPoint(input.Address.MapToIPv6(), input.Port);
  4995. }
  4996. return input;
  4997. }
  4998. //
  4999. // socketAddress must always be the result of remoteEP.Serialize()
  5000. //
  5001. private SocketAddress CheckCacheRemote(ref EndPoint remoteEP, bool isOverwrite)
  5002. {
  5003. IPEndPoint ipSnapshot = remoteEP as IPEndPoint;
  5004. if (ipSnapshot != null)
  5005. {
  5006. // Snapshot to avoid external tampering and malicious derivations if IPEndPoint
  5007. ipSnapshot = ipSnapshot.Snapshot();
  5008. // DualMode: Do the security check on the user input address, but return an IPEndPoint
  5009. // mapped to an IPv6 address.
  5010. remoteEP = RemapIPEndPoint(ipSnapshot);
  5011. }
  5012. // This doesn't use SnapshotAndSerialize() because we need the ipSnapshot later.
  5013. SocketAddress socketAddress = CallSerializeCheckDnsEndPoint(remoteEP);
  5014. // We remember the first peer we have communicated with
  5015. SocketAddress permittedRemoteAddress = m_PermittedRemoteAddress;
  5016. if (permittedRemoteAddress != null && permittedRemoteAddress.Equals(socketAddress))
  5017. {
  5018. return permittedRemoteAddress;
  5019. }
  5020. //
  5021. // for now SocketPermission supports only IPEndPoint
  5022. //
  5023. if (ipSnapshot != null)
  5024. {
  5025. //
  5026. // create the permissions the user would need for the call
  5027. //
  5028. SocketPermission socketPermission
  5029. = new SocketPermission(
  5030. NetworkAccess.Connect,
  5031. Transport,
  5032. ipSnapshot.Address.ToString(),
  5033. ipSnapshot.Port);
  5034. //
  5035. // demand for them
  5036. //
  5037. socketPermission.Demand();
  5038. }
  5039. else {
  5040. //
  5041. // for V1 we will demand permission to run UnmanagedCode for
  5042. // an EndPoint that is not an IPEndPoint until we figure out how these fit
  5043. // into the whole picture of SocketPermission
  5044. //
  5045. ExceptionHelper.UnmanagedPermission.Demand();
  5046. }
  5047. //cache only the first peer we communicated with
  5048. if (m_PermittedRemoteAddress == null || isOverwrite) {
  5049. m_PermittedRemoteAddress = socketAddress;
  5050. }
  5051. return socketAddress;
  5052. }
  5053. #endif
  5054. internal static void InitializeSockets() {
  5055. if (!s_Initialized) {
  5056. lock(InternalSyncObject){
  5057. if (!s_Initialized) {
  5058. #if !MONO
  5059. WSAData wsaData = new WSAData();
  5060. SocketError errorCode =
  5061. UnsafeNclNativeMethods.OSSOCK.WSAStartup(
  5062. (short)0x0202, // we need 2.2
  5063. out wsaData );
  5064. if (errorCode!=SocketError.Success) {
  5065. //
  5066. // failed to initialize, throw
  5067. //
  5068. // WSAStartup does not set LastWin32Error
  5069. throw new SocketException(errorCode);
  5070. }
  5071. #endif
  5072. #if !FEATURE_PAL
  5073. //
  5074. // we're on WinNT4 or greater, we could use CompletionPort if we
  5075. // wanted. check if the user has disabled this functionality in
  5076. // the registry, otherwise use CompletionPort.
  5077. //
  5078. #if DEBUG
  5079. BooleanSwitch disableCompletionPortSwitch = new BooleanSwitch("DisableNetCompletionPort", "System.Net disabling of Completion Port");
  5080. //
  5081. // the following will be true if they've disabled the completionPort
  5082. //
  5083. UseOverlappedIO = disableCompletionPortSwitch.Enabled;
  5084. #endif
  5085. bool ipv4 = true;
  5086. bool ipv6 = true;
  5087. #if MONO
  5088. ipv4 = IsProtocolSupported (System.Net.NetworkInformation.NetworkInterfaceComponent.IPv4);
  5089. ipv6 = IsProtocolSupported (System.Net.NetworkInformation.NetworkInterfaceComponent.IPv6);
  5090. #else
  5091. SafeCloseSocket.InnerSafeCloseSocket socketV4 =
  5092. UnsafeNclNativeMethods.OSSOCK.WSASocket(
  5093. AddressFamily.InterNetwork,
  5094. SocketType.Dgram,
  5095. ProtocolType.IP,
  5096. IntPtr.Zero,
  5097. 0,
  5098. (SocketConstructorFlags) 0);
  5099. if (socketV4.IsInvalid) {
  5100. errorCode = (SocketError) Marshal.GetLastWin32Error();
  5101. if (errorCode == SocketError.AddressFamilyNotSupported)
  5102. ipv4 = false;
  5103. }
  5104. socketV4.Close();
  5105. SafeCloseSocket.InnerSafeCloseSocket socketV6 =
  5106. UnsafeNclNativeMethods.OSSOCK.WSASocket(
  5107. AddressFamily.InterNetworkV6,
  5108. SocketType.Dgram,
  5109. ProtocolType.IP,
  5110. IntPtr.Zero,
  5111. 0,
  5112. (SocketConstructorFlags) 0);
  5113. if (socketV6.IsInvalid) {
  5114. errorCode = (SocketError) Marshal.GetLastWin32Error();
  5115. if (errorCode == SocketError.AddressFamilyNotSupported)
  5116. ipv6 = false;
  5117. }
  5118. socketV6.Close();
  5119. // <
  5120. #endif // MONO
  5121. #if COMNET_DISABLEIPV6
  5122. //
  5123. // Turn off IPv6 support
  5124. //
  5125. ipv6 = false;
  5126. #else
  5127. //
  5128. // Now read the switch as the final check: by checking the current value for IPv6
  5129. // support we may be able to avoid a painful configuration file read.
  5130. //
  5131. if (ipv6) {
  5132. s_OSSupportsIPv6 = true;
  5133. ipv6 = SettingsSectionInternal.Section.Ipv6Enabled;
  5134. }
  5135. #endif
  5136. //
  5137. // Update final state
  5138. //
  5139. s_SupportsIPv4 = ipv4;
  5140. s_SupportsIPv6 = ipv6;
  5141. #else //!FEATURE_PAL
  5142. s_SupportsIPv4 = true;
  5143. s_SupportsIPv6 = false;
  5144. #endif //!FEATURE_PAL
  5145. // Cache some settings locally.
  5146. #if !MONO
  5147. #if !FEATURE_PAL // perfcounter
  5148. s_PerfCountersEnabled = NetworkingPerfCounters.Instance.Enabled;
  5149. #endif
  5150. #endif
  5151. s_Initialized = true;
  5152. }
  5153. }
  5154. }
  5155. }
  5156. #if !MONO
  5157. internal void InternalConnect(EndPoint remoteEP)
  5158. {
  5159. EndPoint endPointSnapshot = remoteEP;
  5160. SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
  5161. DoConnect(endPointSnapshot, socketAddress);
  5162. }
  5163. private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
  5164. {
  5165. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Connect", endPointSnapshot);
  5166. // This can throw ObjectDisposedException.
  5167. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAConnect(
  5168. m_Handle.DangerousGetHandle(),
  5169. socketAddress.m_Buffer,
  5170. socketAddress.m_Size,
  5171. IntPtr.Zero,
  5172. IntPtr.Zero,
  5173. IntPtr.Zero,
  5174. IntPtr.Zero);
  5175. #if TRAVE
  5176. try
  5177. {
  5178. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalConnect() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.WSAConnect returns errorCode:" + errorCode);
  5179. }
  5180. catch (ObjectDisposedException) { }
  5181. #endif
  5182. //
  5183. // if the native call fails we'll throw a SocketException
  5184. //
  5185. if (errorCode!=SocketError.Success) {
  5186. //
  5187. // update our internal state after this socket error and throw
  5188. //
  5189. SocketException socketException = new SocketException(endPointSnapshot);
  5190. UpdateStatusAfterSocketError(socketException);
  5191. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Connect", socketException);
  5192. throw socketException;
  5193. }
  5194. if (m_RightEndPoint==null) {
  5195. //
  5196. // save a copy of the EndPoint so we can use it for Create()
  5197. //
  5198. m_RightEndPoint = endPointSnapshot;
  5199. }
  5200. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoConnect() connection to:" + endPointSnapshot.ToString());
  5201. //
  5202. // update state and performance counter
  5203. //
  5204. SetToConnected();
  5205. if (s_LoggingEnabled) {
  5206. Logging.PrintInfo(Logging.Sockets, this, SR.GetString(SR.net_log_socket_connected, LocalEndPoint, RemoteEndPoint));
  5207. Logging.Exit(Logging.Sockets, this, "Connect", "");
  5208. }
  5209. }
  5210. protected virtual void Dispose(bool disposing)
  5211. {
  5212. if (!disposing)
  5213. {
  5214. return;
  5215. }
  5216. try
  5217. {
  5218. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() disposing:true CleanedUp:" + CleanedUp.ToString());
  5219. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Dispose", null);
  5220. }
  5221. catch (Exception exception)
  5222. {
  5223. if (NclUtilities.IsFatal(exception)) throw;
  5224. }
  5225. // make sure we're the first call to Dispose and no SetAsyncEventSelect is in progress
  5226. int last;
  5227. while ((last = Interlocked.CompareExchange(ref m_IntCleanedUp, 1, 0)) == 2)
  5228. {
  5229. Thread.SpinWait(1);
  5230. }
  5231. if (last == 1)
  5232. {
  5233. try {
  5234. if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "Dispose", null);
  5235. }
  5236. catch (Exception exception)
  5237. {
  5238. if (NclUtilities.IsFatal(exception)) throw;
  5239. }
  5240. return;
  5241. }
  5242. SetToDisconnected();
  5243. AsyncEventBits pendingAsync = AsyncEventBits.FdNone;
  5244. if (m_BlockEventBits != AsyncEventBits.FdNone)
  5245. {
  5246. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Pending nonblocking operations! m_BlockEventBits:" + m_BlockEventBits.ToString());
  5247. UnsetAsyncEventSelect();
  5248. if (m_BlockEventBits == AsyncEventBits.FdConnect)
  5249. {
  5250. LazyAsyncResult connectResult = m_AcceptQueueOrConnectResult as LazyAsyncResult;
  5251. if (connectResult != null && !connectResult.InternalPeekCompleted)
  5252. pendingAsync = AsyncEventBits.FdConnect;
  5253. }
  5254. else if (m_BlockEventBits == AsyncEventBits.FdAccept)
  5255. {
  5256. Queue acceptQueue = m_AcceptQueueOrConnectResult as Queue;
  5257. if (acceptQueue != null && acceptQueue.Count != 0)
  5258. pendingAsync = AsyncEventBits.FdAccept;
  5259. }
  5260. }
  5261. #if SOCKETTHREADPOOL
  5262. if (m_BoundToThreadPool) SocketThreadPool.UnBindHandle(m_Handle);
  5263. #endif
  5264. // Close the handle in one of several ways depending on the timeout.
  5265. // Ignore ObjectDisposedException just in case the handle somehow gets disposed elsewhere.
  5266. try
  5267. {
  5268. int timeout = m_CloseTimeout;
  5269. if (timeout == 0)
  5270. {
  5271. // Abortive.
  5272. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Calling m_Handle.Dispose()");
  5273. m_Handle.Dispose();
  5274. }
  5275. else
  5276. {
  5277. SocketError errorCode;
  5278. // Go to blocking mode. We know no WSAEventSelect is pending because of the lock and UnsetAsyncEventSelect() above.
  5279. if (!willBlock || !willBlockInternal)
  5280. {
  5281. int nonBlockCmd = 0;
  5282. errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
  5283. m_Handle,
  5284. IoctlSocketConstants.FIONBIO,
  5285. ref nonBlockCmd);
  5286. GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") ioctlsocket(FIONBIO):" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
  5287. }
  5288. if (timeout < 0)
  5289. {
  5290. // Close with existing user-specified linger option.
  5291. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Calling m_Handle.CloseAsIs()");
  5292. m_Handle.CloseAsIs();
  5293. }
  5294. else
  5295. {
  5296. // Since our timeout is in ms and linger is in seconds, implement our own sortof linger here.
  5297. errorCode = UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int) SocketShutdown.Send);
  5298. GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") shutdown():" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
  5299. // This should give us a timeout in milliseconds.
  5300. errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
  5301. m_Handle,
  5302. SocketOptionLevel.Socket,
  5303. SocketOptionName.ReceiveTimeout,
  5304. ref timeout,
  5305. sizeof(int));
  5306. GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") setsockopt():" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
  5307. if (errorCode != SocketError.Success)
  5308. {
  5309. m_Handle.Dispose();
  5310. }
  5311. else
  5312. {
  5313. unsafe
  5314. {
  5315. errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), null, 0, SocketFlags.None);
  5316. }
  5317. GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") recv():" + errorCode.ToString());
  5318. if (errorCode != (SocketError) 0)
  5319. {
  5320. // We got a timeout - abort.
  5321. m_Handle.Dispose();
  5322. }
  5323. else
  5324. {
  5325. // We got a FIN or data. Use ioctlsocket to find out which.
  5326. int dataAvailable = 0;
  5327. errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
  5328. m_Handle,
  5329. IoctlSocketConstants.FIONREAD,
  5330. ref dataAvailable);
  5331. GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") ioctlsocket(FIONREAD):" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
  5332. if (errorCode != SocketError.Success || dataAvailable != 0)
  5333. {
  5334. // If we have data or don't know, safest thing is to reset.
  5335. m_Handle.Dispose();
  5336. }
  5337. else
  5338. {
  5339. // We got a FIN. It'd be nice to block for the remainder of the timeout for the handshake to finsh.
  5340. // Since there's no real way to do that, close the socket with the user's preferences. This lets
  5341. // the user decide how best to handle this case via the linger options.
  5342. m_Handle.CloseAsIs();
  5343. }
  5344. }
  5345. }
  5346. }
  5347. }
  5348. }
  5349. catch (ObjectDisposedException)
  5350. {
  5351. GlobalLog.Assert("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ")", "Closing the handle threw ObjectDisposedException.");
  5352. }
  5353. #if !DEBUG
  5354. // Clear out the Overlapped caches.
  5355. if (m_Caches != null)
  5356. {
  5357. OverlappedCache.InterlockedFree(ref m_Caches.SendOverlappedCache);
  5358. OverlappedCache.InterlockedFree(ref m_Caches.ReceiveOverlappedCache);
  5359. }
  5360. #endif
  5361. if (pendingAsync == AsyncEventBits.FdConnect)
  5362. {
  5363. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() QueueUserWorkItem for ConnectCallback");
  5364. // This will try to complete connectResult on a different thread
  5365. ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(((LazyAsyncResult)m_AcceptQueueOrConnectResult).InvokeCallback), new SocketException(SocketError.OperationAborted));
  5366. }
  5367. else if (pendingAsync == AsyncEventBits.FdAccept)
  5368. {
  5369. // This will try to complete all acceptResults on a different thread
  5370. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() QueueUserWorkItem for AcceptCallback");
  5371. ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(CompleteAcceptResults), null);
  5372. }
  5373. if (m_AsyncEvent != null)
  5374. {
  5375. m_AsyncEvent.Close();
  5376. }
  5377. }
  5378. #endif // !MONO
  5379. public void Dispose() {
  5380. Dispose(true);
  5381. GC.SuppressFinalize(this);
  5382. }
  5383. ~Socket() {
  5384. Dispose(false);
  5385. }
  5386. #if !MONO
  5387. // this version does not throw.
  5388. internal void InternalShutdown(SocketShutdown how) {
  5389. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalShutdown() how:" + how.ToString());
  5390. if (CleanedUp || m_Handle.IsInvalid) {
  5391. return;
  5392. }
  5393. try
  5394. {
  5395. UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int)how);
  5396. }
  5397. catch (ObjectDisposedException) { }
  5398. }
  5399. // Set the socket option to begin receiving packet information if it has not been
  5400. // set for this socket previously
  5401. internal void SetReceivingPacketInformation()
  5402. {
  5403. if (!m_ReceivingPacketInformation)
  5404. {
  5405. // DualMode: When bound to IPv6Any you must enable both socket options.
  5406. // When bound to an IPv4 mapped IPv6 address you must enable the IPv4 socket option.
  5407. IPEndPoint ipEndPoint = m_RightEndPoint as IPEndPoint;
  5408. IPAddress boundAddress = (ipEndPoint != null ? ipEndPoint.Address : null);
  5409. Debug.Assert(boundAddress != null, "Not Bound");
  5410. if (this.addressFamily == AddressFamily.InterNetwork
  5411. || (boundAddress != null && IsDualMode
  5412. && (boundAddress.IsIPv4MappedToIPv6 || boundAddress.Equals(IPAddress.IPv6Any))))
  5413. {
  5414. SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
  5415. }
  5416. if (this.addressFamily == AddressFamily.InterNetworkV6
  5417. && (boundAddress == null || !boundAddress.IsIPv4MappedToIPv6))
  5418. {
  5419. SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true);
  5420. }
  5421. m_ReceivingPacketInformation = true;
  5422. }
  5423. }
  5424. internal unsafe void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue, bool silent) {
  5425. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() optionLevel:" + optionLevel + " optionName:" + optionName + " optionValue:" + optionValue + " silent:" + silent);
  5426. if (silent && (CleanedUp || m_Handle.IsInvalid)) {
  5427. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() skipping the call");
  5428. return;
  5429. }
  5430. SocketError errorCode = SocketError.Success;
  5431. try {
  5432. // This can throw ObjectDisposedException.
  5433. errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
  5434. m_Handle,
  5435. optionLevel,
  5436. optionName,
  5437. ref optionValue,
  5438. sizeof(int));
  5439. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
  5440. }
  5441. catch {
  5442. if (silent && m_Handle.IsInvalid) {
  5443. return;
  5444. }
  5445. throw;
  5446. }
  5447. // Keep the internal state in sync if the user manually resets this
  5448. if (optionName == SocketOptionName.PacketInformation && optionValue == 0 &&
  5449. errorCode == SocketError.Success)
  5450. {
  5451. m_ReceivingPacketInformation = false;
  5452. }
  5453. if (silent) {
  5454. return;
  5455. }
  5456. //
  5457. // if the native call fails we'll throw a SocketException
  5458. //
  5459. if (errorCode==SocketError.SocketError) {
  5460. //
  5461. // update our internal state after this socket error and throw
  5462. //
  5463. SocketException socketException = new SocketException();
  5464. UpdateStatusAfterSocketError(socketException);
  5465. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SetSocketOption", socketException);
  5466. throw socketException;
  5467. }
  5468. }
  5469. private void setMulticastOption(SocketOptionName optionName, MulticastOption MR) {
  5470. IPMulticastRequest ipmr = new IPMulticastRequest();
  5471. ipmr.MulticastAddress = unchecked((int)MR.Group.m_Address);
  5472. if(MR.LocalAddress != null){
  5473. ipmr.InterfaceAddress = unchecked((int)MR.LocalAddress.m_Address);
  5474. }
  5475. else { //this structure works w/ interfaces as well
  5476. int ifIndex =IPAddress.HostToNetworkOrder(MR.InterfaceIndex);
  5477. ipmr.InterfaceAddress = unchecked((int)ifIndex);
  5478. }
  5479. #if BIGENDIAN
  5480. ipmr.MulticastAddress = (int) (((uint) ipmr.MulticastAddress << 24) |
  5481. (((uint) ipmr.MulticastAddress & 0x0000FF00) << 8) |
  5482. (((uint) ipmr.MulticastAddress >> 8) & 0x0000FF00) |
  5483. ((uint) ipmr.MulticastAddress >> 24));
  5484. if(MR.LocalAddress != null){
  5485. ipmr.InterfaceAddress = (int) (((uint) ipmr.InterfaceAddress << 24) |
  5486. (((uint) ipmr.InterfaceAddress & 0x0000FF00) << 8) |
  5487. (((uint) ipmr.InterfaceAddress >> 8) & 0x0000FF00) |
  5488. ((uint) ipmr.InterfaceAddress >> 24));
  5489. }
  5490. #endif // BIGENDIAN
  5491. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setMulticastOption(): optionName:" + optionName.ToString() + " MR:" + MR.ToString() + " ipmr:" + ipmr.ToString() + " IPMulticastRequest.Size:" + IPMulticastRequest.Size.ToString());
  5492. // This can throw ObjectDisposedException.
  5493. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
  5494. m_Handle,
  5495. SocketOptionLevel.IP,
  5496. optionName,
  5497. ref ipmr,
  5498. IPMulticastRequest.Size);
  5499. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setMulticastOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
  5500. //
  5501. // if the native call fails we'll throw a SocketException
  5502. //
  5503. if (errorCode==SocketError.SocketError) {
  5504. //
  5505. // update our internal state after this socket error and throw
  5506. //
  5507. SocketException socketException = new SocketException();
  5508. UpdateStatusAfterSocketError(socketException);
  5509. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setMulticastOption", socketException);
  5510. throw socketException;
  5511. }
  5512. }
  5513. /// <devdoc>
  5514. /// <para>
  5515. /// IPv6 setsockopt for JOIN / LEAVE multicast group
  5516. /// </para>
  5517. /// </devdoc>
  5518. private void setIPv6MulticastOption(SocketOptionName optionName, IPv6MulticastOption MR) {
  5519. IPv6MulticastRequest ipmr = new IPv6MulticastRequest();
  5520. ipmr.MulticastAddress = MR.Group.GetAddressBytes();
  5521. ipmr.InterfaceIndex = unchecked((int)MR.InterfaceIndex);
  5522. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setIPv6MulticastOption(): optionName:" + optionName.ToString() + " MR:" + MR.ToString() + " ipmr:" + ipmr.ToString() + " IPv6MulticastRequest.Size:" + IPv6MulticastRequest.Size.ToString());
  5523. // This can throw ObjectDisposedException.
  5524. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
  5525. m_Handle,
  5526. SocketOptionLevel.IPv6,
  5527. optionName,
  5528. ref ipmr,
  5529. IPv6MulticastRequest.Size);
  5530. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setIPv6MulticastOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
  5531. //
  5532. // if the native call fails we'll throw a SocketException
  5533. //
  5534. if (errorCode==SocketError.SocketError) {
  5535. //
  5536. // update our internal state after this socket error and throw
  5537. //
  5538. SocketException socketException = new SocketException();
  5539. UpdateStatusAfterSocketError(socketException);
  5540. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setIPv6MulticastOption", socketException);
  5541. throw socketException;
  5542. }
  5543. }
  5544. private void setLingerOption(LingerOption lref) {
  5545. Linger lngopt = new Linger();
  5546. lngopt.OnOff = lref.Enabled ? (ushort)1 : (ushort)0;
  5547. lngopt.Time = (ushort)lref.LingerTime;
  5548. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setLingerOption(): lref:" + lref.ToString());
  5549. // This can throw ObjectDisposedException.
  5550. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
  5551. m_Handle,
  5552. SocketOptionLevel.Socket,
  5553. SocketOptionName.Linger,
  5554. ref lngopt,
  5555. 4);
  5556. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setLingerOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
  5557. //
  5558. // if the native call fails we'll throw a SocketException
  5559. //
  5560. if (errorCode==SocketError.SocketError) {
  5561. //
  5562. // update our internal state after this socket error and throw
  5563. //
  5564. SocketException socketException = new SocketException();
  5565. UpdateStatusAfterSocketError(socketException);
  5566. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setLingerOption", socketException);
  5567. throw socketException;
  5568. }
  5569. }
  5570. private LingerOption getLingerOpt() {
  5571. Linger lngopt = new Linger();
  5572. int optlen = 4;
  5573. // This can throw ObjectDisposedException.
  5574. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
  5575. m_Handle,
  5576. SocketOptionLevel.Socket,
  5577. SocketOptionName.Linger,
  5578. out lngopt,
  5579. ref optlen);
  5580. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getLingerOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
  5581. //
  5582. // if the native call fails we'll throw a SocketException
  5583. //
  5584. if (errorCode==SocketError.SocketError) {
  5585. //
  5586. // update our internal state after this socket error and throw
  5587. //
  5588. SocketException socketException = new SocketException();
  5589. UpdateStatusAfterSocketError(socketException);
  5590. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getLingerOpt", socketException);
  5591. throw socketException;
  5592. }
  5593. LingerOption lingerOption = new LingerOption(lngopt.OnOff!=0, (int)lngopt.Time);
  5594. return lingerOption;
  5595. }
  5596. private MulticastOption getMulticastOpt(SocketOptionName optionName) {
  5597. IPMulticastRequest ipmr = new IPMulticastRequest();
  5598. int optlen = IPMulticastRequest.Size;
  5599. // This can throw ObjectDisposedException.
  5600. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
  5601. m_Handle,
  5602. SocketOptionLevel.IP,
  5603. optionName,
  5604. out ipmr,
  5605. ref optlen);
  5606. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getMulticastOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
  5607. //
  5608. // if the native call fails we'll throw a SocketException
  5609. //
  5610. if (errorCode==SocketError.SocketError) {
  5611. //
  5612. // update our internal state after this socket error and throw
  5613. //
  5614. SocketException socketException = new SocketException();
  5615. UpdateStatusAfterSocketError(socketException);
  5616. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getMulticastOpt", socketException);
  5617. throw socketException;
  5618. }
  5619. #if BIGENDIAN
  5620. ipmr.MulticastAddress = (int) (((uint) ipmr.MulticastAddress << 24) |
  5621. (((uint) ipmr.MulticastAddress & 0x0000FF00) << 8) |
  5622. (((uint) ipmr.MulticastAddress >> 8) & 0x0000FF00) |
  5623. ((uint) ipmr.MulticastAddress >> 24));
  5624. ipmr.InterfaceAddress = (int) (((uint) ipmr.InterfaceAddress << 24) |
  5625. (((uint) ipmr.InterfaceAddress & 0x0000FF00) << 8) |
  5626. (((uint) ipmr.InterfaceAddress >> 8) & 0x0000FF00) |
  5627. ((uint) ipmr.InterfaceAddress >> 24));
  5628. #endif // BIGENDIAN
  5629. IPAddress multicastAddr = new IPAddress(ipmr.MulticastAddress);
  5630. IPAddress multicastIntr = new IPAddress(ipmr.InterfaceAddress);
  5631. MulticastOption multicastOption = new MulticastOption(multicastAddr, multicastIntr);
  5632. return multicastOption;
  5633. }
  5634. /// <devdoc>
  5635. /// <para>
  5636. /// IPv6 getsockopt for JOIN / LEAVE multicast group
  5637. /// </para>
  5638. /// </devdoc>
  5639. private IPv6MulticastOption getIPv6MulticastOpt(SocketOptionName optionName) {
  5640. IPv6MulticastRequest ipmr = new IPv6MulticastRequest();
  5641. int optlen = IPv6MulticastRequest.Size;
  5642. // This can throw ObjectDisposedException.
  5643. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
  5644. m_Handle,
  5645. SocketOptionLevel.IP,
  5646. optionName,
  5647. out ipmr,
  5648. ref optlen);
  5649. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getIPv6MulticastOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
  5650. //
  5651. // if the native call fails we'll throw a SocketException
  5652. //
  5653. if (errorCode==SocketError.SocketError) {
  5654. //
  5655. // update our internal state after this socket error and throw
  5656. //
  5657. SocketException socketException = new SocketException();
  5658. UpdateStatusAfterSocketError(socketException);
  5659. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getIPv6MulticastOpt", socketException);
  5660. throw socketException;
  5661. }
  5662. IPv6MulticastOption multicastOption = new IPv6MulticastOption(new IPAddress(ipmr.MulticastAddress),ipmr.InterfaceIndex);
  5663. return multicastOption;
  5664. }
  5665. //
  5666. // this version will ignore failures but it returns the win32
  5667. // error code, and it will update internal state on success.
  5668. //
  5669. private SocketError InternalSetBlocking(bool desired, out bool current) {
  5670. GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "desired:" + desired.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
  5671. if (CleanedUp) {
  5672. GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "ObjectDisposed");
  5673. current = willBlock;
  5674. return SocketError.Success;
  5675. }
  5676. int intBlocking = desired ? 0 : -1;
  5677. //
  5678. SocketError errorCode;
  5679. try
  5680. {
  5681. errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
  5682. m_Handle,
  5683. IoctlSocketConstants.FIONBIO,
  5684. ref intBlocking);
  5685. if (errorCode == SocketError.SocketError)
  5686. {
  5687. errorCode = (SocketError) Marshal.GetLastWin32Error();
  5688. }
  5689. }
  5690. catch (ObjectDisposedException)
  5691. {
  5692. errorCode = SocketError.NotSocket;
  5693. }
  5694. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking() UnsafeNclNativeMethods.OSSOCK.ioctlsocket returns errorCode:" + errorCode);
  5695. //
  5696. // we will update only internal state but only on successfull win32 call
  5697. // so if the native call fails, the state will remain the same.
  5698. //
  5699. if (errorCode==SocketError.Success) {
  5700. //
  5701. // success, update internal state
  5702. //
  5703. willBlockInternal = intBlocking==0;
  5704. }
  5705. GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "errorCode:" + errorCode.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
  5706. current = willBlockInternal;
  5707. return errorCode;
  5708. }
  5709. //
  5710. // this version will ignore all failures.
  5711. //
  5712. internal void InternalSetBlocking(bool desired) {
  5713. bool current;
  5714. InternalSetBlocking(desired, out current);
  5715. }
  5716. private static IntPtr[] SocketListToFileDescriptorSet(IList socketList) {
  5717. if (socketList==null || socketList.Count==0) {
  5718. return null;
  5719. }
  5720. IntPtr[] fileDescriptorSet = new IntPtr[socketList.Count + 1];
  5721. fileDescriptorSet[0] = (IntPtr)socketList.Count;
  5722. for (int current=0; current<socketList.Count; current++) {
  5723. if (!(socketList[current] is Socket)) {
  5724. throw new ArgumentException(SR.GetString(SR.net_sockets_select, socketList[current].GetType().FullName, typeof(System.Net.Sockets.Socket).FullName), "socketList");
  5725. }
  5726. fileDescriptorSet[current + 1] = ((Socket)socketList[current]).m_Handle.DangerousGetHandle();
  5727. }
  5728. return fileDescriptorSet;
  5729. }
  5730. //
  5731. // Transform the list socketList such that the only sockets left are those
  5732. // with a file descriptor contained in the array "fileDescriptorArray"
  5733. //
  5734. private static void SelectFileDescriptor(IList socketList, IntPtr[] fileDescriptorSet) {
  5735. // Walk the list in order
  5736. // Note that the counter is not necessarily incremented at each step;
  5737. // when the socket is removed, advancing occurs automatically as the
  5738. // other elements are shifted down.
  5739. if (socketList==null || socketList.Count==0) {
  5740. return;
  5741. }
  5742. if ((int)fileDescriptorSet[0]==0) {
  5743. // no socket present, will never find any socket, remove them all
  5744. socketList.Clear();
  5745. return;
  5746. }
  5747. lock (socketList) {
  5748. for (int currentSocket=0; currentSocket<socketList.Count; currentSocket++) {
  5749. Socket socket = socketList[currentSocket] as Socket;
  5750. // Look for the file descriptor in the array
  5751. int currentFileDescriptor;
  5752. for (currentFileDescriptor=0; currentFileDescriptor<(int)fileDescriptorSet[0]; currentFileDescriptor++) {
  5753. if (fileDescriptorSet[currentFileDescriptor + 1]==socket.m_Handle.DangerousGetHandle()) {
  5754. break;
  5755. }
  5756. }
  5757. if (currentFileDescriptor==(int)fileDescriptorSet[0]) {
  5758. // descriptor not found: remove the current socket and start again
  5759. socketList.RemoveAt(currentSocket--);
  5760. }
  5761. }
  5762. }
  5763. }
  5764. private static void MicrosecondsToTimeValue(long microSeconds, ref TimeValue socketTime) {
  5765. socketTime.Seconds = (int) (microSeconds / microcnv);
  5766. socketTime.Microseconds = (int) (microSeconds % microcnv);
  5767. }
  5768. //Implements ConnectEx - this provides completion port IO and support for
  5769. //disconnect and reconnects
  5770. // Since this is private, the unsafe mode is specified with a flag instead of an overload.
  5771. private IAsyncResult BeginConnectEx(EndPoint remoteEP, bool flowContext, AsyncCallback callback, object state)
  5772. {
  5773. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnectEx", "");
  5774. // This will check the permissions for connect.
  5775. EndPoint endPointSnapshot = remoteEP;
  5776. SocketAddress socketAddress = flowContext ? CheckCacheRemote(ref endPointSnapshot, true) : SnapshotAndSerialize(ref endPointSnapshot);
  5777. //socket must be bound first
  5778. //the calling method BeginConnect will ensure that this method is only
  5779. //called if m_RightEndPoint is not null, of that the endpoint is an ipendpoint
  5780. if (m_RightEndPoint==null){
  5781. GlobalLog.Assert(endPointSnapshot.GetType() == typeof(IPEndPoint), "Socket#{0}::BeginConnectEx()|Socket not bound and endpoint not IPEndPoint.", ValidationHelper.HashString(this));
  5782. if (endPointSnapshot.AddressFamily == AddressFamily.InterNetwork)
  5783. InternalBind(new IPEndPoint(IPAddress.Any, 0));
  5784. else
  5785. InternalBind(new IPEndPoint(IPAddress.IPv6Any, 0));
  5786. }
  5787. //
  5788. // Allocate the async result and the event we'll pass to the
  5789. // thread pool.
  5790. //
  5791. ConnectOverlappedAsyncResult asyncResult = new ConnectOverlappedAsyncResult(this, endPointSnapshot, state, callback);
  5792. // If context flowing is enabled, set it up here. No need to lock since the context isn't used until the callback.
  5793. if (flowContext)
  5794. {
  5795. asyncResult.StartPostingAsyncOp(false);
  5796. }
  5797. // This will pin socketAddress buffer
  5798. asyncResult.SetUnmanagedStructures(socketAddress.m_Buffer);
  5799. //we should fix this in Whidbey.
  5800. EndPoint oldEndPoint = m_RightEndPoint;
  5801. if (m_RightEndPoint == null) {
  5802. m_RightEndPoint = endPointSnapshot;
  5803. }
  5804. SocketError errorCode=SocketError.Success;
  5805. int ignoreBytesSent;
  5806. try
  5807. {
  5808. if (!ConnectEx(
  5809. m_Handle,
  5810. Marshal.UnsafeAddrOfPinnedArrayElement(socketAddress.m_Buffer, 0),
  5811. socketAddress.m_Size,
  5812. IntPtr.Zero,
  5813. 0,
  5814. out ignoreBytesSent,
  5815. asyncResult.OverlappedHandle))
  5816. {
  5817. errorCode = (SocketError)Marshal.GetLastWin32Error();
  5818. }
  5819. }
  5820. catch
  5821. {
  5822. //
  5823. // Bug 152350: If ConnectEx throws we need to unpin the socketAddress buffer.
  5824. // m_RightEndPoint will always equal oldEndPoint anyways...
  5825. //
  5826. asyncResult.InternalCleanup();
  5827. m_RightEndPoint = oldEndPoint;
  5828. throw;
  5829. }
  5830. if (errorCode == SocketError.Success) {
  5831. SetToConnected();
  5832. }
  5833. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginConnectEx() UnsafeNclNativeMethods.OSSOCK.connect returns:" + errorCode.ToString());
  5834. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  5835. //
  5836. // if the asynchronous native call fails synchronously
  5837. // we'll throw a SocketException
  5838. //
  5839. if (errorCode != SocketError.Success) {
  5840. //
  5841. // update our internal state after this socket error and throw
  5842. //
  5843. m_RightEndPoint = oldEndPoint;
  5844. SocketException socketException = new SocketException(errorCode);
  5845. UpdateStatusAfterSocketError(socketException);
  5846. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginConnectEx", socketException);
  5847. throw socketException;
  5848. }
  5849. // We didn't throw, so indicate that we're returning this result to the user. This may call the callback.
  5850. // This is a nop if the context isn't being flowed.
  5851. asyncResult.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
  5852. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginConnectEx() to:" + endPointSnapshot.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  5853. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnectEx", asyncResult);
  5854. return asyncResult;
  5855. }
  5856. internal void MultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags) {
  5857. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "MultipleSend", "");
  5858. if (CleanedUp) {
  5859. throw new ObjectDisposedException(this.GetType().FullName);
  5860. }
  5861. //
  5862. // parameter validation
  5863. //
  5864. GlobalLog.Assert(buffers != null, "Socket#{0}::MultipleSend()|buffers == null", ValidationHelper.HashString(this));
  5865. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::MultipleSend() buffers.Length:" + buffers.Length.ToString());
  5866. WSABuffer[] WSABuffers = new WSABuffer[buffers.Length];
  5867. GCHandle[] objectsToPin = null;
  5868. int bytesTransferred;
  5869. SocketError errorCode;
  5870. try {
  5871. objectsToPin = new GCHandle[buffers.Length];
  5872. for (int i = 0; i < buffers.Length; ++i)
  5873. {
  5874. objectsToPin[i] = GCHandle.Alloc(buffers[i].Buffer, GCHandleType.Pinned);
  5875. WSABuffers[i].Length = buffers[i].Size;
  5876. WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffers[i].Buffer, buffers[i].Offset);
  5877. }
  5878. // This can throw ObjectDisposedException.
  5879. errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend_Blocking(
  5880. m_Handle.DangerousGetHandle(),
  5881. WSABuffers,
  5882. WSABuffers.Length,
  5883. out bytesTransferred,
  5884. socketFlags,
  5885. SafeNativeOverlapped.Zero,
  5886. IntPtr.Zero);
  5887. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::MultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString());
  5888. }
  5889. finally {
  5890. if (objectsToPin != null)
  5891. for (int i = 0; i < objectsToPin.Length; ++i)
  5892. if (objectsToPin[i].IsAllocated)
  5893. objectsToPin[i].Free();
  5894. }
  5895. if (errorCode!=SocketError.Success) {
  5896. SocketException socketException = new SocketException();
  5897. UpdateStatusAfterSocketError(socketException);
  5898. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "MultipleSend", socketException);
  5899. throw socketException;
  5900. }
  5901. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "MultipleSend", "");
  5902. }
  5903. private static void DnsCallback(IAsyncResult result){
  5904. if (result.CompletedSynchronously)
  5905. return;
  5906. bool invokeCallback = false;
  5907. MultipleAddressConnectAsyncResult context = (MultipleAddressConnectAsyncResult) result.AsyncState;
  5908. try
  5909. {
  5910. invokeCallback = DoDnsCallback(result, context);
  5911. }
  5912. catch (Exception exception)
  5913. {
  5914. context.InvokeCallback(exception);
  5915. }
  5916. // Invoke the callback outside of the try block so we don't catch user Exceptions
  5917. if (invokeCallback)
  5918. {
  5919. context.InvokeCallback();
  5920. }
  5921. }
  5922. private static bool DoDnsCallback(IAsyncResult result, MultipleAddressConnectAsyncResult context)
  5923. {
  5924. IPAddress[] addresses = Dns.EndGetHostAddresses(result);
  5925. context.addresses = addresses;
  5926. return DoMultipleAddressConnectCallback(PostOneBeginConnect(context), context);
  5927. }
  5928. private class MultipleAddressConnectAsyncResult : ContextAwareResult
  5929. {
  5930. internal MultipleAddressConnectAsyncResult(IPAddress[] addresses, int port, Socket socket, object myState, AsyncCallback myCallBack) :
  5931. base(socket, myState, myCallBack)
  5932. {
  5933. this.addresses = addresses;
  5934. this.port = port;
  5935. this.socket = socket;
  5936. }
  5937. internal Socket socket; // Keep this member just to avoid all the casting.
  5938. internal IPAddress[] addresses;
  5939. internal int index;
  5940. internal int port;
  5941. internal Exception lastException;
  5942. internal EndPoint RemoteEndPoint {
  5943. get {
  5944. if (addresses != null && index > 0 && index < addresses.Length) {
  5945. return new IPEndPoint(addresses[index], port);
  5946. } else {
  5947. return null;
  5948. }
  5949. }
  5950. }
  5951. }
  5952. private static object PostOneBeginConnect(MultipleAddressConnectAsyncResult context)
  5953. {
  5954. IPAddress currentAddressSnapshot = context.addresses[context.index];
  5955. if (!context.socket.CanTryAddressFamily(currentAddressSnapshot.AddressFamily))
  5956. {
  5957. return context.lastException != null ? context.lastException : new ArgumentException(SR.GetString(SR.net_invalidAddressList), "context");
  5958. }
  5959. try
  5960. {
  5961. EndPoint endPoint = new IPEndPoint(currentAddressSnapshot, context.port);
  5962. // MSRC 11081 - Do the necessary security demand
  5963. context.socket.CheckCacheRemote(ref endPoint, true);
  5964. IAsyncResult connectResult = context.socket.UnsafeBeginConnect(endPoint,
  5965. new AsyncCallback(MultipleAddressConnectCallback), context);
  5966. if (connectResult.CompletedSynchronously)
  5967. {
  5968. return connectResult;
  5969. }
  5970. }
  5971. catch (Exception exception)
  5972. {
  5973. if (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException)
  5974. throw;
  5975. return exception;
  5976. }
  5977. return null;
  5978. }
  5979. private static void MultipleAddressConnectCallback(IAsyncResult result)
  5980. {
  5981. if (result.CompletedSynchronously)
  5982. return;
  5983. bool invokeCallback = false;
  5984. MultipleAddressConnectAsyncResult context = (MultipleAddressConnectAsyncResult) result.AsyncState;
  5985. try
  5986. {
  5987. invokeCallback = DoMultipleAddressConnectCallback(result, context);
  5988. }
  5989. catch (Exception exception)
  5990. {
  5991. context.InvokeCallback(exception);
  5992. }
  5993. // Invoke the callback outside of the try block so we don't catch user Exceptions
  5994. if (invokeCallback)
  5995. {
  5996. context.InvokeCallback();
  5997. }
  5998. }
  5999. // This is like a regular async callback worker, except the result can be an exception. This is a useful pattern when
  6000. // processing should continue whether or not an async step failed.
  6001. private static bool DoMultipleAddressConnectCallback(object result, MultipleAddressConnectAsyncResult context)
  6002. {
  6003. while (result != null)
  6004. {
  6005. Exception ex = result as Exception;
  6006. if (ex == null)
  6007. {
  6008. try
  6009. {
  6010. context.socket.EndConnect((IAsyncResult) result);
  6011. }
  6012. catch (Exception exception)
  6013. {
  6014. ex = exception;
  6015. }
  6016. }
  6017. if (ex == null)
  6018. {
  6019. // Don't invoke the callback from here, because we're probably inside
  6020. // a catch-all block that would eat exceptions from the callback.
  6021. // Instead tell our caller to invoke the callback outside of its catchall.
  6022. return true;
  6023. }
  6024. else
  6025. {
  6026. if (++context.index >= context.addresses.Length)
  6027. throw ex;
  6028. context.lastException = ex;
  6029. result = PostOneBeginConnect(context);
  6030. }
  6031. }
  6032. // Don't invoke the callback at all, because we've posted another async connection attempt
  6033. return false;
  6034. }
  6035. internal IAsyncResult BeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state) {
  6036. // Set up the async result and start the flow.
  6037. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  6038. asyncResult.StartPostingAsyncOp(false);
  6039. // Start the send.
  6040. DoBeginMultipleSend(buffers, socketFlags, asyncResult);
  6041. // Finish it up (capture, complete).
  6042. asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
  6043. return asyncResult;
  6044. }
  6045. internal IAsyncResult UnsafeBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
  6046. {
  6047. // Unsafe - don't flow.
  6048. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  6049. DoBeginMultipleSend(buffers, socketFlags, asyncResult);
  6050. return asyncResult;
  6051. }
  6052. private void DoBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
  6053. {
  6054. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginMultipleSend", "");
  6055. if (CleanedUp) {
  6056. throw new ObjectDisposedException(this.GetType().FullName);
  6057. }
  6058. //
  6059. // parameter validation
  6060. //
  6061. GlobalLog.Assert(buffers != null, "Socket#{0}::DoBeginMultipleSend()|buffers == null", ValidationHelper.HashString(this));
  6062. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginMultipleSend() buffers.Length:" + buffers.Length.ToString());
  6063. // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
  6064. // avoid a Socket leak in case of error.
  6065. SocketError errorCode = SocketError.SocketError;
  6066. try
  6067. {
  6068. // Set up asyncResult for overlapped WSASend.
  6069. // This call will use completion ports on WinNT and Overlapped IO on Win9x.
  6070. asyncResult.SetUnmanagedStructures(buffers, ref Caches.SendOverlappedCache);
  6071. // This can throw ObjectDisposedException.
  6072. int bytesTransferred;
  6073. errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
  6074. m_Handle,
  6075. asyncResult.m_WSABuffers,
  6076. asyncResult.m_WSABuffers.Length,
  6077. out bytesTransferred,
  6078. socketFlags,
  6079. asyncResult.OverlappedHandle,
  6080. IntPtr.Zero);
  6081. if (errorCode!=SocketError.Success) {
  6082. errorCode = (SocketError)Marshal.GetLastWin32Error();
  6083. }
  6084. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginMultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
  6085. }
  6086. finally
  6087. {
  6088. errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
  6089. }
  6090. //
  6091. // if the asynchronous native call fails synchronously
  6092. // we'll throw a SocketException
  6093. //
  6094. if (errorCode!=SocketError.Success) {
  6095. //
  6096. // update our internal state after this socket error and throw
  6097. //
  6098. asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  6099. SocketException socketException = new SocketException(errorCode);
  6100. UpdateStatusAfterSocketError(socketException);
  6101. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginMultipleSend", socketException);
  6102. throw socketException;
  6103. }
  6104. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginMultipleSend", asyncResult);
  6105. }
  6106. internal int EndMultipleSend(IAsyncResult asyncResult) {
  6107. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndMultipleSend", asyncResult);
  6108. //
  6109. // parameter validation
  6110. //
  6111. GlobalLog.Assert(asyncResult != null, "Socket#{0}::EndMultipleSend()|asyncResult == null", ValidationHelper.HashString(this));
  6112. OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
  6113. GlobalLog.Assert(castedAsyncResult != null, "Socket#{0}::EndMultipleSend()|castedAsyncResult == null", ValidationHelper.HashString(this));
  6114. GlobalLog.Assert(castedAsyncResult.AsyncObject == this, "Socket#{0}::EndMultipleSend()|castedAsyncResult.AsyncObject != this", ValidationHelper.HashString(this));
  6115. GlobalLog.Assert(!castedAsyncResult.EndCalled, "Socket#{0}::EndMultipleSend()|castedAsyncResult.EndCalled", ValidationHelper.HashString(this));
  6116. int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
  6117. castedAsyncResult.EndCalled = true;
  6118. castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
  6119. #if !FEATURE_PAL // perfcounter
  6120. if (s_PerfCountersEnabled)
  6121. {
  6122. if (bytesTransferred>0) {
  6123. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
  6124. if (Transport==TransportType.Udp) {
  6125. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
  6126. }
  6127. }
  6128. }
  6129. #endif //!FEATURE_PAL
  6130. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndMultipleSend() bytesTransferred:" + bytesTransferred.ToString());
  6131. //
  6132. // if the asynchronous native call failed asynchronously
  6133. // we'll throw a SocketException
  6134. //
  6135. if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
  6136. //
  6137. // update our internal state after this socket error and throw
  6138. //
  6139. SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
  6140. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndMultipleSend", socketException);
  6141. throw socketException;
  6142. }
  6143. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndMultipleSend", bytesTransferred);
  6144. return bytesTransferred;
  6145. }
  6146. //
  6147. // CreateAcceptSocket - pulls unmanaged results and assembles them
  6148. // into a new Socket object
  6149. //
  6150. private Socket CreateAcceptSocket(SafeCloseSocket fd, EndPoint remoteEP, bool needCancelSelect) {
  6151. //
  6152. // Internal state of the socket is inherited from listener
  6153. //
  6154. Socket socket = new Socket(fd);
  6155. return UpdateAcceptSocket(socket,remoteEP, needCancelSelect);
  6156. }
  6157. internal Socket UpdateAcceptSocket(Socket socket, EndPoint remoteEP, bool needCancelSelect) {
  6158. //
  6159. // Internal state of the socket is inherited from listener
  6160. //
  6161. socket.addressFamily = addressFamily;
  6162. socket.socketType = socketType;
  6163. socket.protocolType = protocolType;
  6164. socket.m_RightEndPoint = m_RightEndPoint;
  6165. socket.m_RemoteEndPoint = remoteEP;
  6166. //
  6167. // the socket is connected
  6168. //
  6169. socket.SetToConnected();
  6170. //
  6171. // if the socket is returned by an Endb), the socket might have
  6172. // inherited the WSAEventSelect() call from the accepting socket.
  6173. // we need to cancel this otherwise the socket will be in non-blocking
  6174. // mode and we cannot force blocking mode using the ioctlsocket() in
  6175. // Socket.set_Blocking(), since it fails returing 10022 as documented in MSDN.
  6176. // (note that the m_AsyncEvent event will not be created in this case.
  6177. //
  6178. socket.willBlock = willBlock;
  6179. if (needCancelSelect) {
  6180. socket.UnsetAsyncEventSelect();
  6181. }
  6182. else {
  6183. // We need to make sure the Socket is in the right blocking state
  6184. // even if we don't have to call UnsetAsyncEventSelect
  6185. socket.InternalSetBlocking(willBlock);
  6186. }
  6187. return socket;
  6188. }
  6189. //
  6190. // SetToConnected - updates the status of the socket to connected
  6191. //
  6192. internal void SetToConnected() {
  6193. if (m_IsConnected) {
  6194. //
  6195. // socket was already connected
  6196. //
  6197. return;
  6198. }
  6199. //
  6200. // update the status: this socket was indeed connected at
  6201. // some point in time update the perf counter as well.
  6202. //
  6203. m_IsConnected = true;
  6204. m_IsDisconnected = false;
  6205. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToConnected() now connected SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
  6206. #if !FEATURE_PAL // perfcounter
  6207. if (s_PerfCountersEnabled)
  6208. {
  6209. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketConnectionsEstablished);
  6210. }
  6211. #endif //!FEATURE_PAL
  6212. }
  6213. //
  6214. // SetToDisconnected - updates the status of the socket to disconnected
  6215. //
  6216. internal void SetToDisconnected() {
  6217. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToDisconnected()");
  6218. if (!m_IsConnected) {
  6219. //
  6220. // socket was already disconnected
  6221. //
  6222. return;
  6223. }
  6224. //
  6225. // update the status: this socket was indeed disconnected at
  6226. // some point in time, clear any async select bits.
  6227. //
  6228. m_IsConnected = false;
  6229. m_IsDisconnected = true;
  6230. if (!CleanedUp) {
  6231. //
  6232. // if socket is still alive cancel WSAEventSelect()
  6233. //
  6234. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToDisconnected()");
  6235. UnsetAsyncEventSelect();
  6236. }
  6237. }
  6238. //
  6239. // UpdateStatusAfterSocketError(socketException) - updates the status of a connected socket
  6240. // on which a failure occured. it'll go to winsock and check if the connection
  6241. // is still open and if it needs to update our internal state.
  6242. //
  6243. internal void UpdateStatusAfterSocketError(SocketException socketException){
  6244. UpdateStatusAfterSocketError((SocketError) socketException.NativeErrorCode);
  6245. }
  6246. internal void UpdateStatusAfterSocketError(SocketError errorCode)
  6247. {
  6248. //
  6249. // if we already know the socket is disconnected
  6250. // we don't need to do anything else.
  6251. //
  6252. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UpdateStatusAfterSocketError(socketException)");
  6253. if (s_LoggingEnabled) Logging.PrintError(Logging.Sockets, this, "UpdateStatusAfterSocketError", errorCode.ToString());
  6254. if (m_IsConnected && (m_Handle.IsInvalid || (errorCode != SocketError.WouldBlock &&
  6255. errorCode != SocketError.IOPending && errorCode != SocketError.NoBufferSpaceAvailable &&
  6256. errorCode != SocketError.TimedOut)))
  6257. {
  6258. //
  6259. //
  6260. // the socket is no longer a valid socket
  6261. //
  6262. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UpdateStatusAfterSocketError(socketException) Invalidating socket.");
  6263. SetToDisconnected();
  6264. }
  6265. }
  6266. //
  6267. // Does internal initalization before async winsock
  6268. // call to BeginConnect() or BeginAccept().
  6269. //
  6270. private void UnsetAsyncEventSelect()
  6271. {
  6272. GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
  6273. RegisteredWaitHandle registeredWait = m_RegisteredWait;
  6274. if (registeredWait != null)
  6275. {
  6276. m_RegisteredWait = null;
  6277. registeredWait.Unregister(null);
  6278. }
  6279. SocketError errorCode = SocketError.NotSocket;
  6280. try {
  6281. errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_Handle, IntPtr.Zero, AsyncEventBits.FdNone);
  6282. }
  6283. catch (Exception e)
  6284. {
  6285. if (NclUtilities.IsFatal(e))
  6286. throw;
  6287. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect() !!! (ignoring) Exception: " + e.ToString());
  6288. GlobalLog.Assert(CleanedUp, "Socket#{0}::UnsetAsyncEventSelect|Got exception and CleanedUp not set.", ValidationHelper.HashString(this));
  6289. }
  6290. //
  6291. // May be re-used in future, reset if the event got signalled after registeredWait.Unregister call
  6292. //
  6293. if (m_AsyncEvent != null)
  6294. {
  6295. try
  6296. {
  6297. m_AsyncEvent.Reset();
  6298. }
  6299. catch (ObjectDisposedException) { }
  6300. }
  6301. if (errorCode == SocketError.SocketError)
  6302. {
  6303. //
  6304. // update our internal state after this socket error
  6305. // we won't throw since this is an internal method
  6306. //
  6307. UpdateStatusAfterSocketError(errorCode);
  6308. }
  6309. // The call to WSAEventSelect will always put us into non-blocking mode.
  6310. // Revert back to what the user has requested.
  6311. InternalSetBlocking(willBlock);
  6312. GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
  6313. }
  6314. private bool SetAsyncEventSelect(AsyncEventBits blockEventBits)
  6315. {
  6316. GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "blockEventBits:" + blockEventBits.ToString() + " m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
  6317. GlobalLog.Assert(blockEventBits != AsyncEventBits.FdNone, "Socket#{0}::SetAsyncEventSelect|Use UnsetAsyncEventSelect for FdNone.", ValidationHelper.HashString(this));
  6318. GlobalLog.Assert(m_BlockEventBits == AsyncEventBits.FdNone || m_BlockEventBits == blockEventBits, "Socket#{0}::SetAsyncEventSelect|Can't change from one active wait to another.", ValidationHelper.HashString(this));
  6319. GlobalLog.Assert(m_RegisteredWait == null, "Socket#{0}::SetAsyncEventSelect|Already actively waiting on an op.", ValidationHelper.HashString(this));
  6320. // This check is bogus, too late diggin into a historical reason for it.
  6321. // Make sure the upper level will fail with ObjectDisposedException
  6322. if (m_RegisteredWait != null)
  6323. return false;
  6324. //
  6325. // This will put us into non-blocking mode. Create the event if it isn't, and register a wait.
  6326. //
  6327. if (m_AsyncEvent == null)
  6328. {
  6329. Interlocked.CompareExchange<ManualResetEvent>(ref m_AsyncEvent, new ManualResetEvent(false), null);
  6330. if (s_RegisteredWaitCallback == null)
  6331. s_RegisteredWaitCallback = new WaitOrTimerCallback(RegisteredWaitCallback);
  6332. }
  6333. //
  6334. // Try to win over Dispose is there is a ----
  6335. //
  6336. if (Interlocked.CompareExchange(ref m_IntCleanedUp, 2, 0) != 0)
  6337. {
  6338. GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect() Already Cleaned up, returning ... ", string.Empty);
  6339. return false;
  6340. }
  6341. try
  6342. {
  6343. m_BlockEventBits = blockEventBits;
  6344. m_RegisteredWait = ThreadPool.UnsafeRegisterWaitForSingleObject(m_AsyncEvent, s_RegisteredWaitCallback, this, Timeout.Infinite, true);
  6345. }
  6346. finally
  6347. {
  6348. //
  6349. // Release dispose if any is waiting
  6350. //
  6351. Interlocked.Exchange(ref m_IntCleanedUp, 0);
  6352. }
  6353. SocketError errorCode = SocketError.NotSocket;
  6354. //
  6355. // issue the native call
  6356. //
  6357. try {
  6358. errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_Handle, m_AsyncEvent.SafeWaitHandle, blockEventBits);
  6359. }
  6360. catch (Exception e)
  6361. {
  6362. if (NclUtilities.IsFatal(e))
  6363. throw;
  6364. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect() !!! (converting to ObjectDisposed) Exception :" + e.ToString());
  6365. GlobalLog.Assert(CleanedUp, "Socket#{0}::SetAsyncEventSelect|WSAEventSelect got exception and CleanedUp not set.", ValidationHelper.HashString(this));
  6366. }
  6367. if (errorCode==SocketError.SocketError) {
  6368. //
  6369. // update our internal state after this socket error
  6370. // we won't throw since this is an internal method
  6371. //
  6372. UpdateStatusAfterSocketError(errorCode);
  6373. }
  6374. //
  6375. // the call to WSAEventSelect will put us in non-blocking mode,
  6376. // hence we need update internal status
  6377. //
  6378. willBlockInternal = false;
  6379. GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
  6380. return errorCode == SocketError.Success;
  6381. }
  6382. private static void RegisteredWaitCallback(object state, bool timedOut)
  6383. {
  6384. GlobalLog.Enter("Socket#" + ValidationHelper.HashString(state) + "::RegisteredWaitCallback", "m_BlockEventBits:" + ((Socket)state).m_BlockEventBits.ToString());
  6385. #if DEBUG
  6386. // GlobalLog.SetThreadSource(ThreadKinds.Worker); Because of change 1077887, need logic to determine thread type here.
  6387. using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
  6388. #endif
  6389. Socket me = (Socket)state;
  6390. // Interlocked to avoid a race condition with DoBeginConnect
  6391. if (Interlocked.Exchange(ref me.m_RegisteredWait, null) != null)
  6392. {
  6393. switch (me.m_BlockEventBits)
  6394. {
  6395. case AsyncEventBits.FdConnect:
  6396. me.ConnectCallback();
  6397. break;
  6398. case AsyncEventBits.FdAccept:
  6399. me.AcceptCallback(null);
  6400. break;
  6401. }
  6402. }
  6403. #if DEBUG
  6404. }
  6405. #endif
  6406. GlobalLog.Leave("Socket#" + ValidationHelper.HashString(state) + "::RegisteredWaitCallback", "m_BlockEventBits:" + ((Socket)state).m_BlockEventBits.ToString());
  6407. }
  6408. //
  6409. // ValidateBlockingMode - called before synchronous calls to validate
  6410. // the fact that we are in blocking mode (not in non-blocking mode) so the
  6411. // call will actually be synchronous
  6412. //
  6413. private void ValidateBlockingMode() {
  6414. if (willBlock && !willBlockInternal) {
  6415. throw new InvalidOperationException(SR.GetString(SR.net_invasync));
  6416. }
  6417. }
  6418. //
  6419. // This Method binds the Socket Win32 Handle to the ThreadPool's CompletionPort
  6420. // (make sure we only bind once per socket)
  6421. //
  6422. [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
  6423. internal void BindToCompletionPort()
  6424. {
  6425. //
  6426. // Check to see if the socket native m_Handle is already
  6427. // bound to the ThreadPool's completion port.
  6428. //
  6429. if (!m_BoundToThreadPool && !UseOverlappedIO) {
  6430. lock (this) {
  6431. if (!m_BoundToThreadPool) {
  6432. #if SOCKETTHREADPOOL
  6433. // bind the socket native m_Handle to prototype SocketThreadPool
  6434. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BindToCompletionPort() calling SocketThreadPool.BindHandle()");
  6435. SocketThreadPool.BindHandle(m_Handle);
  6436. m_BoundToThreadPool = true;
  6437. #else
  6438. //
  6439. // bind the socket native m_Handle to the ThreadPool
  6440. //
  6441. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BindToCompletionPort() calling ThreadPool.BindHandle()");
  6442. try
  6443. {
  6444. ThreadPool.BindHandle(m_Handle);
  6445. m_BoundToThreadPool = true;
  6446. }
  6447. catch (Exception exception)
  6448. {
  6449. if (NclUtilities.IsFatal(exception)) throw;
  6450. Close(0);
  6451. throw;
  6452. }
  6453. #endif
  6454. }
  6455. }
  6456. }
  6457. }
  6458. #if TRAVE
  6459. [System.Diagnostics.Conditional("TRAVE")]
  6460. internal void DebugMembers() {
  6461. GlobalLog.Print("m_Handle:" + m_Handle.DangerousGetHandle().ToString("x") );
  6462. GlobalLog.Print("m_IsConnected: " + m_IsConnected);
  6463. }
  6464. #endif
  6465. //
  6466. // AcceptAsync
  6467. //
  6468. public bool AcceptAsync(SocketAsyncEventArgs e) {
  6469. bool retval;
  6470. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "AcceptAsync", "");
  6471. // Throw if socket disposed
  6472. if(CleanedUp) {
  6473. throw new ObjectDisposedException(GetType().FullName);
  6474. }
  6475. // Throw if multiple buffers specified.
  6476. if(e.m_BufferList != null) {
  6477. throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
  6478. }
  6479. // Throw if not bound.
  6480. if(m_RightEndPoint == null) {
  6481. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  6482. }
  6483. // Throw if not listening.
  6484. if(!isListening) {
  6485. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
  6486. }
  6487. // Handle AcceptSocket property.
  6488. if(e.AcceptSocket == null) {
  6489. // Accept socket not specified - create it.
  6490. e.AcceptSocket = new Socket(addressFamily, socketType, protocolType);
  6491. } else {
  6492. // Validate accept socket for use here.
  6493. if(e.AcceptSocket.m_RightEndPoint != null && !e.AcceptSocket.m_IsDisconnected) {
  6494. throw new InvalidOperationException(SR.GetString(SR.net_sockets_namedmustnotbebound, "AcceptSocket"));
  6495. }
  6496. }
  6497. // Prepare for the native call.
  6498. e.StartOperationCommon(this);
  6499. e.StartOperationAccept();
  6500. BindToCompletionPort();
  6501. // Local variables for sync completion.
  6502. int bytesTransferred;
  6503. SocketError socketError = SocketError.Success;
  6504. // Make the native call.
  6505. try {
  6506. if(!AcceptEx(
  6507. m_Handle,
  6508. e.AcceptSocket.m_Handle,
  6509. (e.m_PtrSingleBuffer != IntPtr.Zero) ? e.m_PtrSingleBuffer : e.m_PtrAcceptBuffer,
  6510. (e.m_PtrSingleBuffer != IntPtr.Zero) ? e.Count - e.m_AcceptAddressBufferCount : 0,
  6511. e.m_AcceptAddressBufferCount / 2,
  6512. e.m_AcceptAddressBufferCount / 2,
  6513. out bytesTransferred,
  6514. e.m_PtrNativeOverlapped)) {
  6515. socketError = (SocketError)Marshal.GetLastWin32Error();
  6516. }
  6517. }
  6518. catch (Exception ex) {
  6519. // clear in-use on event arg object
  6520. e.Complete();
  6521. throw ex;
  6522. }
  6523. // Handle completion when completion port is not posted.
  6524. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  6525. e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
  6526. retval = false;
  6527. } else {
  6528. retval = true;
  6529. }
  6530. if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "AcceptAsync", retval);
  6531. return retval;
  6532. }
  6533. //
  6534. // ConnectAsync
  6535. //
  6536. public bool ConnectAsync(SocketAsyncEventArgs e) {
  6537. bool retval;
  6538. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ConnectAsync", "");
  6539. // Throw if socket disposed
  6540. if(CleanedUp) {
  6541. throw new ObjectDisposedException(GetType().FullName);
  6542. }
  6543. // Throw if multiple buffers specified.
  6544. if(e.m_BufferList != null) {
  6545. throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
  6546. }
  6547. // Throw if RemoteEndPoint is null.
  6548. if(e.RemoteEndPoint == null) {
  6549. throw new ArgumentNullException("remoteEP");
  6550. }
  6551. // Throw if listening.
  6552. if(isListening) {
  6553. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
  6554. }
  6555. // Check permissions for connect and prepare SocketAddress.
  6556. EndPoint endPointSnapshot = e.RemoteEndPoint;
  6557. DnsEndPoint dnsEP = endPointSnapshot as DnsEndPoint;
  6558. if (dnsEP != null) {
  6559. if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, "Socket#" + ValidationHelper.HashString(this)
  6560. + "::ConnectAsync " + SR.GetString(SR.net_log_socket_connect_dnsendpoint));
  6561. if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily)) {
  6562. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  6563. }
  6564. MultipleConnectAsync multipleConnectAsync = new SingleSocketMultipleConnectAsync(this, true);
  6565. e.StartOperationCommon(this);
  6566. e.StartOperationWrapperConnect(multipleConnectAsync);
  6567. retval = multipleConnectAsync.StartConnectAsync(e, dnsEP);
  6568. }
  6569. else {
  6570. // Throw if remote address family doesn't match socket.
  6571. if (!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
  6572. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  6573. }
  6574. e.m_SocketAddress = CheckCacheRemote(ref endPointSnapshot, false);
  6575. // Do wildcard bind if socket not bound.
  6576. if(m_RightEndPoint == null) {
  6577. if(endPointSnapshot.AddressFamily == AddressFamily.InterNetwork)
  6578. InternalBind(new IPEndPoint(IPAddress.Any, 0));
  6579. else
  6580. InternalBind(new IPEndPoint(IPAddress.IPv6Any, 0));
  6581. }
  6582. // Save the old RightEndPoint and prep new RightEndPoint.
  6583. EndPoint oldEndPoint = m_RightEndPoint;
  6584. if(m_RightEndPoint == null) {
  6585. m_RightEndPoint = endPointSnapshot;
  6586. }
  6587. // Prepare for the native call.
  6588. e.StartOperationCommon(this);
  6589. e.StartOperationConnect();
  6590. BindToCompletionPort();
  6591. // Make the native call.
  6592. int bytesTransferred;
  6593. SocketError socketError = SocketError.Success;
  6594. try {
  6595. if(!ConnectEx(
  6596. m_Handle,
  6597. e.m_PtrSocketAddressBuffer,
  6598. e.m_SocketAddress.m_Size,
  6599. e.m_PtrSingleBuffer,
  6600. e.Count,
  6601. out bytesTransferred,
  6602. e.m_PtrNativeOverlapped)) {
  6603. socketError = (SocketError)Marshal.GetLastWin32Error();
  6604. }
  6605. }
  6606. catch (Exception ex) {
  6607. m_RightEndPoint = oldEndPoint;
  6608. // clear in-use on event arg object
  6609. e.Complete();
  6610. throw ex;
  6611. }
  6612. // Handle failure where completion port is not posted.
  6613. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  6614. e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
  6615. retval = false;
  6616. } else {
  6617. retval = true;
  6618. }
  6619. }
  6620. if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ConnectAsync", retval);
  6621. return retval;
  6622. }
  6623. #endif // MONO
  6624. public static bool ConnectAsync(SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e) {
  6625. bool retval;
  6626. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, null, "ConnectAsync", "");
  6627. // Throw if multiple buffers specified.
  6628. if (e.BufferList != null) {
  6629. throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
  6630. }
  6631. // Throw if RemoteEndPoint is null.
  6632. if (e.RemoteEndPoint == null) {
  6633. throw new ArgumentNullException("remoteEP");
  6634. }
  6635. EndPoint endPointSnapshot = e.RemoteEndPoint;
  6636. DnsEndPoint dnsEP = endPointSnapshot as DnsEndPoint;
  6637. if (dnsEP != null) {
  6638. Socket attemptSocket = null;
  6639. MultipleConnectAsync multipleConnectAsync = null;
  6640. if (dnsEP.AddressFamily == AddressFamily.Unspecified) {
  6641. multipleConnectAsync = new DualSocketMultipleConnectAsync(socketType, protocolType);
  6642. } else {
  6643. attemptSocket = new Socket(dnsEP.AddressFamily, socketType, protocolType);
  6644. multipleConnectAsync = new SingleSocketMultipleConnectAsync(attemptSocket, false);
  6645. }
  6646. e.StartOperationCommon(attemptSocket);
  6647. e.StartOperationWrapperConnect(multipleConnectAsync);
  6648. retval = multipleConnectAsync.StartConnectAsync(e, dnsEP);
  6649. } else {
  6650. Socket attemptSocket = new Socket(endPointSnapshot.AddressFamily, socketType, protocolType);
  6651. retval = attemptSocket.ConnectAsync(e);
  6652. }
  6653. if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, null, "ConnectAsync", retval);
  6654. return retval;
  6655. }
  6656. #if !MONO
  6657. public static void CancelConnectAsync(SocketAsyncEventArgs e) {
  6658. if (e == null) {
  6659. throw new ArgumentNullException("e");
  6660. }
  6661. e.CancelConnectAsync();
  6662. }
  6663. //
  6664. // DisconnectAsync
  6665. //
  6666. public bool DisconnectAsync(SocketAsyncEventArgs e) {
  6667. bool retval;
  6668. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "DisconnectAsync", "");
  6669. // Throw if socket disposed
  6670. if(CleanedUp) {
  6671. throw new ObjectDisposedException(GetType().FullName);
  6672. }
  6673. // Prepare for the native call.
  6674. e.StartOperationCommon(this);
  6675. e.StartOperationDisconnect();
  6676. BindToCompletionPort();
  6677. // Make the native call.
  6678. SocketError socketError = SocketError.Success;
  6679. try {
  6680. if(!DisconnectEx(
  6681. m_Handle,
  6682. e.m_PtrNativeOverlapped,
  6683. (int)(e.DisconnectReuseSocket ? TransmitFileOptions.ReuseSocket : 0),
  6684. 0)) {
  6685. socketError = (SocketError)Marshal.GetLastWin32Error();
  6686. }
  6687. }
  6688. catch(Exception ex) {
  6689. // clear in-use on event arg object
  6690. e.Complete();
  6691. throw ex;
  6692. }
  6693. // Handle completion when completion port is not posted.
  6694. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  6695. e.FinishOperationSyncFailure(socketError, 0, SocketFlags.None);
  6696. retval = false;
  6697. } else {
  6698. retval = true;
  6699. }
  6700. if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "DisconnectAsync", retval);
  6701. return retval;
  6702. }
  6703. //
  6704. // ReceiveAsync
  6705. //
  6706. public bool ReceiveAsync(SocketAsyncEventArgs e) {
  6707. bool retval;
  6708. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveAsync", "");
  6709. // Throw if socket disposed
  6710. if(CleanedUp) {
  6711. throw new ObjectDisposedException(GetType().FullName);
  6712. }
  6713. // Prepare for the native call.
  6714. e.StartOperationCommon(this);
  6715. e.StartOperationReceive();
  6716. BindToCompletionPort();
  6717. // Local vars for sync completion of native call.
  6718. SocketFlags flags = e.m_SocketFlags;
  6719. int bytesTransferred;
  6720. SocketError socketError;
  6721. // Wrap native methods with try/catch so event args object can be cleaned up
  6722. try {
  6723. if(e.m_Buffer != null) {
  6724. // Single buffer case
  6725. socketError = UnsafeNclNativeMethods.OSSOCK.WSARecv(
  6726. m_Handle,
  6727. ref e.m_WSABuffer,
  6728. 1,
  6729. out bytesTransferred,
  6730. ref flags,
  6731. e.m_PtrNativeOverlapped,
  6732. IntPtr.Zero);
  6733. } else {
  6734. // Multi buffer case
  6735. socketError = UnsafeNclNativeMethods.OSSOCK.WSARecv(
  6736. m_Handle,
  6737. e.m_WSABufferArray,
  6738. e.m_WSABufferArray.Length,
  6739. out bytesTransferred,
  6740. ref flags,
  6741. e.m_PtrNativeOverlapped,
  6742. IntPtr.Zero);
  6743. }
  6744. }
  6745. catch(Exception ex) {
  6746. // clear in-use on event arg object
  6747. e.Complete();
  6748. throw ex;
  6749. }
  6750. // Native method emits single catch-all error code when error occurs.
  6751. // Must get Win32 error for specific error code.
  6752. if(socketError != SocketError.Success) {
  6753. socketError = (SocketError)Marshal.GetLastWin32Error();
  6754. }
  6755. // Handle completion when completion port is not posted.
  6756. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  6757. e.FinishOperationSyncFailure(socketError, bytesTransferred, flags);
  6758. retval = false;
  6759. } else {
  6760. retval = true;
  6761. }
  6762. if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveAsync", retval);
  6763. return retval;
  6764. }
  6765. //
  6766. // ReceiveFromAsync
  6767. //
  6768. public bool ReceiveFromAsync(SocketAsyncEventArgs e) {
  6769. bool retval;
  6770. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveFromAsync", "");
  6771. // Throw if socket disposed
  6772. if(CleanedUp) {
  6773. throw new ObjectDisposedException(GetType().FullName);
  6774. }
  6775. // Throw if remote endpoint property is null.
  6776. if(e.RemoteEndPoint == null) {
  6777. throw new ArgumentNullException("RemoteEndPoint");
  6778. }
  6779. if(!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
  6780. throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
  6781. e.RemoteEndPoint.AddressFamily, addressFamily), "RemoteEndPoint");
  6782. }
  6783. // We don't do a CAS demand here because the contents of remoteEP aren't used by
  6784. // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
  6785. // with the right address family
  6786. EndPoint endPointSnapshot = e.RemoteEndPoint;
  6787. e.m_SocketAddress = SnapshotAndSerialize(ref endPointSnapshot);
  6788. // DualMode may have updated the endPointSnapshot, and it has to have the same AddressFamily as
  6789. // e.m_SocketAddres for Create to work later.
  6790. e.RemoteEndPoint = endPointSnapshot;
  6791. // Prepare for the native call.
  6792. e.StartOperationCommon(this);
  6793. e.StartOperationReceiveFrom();
  6794. BindToCompletionPort();
  6795. // Make the native call.
  6796. SocketFlags flags = e.m_SocketFlags;
  6797. int bytesTransferred;
  6798. SocketError socketError;
  6799. try {
  6800. if(e.m_Buffer != null) {
  6801. socketError = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
  6802. m_Handle,
  6803. ref e.m_WSABuffer,
  6804. 1,
  6805. out bytesTransferred,
  6806. ref flags,
  6807. e.m_PtrSocketAddressBuffer,
  6808. e.m_PtrSocketAddressBufferSize,
  6809. e.m_PtrNativeOverlapped,
  6810. IntPtr.Zero);
  6811. } else {
  6812. socketError = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
  6813. m_Handle,
  6814. e.m_WSABufferArray,
  6815. e.m_WSABufferArray.Length,
  6816. out bytesTransferred,
  6817. ref flags,
  6818. e.m_PtrSocketAddressBuffer,
  6819. e.m_PtrSocketAddressBufferSize,
  6820. e.m_PtrNativeOverlapped,
  6821. IntPtr.Zero);
  6822. }
  6823. }
  6824. catch(Exception ex) {
  6825. // clear in-use on event arg object
  6826. e.Complete();
  6827. throw ex;
  6828. }
  6829. // Native method emits single catch-all error code when error occurs.
  6830. // Must get Win32 error for specific error code.
  6831. if(socketError != SocketError.Success) {
  6832. socketError = (SocketError)Marshal.GetLastWin32Error();
  6833. }
  6834. // Handle completion when completion port is not posted.
  6835. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  6836. e.FinishOperationSyncFailure(socketError, bytesTransferred, flags);
  6837. retval = false;
  6838. } else {
  6839. retval = true;
  6840. }
  6841. if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveFromAsync", retval);
  6842. return retval;
  6843. }
  6844. //
  6845. // ReceiveMessageFromAsync
  6846. //
  6847. public bool ReceiveMessageFromAsync(SocketAsyncEventArgs e) {
  6848. bool retval;
  6849. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveMessageFromAsync", "");
  6850. // Throw if socket disposed
  6851. if(CleanedUp) {
  6852. throw new ObjectDisposedException(GetType().FullName);
  6853. }
  6854. // Throw if remote endpoint property is null.
  6855. if(e.RemoteEndPoint == null) {
  6856. throw new ArgumentNullException("RemoteEndPoint");
  6857. }
  6858. if(!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
  6859. throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
  6860. e.RemoteEndPoint.AddressFamily, addressFamily), "RemoteEndPoint");
  6861. }
  6862. // We don't do a CAS demand here because the contents of remoteEP aren't used by
  6863. // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
  6864. // with the right address family
  6865. EndPoint endPointSnapshot = e.RemoteEndPoint;
  6866. e.m_SocketAddress = SnapshotAndSerialize(ref endPointSnapshot);
  6867. // DualMode may have updated the endPointSnapshot, and it has to have the same AddressFamily as
  6868. // e.m_SocketAddres for Create to work later.
  6869. e.RemoteEndPoint = endPointSnapshot;
  6870. SetReceivingPacketInformation();
  6871. // Prepare for the native call.
  6872. e.StartOperationCommon(this);
  6873. e.StartOperationReceiveMessageFrom();
  6874. BindToCompletionPort();
  6875. // Make the native call.
  6876. int bytesTransferred;
  6877. SocketError socketError;
  6878. try {
  6879. socketError = WSARecvMsg(
  6880. m_Handle,
  6881. e.m_PtrWSAMessageBuffer,
  6882. out bytesTransferred,
  6883. e.m_PtrNativeOverlapped,
  6884. IntPtr.Zero);
  6885. }
  6886. catch(Exception ex) {
  6887. // clear in-use on event arg object
  6888. e.Complete();
  6889. throw ex;
  6890. }
  6891. // Native method emits single catch-all error code when error occurs.
  6892. // Must get Win32 error for specific error code.
  6893. if(socketError != SocketError.Success) {
  6894. socketError = (SocketError)Marshal.GetLastWin32Error();
  6895. }
  6896. // Handle completion when completion port is not posted.
  6897. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  6898. e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
  6899. retval = false;
  6900. } else {
  6901. retval = true;
  6902. }
  6903. if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveMessageFromAsync", retval);
  6904. return retval;
  6905. }
  6906. //
  6907. // SendAsync
  6908. //
  6909. public bool SendAsync(SocketAsyncEventArgs e) {
  6910. bool retval;
  6911. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendAsync", "");
  6912. // Throw if socket disposed
  6913. if(CleanedUp) {
  6914. throw new ObjectDisposedException(GetType().FullName);
  6915. }
  6916. // Prepare for the native call.
  6917. e.StartOperationCommon(this);
  6918. e.StartOperationSend();
  6919. BindToCompletionPort();
  6920. // Local vars for sync completion of native call.
  6921. int bytesTransferred;
  6922. SocketError socketError;
  6923. // Wrap native methods with try/catch so event args object can be cleaned up
  6924. try {
  6925. if(e.m_Buffer != null) {
  6926. // Single buffer case
  6927. socketError = UnsafeNclNativeMethods.OSSOCK.WSASend(
  6928. m_Handle,
  6929. ref e.m_WSABuffer,
  6930. 1,
  6931. out bytesTransferred,
  6932. e.m_SocketFlags,
  6933. e.m_PtrNativeOverlapped,
  6934. IntPtr.Zero);
  6935. } else {
  6936. // Multi buffer case
  6937. socketError = UnsafeNclNativeMethods.OSSOCK.WSASend(
  6938. m_Handle,
  6939. e.m_WSABufferArray,
  6940. e.m_WSABufferArray.Length,
  6941. out bytesTransferred,
  6942. e.m_SocketFlags,
  6943. e.m_PtrNativeOverlapped,
  6944. IntPtr.Zero);
  6945. }
  6946. }
  6947. catch(Exception ex) {
  6948. // clear in-use on event arg object
  6949. e.Complete();
  6950. throw ex;
  6951. }
  6952. // Native method emits single catch-all error code when error occurs.
  6953. // Must get Win32 error for specific error code.
  6954. if(socketError != SocketError.Success) {
  6955. socketError = (SocketError)Marshal.GetLastWin32Error();
  6956. }
  6957. // Handle completion when completion port is not posted.
  6958. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  6959. e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
  6960. retval = false;
  6961. } else {
  6962. retval = true;
  6963. }
  6964. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendAsync", retval);
  6965. return retval;
  6966. }
  6967. //
  6968. // SendPacketsAsync
  6969. //
  6970. public bool SendPacketsAsync(SocketAsyncEventArgs e) {
  6971. bool retval;
  6972. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendPacketsAsync", "");
  6973. // Throw if socket disposed
  6974. if(CleanedUp) {
  6975. throw new ObjectDisposedException(GetType().FullName);
  6976. }
  6977. // Throw if not connected.
  6978. if(!Connected) {
  6979. throw new NotSupportedException(SR.GetString(SR.net_notconnected));
  6980. }
  6981. // Prepare for the native call.
  6982. e.StartOperationCommon(this);
  6983. e.StartOperationSendPackets();
  6984. BindToCompletionPort();
  6985. // Make the native call.
  6986. SocketError socketError;
  6987. bool result;
  6988. if (e.m_SendPacketsDescriptor.Length > 0) {
  6989. try {
  6990. result = TransmitPackets(
  6991. m_Handle,
  6992. e.m_PtrSendPacketsDescriptor,
  6993. e.m_SendPacketsDescriptor.Length,
  6994. e.m_SendPacketsSendSize,
  6995. e.m_PtrNativeOverlapped,
  6996. e.m_SendPacketsFlags);
  6997. }
  6998. catch(Exception) {
  6999. // clear in-use on event arg object
  7000. e.Complete();
  7001. throw;
  7002. }
  7003. if(!result) {
  7004. socketError = (SocketError)Marshal.GetLastWin32Error();
  7005. } else {
  7006. socketError = SocketError.Success;
  7007. }
  7008. // Handle completion when completion port is not posted.
  7009. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  7010. e.FinishOperationSyncFailure(socketError, 0, SocketFlags.None);
  7011. retval = false;
  7012. } else {
  7013. retval = true;
  7014. }
  7015. }
  7016. else {
  7017. // No buffers or files to send.
  7018. e.FinishOperationSuccess(SocketError.Success, 0, SocketFlags.None);
  7019. retval = false;
  7020. }
  7021. if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "SendPacketsAsync", retval);
  7022. return retval;
  7023. }
  7024. //
  7025. // SendToAsync
  7026. //
  7027. public bool SendToAsync(SocketAsyncEventArgs e) {
  7028. bool retval;
  7029. if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendToAsync", "");
  7030. // Throw if socket disposed
  7031. if(CleanedUp) {
  7032. throw new ObjectDisposedException(GetType().FullName);
  7033. }
  7034. // Throw if remote endpoint property is null.
  7035. if(e.RemoteEndPoint == null) {
  7036. throw new ArgumentNullException("RemoteEndPoint");
  7037. }
  7038. // Check permissions for connect and prepare SocketAddress
  7039. EndPoint endPointSnapshot = e.RemoteEndPoint;
  7040. e.m_SocketAddress = CheckCacheRemote(ref endPointSnapshot, false);
  7041. // Prepare for the native call.
  7042. e.StartOperationCommon(this);
  7043. e.StartOperationSendTo();
  7044. BindToCompletionPort();
  7045. // Make the native call.
  7046. int bytesTransferred;
  7047. SocketError socketError;
  7048. // Wrap native methods with try/catch so event args object can be cleaned up
  7049. try {
  7050. if(e.m_Buffer != null) {
  7051. // Single buffer case
  7052. socketError = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
  7053. m_Handle,
  7054. ref e.m_WSABuffer,
  7055. 1,
  7056. out bytesTransferred,
  7057. e.m_SocketFlags,
  7058. e.m_PtrSocketAddressBuffer,
  7059. e.m_SocketAddress.m_Size,
  7060. e.m_PtrNativeOverlapped,
  7061. IntPtr.Zero);
  7062. } else {
  7063. socketError = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
  7064. m_Handle,
  7065. e.m_WSABufferArray,
  7066. e.m_WSABufferArray.Length,
  7067. out bytesTransferred,
  7068. e.m_SocketFlags,
  7069. e.m_PtrSocketAddressBuffer,
  7070. e.m_SocketAddress.m_Size,
  7071. e.m_PtrNativeOverlapped,
  7072. IntPtr.Zero);
  7073. }
  7074. }
  7075. catch(Exception ex) {
  7076. // clear in-use on event arg object
  7077. e.Complete();
  7078. throw ex;
  7079. }
  7080. // Native method emits single catch-all error code when error occurs.
  7081. // Must get Win32 error for specific error code.
  7082. if(socketError != SocketError.Success) {
  7083. socketError = (SocketError)Marshal.GetLastWin32Error();
  7084. }
  7085. // Handle completion when completion port is not posted.
  7086. if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
  7087. e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
  7088. retval = false;
  7089. } else {
  7090. retval = true;
  7091. }
  7092. if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "SendToAsync", retval);
  7093. return retval;
  7094. }
  7095. #endif // !MONO
  7096. } // end of class Socket
  7097. #if !MONO
  7098. internal class ConnectAsyncResult:ContextAwareResult{
  7099. private EndPoint m_EndPoint;
  7100. internal ConnectAsyncResult(object myObject, EndPoint endPoint, object myState, AsyncCallback myCallBack):base(myObject, myState, myCallBack) {
  7101. m_EndPoint = endPoint;
  7102. }
  7103. internal EndPoint RemoteEndPoint {
  7104. get { return m_EndPoint; }
  7105. }
  7106. }
  7107. internal class AcceptAsyncResult:ContextAwareResult{
  7108. internal AcceptAsyncResult(object myObject, object myState, AsyncCallback myCallBack):base(myObject, myState, myCallBack) {
  7109. }
  7110. }
  7111. #endif
  7112. public enum SocketAsyncOperation {
  7113. None = 0,
  7114. Accept,
  7115. Connect,
  7116. Disconnect,
  7117. Receive,
  7118. ReceiveFrom,
  7119. ReceiveMessageFrom,
  7120. Send,
  7121. SendPackets,
  7122. SendTo
  7123. }
  7124. // class that wraps the semantics of a winsock TRANSMIT_PACKETS_ELEMENTS struct
  7125. public class SendPacketsElement {
  7126. internal string m_FilePath;
  7127. internal byte [] m_Buffer;
  7128. internal int m_Offset;
  7129. internal int m_Count;
  7130. #if MONO
  7131. bool m_endOfPacket;
  7132. #else
  7133. internal UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags m_Flags;
  7134. #endif
  7135. // hide default constructor
  7136. private SendPacketsElement() {}
  7137. // constructors for file elements
  7138. public SendPacketsElement(string filepath) :
  7139. this(filepath, 0, 0, false) { }
  7140. public SendPacketsElement(string filepath, int offset, int count) :
  7141. this(filepath, offset, count, false) { }
  7142. public SendPacketsElement(string filepath, int offset, int count, bool endOfPacket) {
  7143. // We will validate if the file exists on send
  7144. if (filepath == null) {
  7145. throw new ArgumentNullException("filepath");
  7146. }
  7147. // The native API will validate the file length on send
  7148. if (offset < 0) {
  7149. throw new ArgumentOutOfRangeException("offset");
  7150. }
  7151. if (count < 0) {
  7152. throw new ArgumentOutOfRangeException("count");
  7153. }
  7154. Contract.EndContractBlock();
  7155. #if MONO
  7156. Initialize(filepath, null, offset, count, /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.File,*/
  7157. endOfPacket);
  7158. #else
  7159. Initialize(filepath, null, offset, count, UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.File,
  7160. endOfPacket);
  7161. #endif
  7162. }
  7163. // constructors for buffer elements
  7164. public SendPacketsElement(byte[] buffer) :
  7165. this(buffer, 0, (buffer != null ? buffer.Length : 0), false) { }
  7166. public SendPacketsElement(byte[] buffer, int offset, int count) :
  7167. this(buffer, offset, count, false) { }
  7168. public SendPacketsElement(byte[] buffer, int offset, int count, bool endOfPacket) {
  7169. if (buffer == null) {
  7170. throw new ArgumentNullException("buffer");
  7171. }
  7172. if (offset < 0 || offset > buffer.Length) {
  7173. throw new ArgumentOutOfRangeException("offset");
  7174. }
  7175. if (count < 0 || count > (buffer.Length - offset)) {
  7176. throw new ArgumentOutOfRangeException("count");
  7177. }
  7178. Contract.EndContractBlock();
  7179. #if MONO
  7180. Initialize(null, buffer, offset, count, /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.Memory,*/
  7181. endOfPacket);
  7182. #else
  7183. Initialize(null, buffer, offset, count, UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.Memory,
  7184. endOfPacket);
  7185. #endif
  7186. }
  7187. private void Initialize(string filePath, byte[] buffer, int offset, int count,
  7188. /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags flags,*/ bool endOfPacket) {
  7189. m_FilePath = filePath;
  7190. m_Buffer = buffer;
  7191. m_Offset = offset;
  7192. m_Count = count;
  7193. #if MONO
  7194. m_endOfPacket = endOfPacket;
  7195. #else
  7196. m_Flags = flags;
  7197. if (endOfPacket) {
  7198. m_Flags |= UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.EndOfPacket;
  7199. }
  7200. #endif
  7201. }
  7202. // Filename property
  7203. public string FilePath {
  7204. get { return m_FilePath; }
  7205. }
  7206. // Buffer property
  7207. public byte[] Buffer {
  7208. get { return m_Buffer; }
  7209. }
  7210. // Count property
  7211. public int Count {
  7212. get { return m_Count; }
  7213. }
  7214. // Offset property
  7215. public int Offset {
  7216. get { return m_Offset; }
  7217. }
  7218. // EndOfPacket property
  7219. public bool EndOfPacket {
  7220. get {
  7221. #if MONO
  7222. return m_endOfPacket;
  7223. #else
  7224. return (m_Flags & UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.EndOfPacket) != 0;
  7225. #endif
  7226. }
  7227. }
  7228. }
  7229. #region designer support for System.Windows.dll
  7230. //introduced for supporting design-time loading of System.Windows.dll
  7231. [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
  7232. [EditorBrowsable(EditorBrowsableState.Never)]
  7233. public enum SocketClientAccessPolicyProtocol
  7234. {
  7235. Tcp,
  7236. Http
  7237. }
  7238. #endregion
  7239. #if !MONO
  7240. public class SocketAsyncEventArgs : EventArgs, IDisposable {
  7241. // Struct sizes needed for some custom marshalling.
  7242. internal static readonly int s_ControlDataSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.ControlData));
  7243. internal static readonly int s_ControlDataIPv6Size = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6));
  7244. internal static readonly int s_WSAMsgSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.WSAMsg));
  7245. // AcceptSocket property variables.
  7246. internal Socket m_AcceptSocket;
  7247. private Socket m_ConnectSocket;
  7248. // Buffer,Offset,Count property variables.
  7249. internal byte[] m_Buffer;
  7250. internal WSABuffer m_WSABuffer;
  7251. internal IntPtr m_PtrSingleBuffer;
  7252. internal int m_Count;
  7253. internal int m_Offset;
  7254. // BufferList property variables.
  7255. internal IList<ArraySegment<byte> > m_BufferList;
  7256. private bool m_BufferListChanged;
  7257. internal WSABuffer[] m_WSABufferArray;
  7258. // BytesTransferred property variables.
  7259. private int m_BytesTransferred;
  7260. // Completed event property variables.
  7261. private event EventHandler<SocketAsyncEventArgs> m_Completed;
  7262. private bool m_CompletedChanged;
  7263. // DisconnectReuseSocket propery variables.
  7264. private bool m_DisconnectReuseSocket;
  7265. // LastOperation property variables.
  7266. private SocketAsyncOperation m_CompletedOperation;
  7267. // ReceiveMessageFromPacketInfo property variables.
  7268. private IPPacketInformation m_ReceiveMessageFromPacketInfo;
  7269. // RemoteEndPoint property variables.
  7270. private EndPoint m_RemoteEndPoint;
  7271. // SendPacketsFlags property variable.
  7272. internal TransmitFileOptions m_SendPacketsFlags;
  7273. // SendPacketsSendSize property variable.
  7274. internal int m_SendPacketsSendSize;
  7275. // SendPacketsElements property variables.
  7276. internal SendPacketsElement[] m_SendPacketsElements;
  7277. private SendPacketsElement[] m_SendPacketsElementsInternal;
  7278. internal int m_SendPacketsElementsFileCount;
  7279. internal int m_SendPacketsElementsBufferCount;
  7280. // SocketError property variables.
  7281. private SocketError m_SocketError;
  7282. private Exception m_ConnectByNameError;
  7283. // SocketFlags property variables.
  7284. internal SocketFlags m_SocketFlags;
  7285. // UserToken property variables.
  7286. private object m_UserToken;
  7287. // Internal buffer for AcceptEx when Buffer not supplied.
  7288. internal byte[] m_AcceptBuffer;
  7289. internal int m_AcceptAddressBufferCount;
  7290. internal IntPtr m_PtrAcceptBuffer;
  7291. // Internal SocketAddress buffer
  7292. internal SocketAddress m_SocketAddress;
  7293. private GCHandle m_SocketAddressGCHandle;
  7294. private SocketAddress m_PinnedSocketAddress;
  7295. internal IntPtr m_PtrSocketAddressBuffer;
  7296. internal IntPtr m_PtrSocketAddressBufferSize;
  7297. // Internal buffers for WSARecvMsg
  7298. private byte[] m_WSAMessageBuffer;
  7299. private GCHandle m_WSAMessageBufferGCHandle;
  7300. internal IntPtr m_PtrWSAMessageBuffer;
  7301. private byte[] m_ControlBuffer;
  7302. private GCHandle m_ControlBufferGCHandle;
  7303. internal IntPtr m_PtrControlBuffer;
  7304. private WSABuffer[] m_WSARecvMsgWSABufferArray;
  7305. private GCHandle m_WSARecvMsgWSABufferArrayGCHandle;
  7306. private IntPtr m_PtrWSARecvMsgWSABufferArray;
  7307. // Internal variables for SendPackets
  7308. internal FileStream[] m_SendPacketsFileStreams;
  7309. internal SafeHandle[] m_SendPacketsFileHandles;
  7310. internal UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElement[] m_SendPacketsDescriptor;
  7311. internal IntPtr m_PtrSendPacketsDescriptor;
  7312. // Misc state variables.
  7313. private ExecutionContext m_Context;
  7314. private ExecutionContext m_ContextCopy;
  7315. private ContextCallback m_ExecutionCallback;
  7316. private Socket m_CurrentSocket;
  7317. private bool m_DisposeCalled;
  7318. // Controls thread safety via Interlocked
  7319. private const int Configuring = -1;
  7320. private const int Free = 0;
  7321. private const int InProgress = 1;
  7322. private const int Disposed = 2;
  7323. private int m_Operating;
  7324. // Overlapped object related variables.
  7325. internal SafeNativeOverlapped m_PtrNativeOverlapped;
  7326. private Overlapped m_Overlapped;
  7327. private object[] m_ObjectsToPin;
  7328. private enum PinState {
  7329. None = 0,
  7330. NoBuffer,
  7331. SingleAcceptBuffer,
  7332. SingleBuffer,
  7333. MultipleBuffer,
  7334. SendPackets
  7335. }
  7336. private PinState m_PinState;
  7337. private byte[] m_PinnedAcceptBuffer;
  7338. private byte[] m_PinnedSingleBuffer;
  7339. private int m_PinnedSingleBufferOffset;
  7340. private int m_PinnedSingleBufferCount;
  7341. private MultipleConnectAsync m_MultipleConnect;
  7342. private static bool s_LoggingEnabled = Logging.On;
  7343. #region designer support for System.Windows.dll
  7344. //introduced for supporting design-time loading of System.Windows.dll
  7345. [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
  7346. [EditorBrowsable(EditorBrowsableState.Never)]
  7347. public SocketClientAccessPolicyProtocol SocketClientAccessPolicyProtocol { get; set; }
  7348. #endregion
  7349. // Public constructor.
  7350. public SocketAsyncEventArgs() {
  7351. // Create callback delegate
  7352. m_ExecutionCallback = new ContextCallback(ExecutionCallback);
  7353. // Zero tells TransmitPackets to select a default send size.
  7354. m_SendPacketsSendSize = 0;
  7355. }
  7356. // AcceptSocket property.
  7357. public Socket AcceptSocket {
  7358. get { return m_AcceptSocket; }
  7359. set { m_AcceptSocket = value; }
  7360. }
  7361. public Socket ConnectSocket {
  7362. get { return m_ConnectSocket; }
  7363. }
  7364. // Buffer property.
  7365. public byte[] Buffer {
  7366. get { return m_Buffer; }
  7367. }
  7368. // Offset property.
  7369. public int Offset {
  7370. get { return m_Offset; }
  7371. }
  7372. // Count property.
  7373. public int Count {
  7374. get { return m_Count; }
  7375. }
  7376. // BufferList property.
  7377. // Mutually exclusive with Buffer.
  7378. // Setting this property with an existing non-null Buffer will throw.
  7379. public IList<ArraySegment<byte> > BufferList {
  7380. get { return m_BufferList; }
  7381. set {
  7382. StartConfiguring();
  7383. try {
  7384. if(value != null && m_Buffer != null) {
  7385. throw new ArgumentException(SR.GetString(SR.net_ambiguousbuffers, "Buffer"));
  7386. }
  7387. m_BufferList = value;
  7388. m_BufferListChanged = true;
  7389. CheckPinMultipleBuffers();
  7390. } finally {
  7391. Complete();
  7392. }
  7393. }
  7394. }
  7395. // BytesTransferred property.
  7396. public int BytesTransferred {
  7397. get { return m_BytesTransferred; }
  7398. }
  7399. // Completed property.
  7400. public event EventHandler<SocketAsyncEventArgs> Completed {
  7401. add {
  7402. m_Completed += value;
  7403. m_CompletedChanged = true;
  7404. }
  7405. remove {
  7406. m_Completed -= value;
  7407. m_CompletedChanged = true;
  7408. }
  7409. }
  7410. // Method to raise Completed event.
  7411. protected virtual void OnCompleted(SocketAsyncEventArgs e) {
  7412. EventHandler<SocketAsyncEventArgs> handler = m_Completed;
  7413. if(handler != null) {
  7414. handler(e.m_CurrentSocket, e);
  7415. }
  7416. }
  7417. // DisconnectResuseSocket property.
  7418. public bool DisconnectReuseSocket {
  7419. get { return m_DisconnectReuseSocket; }
  7420. set { m_DisconnectReuseSocket = value; }
  7421. }
  7422. // LastOperation property.
  7423. public SocketAsyncOperation LastOperation {
  7424. get { return m_CompletedOperation; }
  7425. }
  7426. // ReceiveMessageFromPacketInfo property.
  7427. public IPPacketInformation ReceiveMessageFromPacketInfo {
  7428. get { return m_ReceiveMessageFromPacketInfo; }
  7429. }
  7430. // RemoteEndPoint property.
  7431. public EndPoint RemoteEndPoint {
  7432. get { return m_RemoteEndPoint; }
  7433. set { m_RemoteEndPoint = value; }
  7434. }
  7435. // SendPacketsElements property.
  7436. public SendPacketsElement[] SendPacketsElements {
  7437. get { return m_SendPacketsElements; }
  7438. set {
  7439. StartConfiguring();
  7440. try {
  7441. m_SendPacketsElements = value;
  7442. m_SendPacketsElementsInternal = null;
  7443. } finally {
  7444. Complete();
  7445. }
  7446. }
  7447. }
  7448. // SendPacketsFlags property.
  7449. public TransmitFileOptions SendPacketsFlags {
  7450. get { return m_SendPacketsFlags; }
  7451. set { m_SendPacketsFlags = value; }
  7452. }
  7453. // SendPacketsSendSize property.
  7454. public int SendPacketsSendSize {
  7455. get { return m_SendPacketsSendSize; }
  7456. set { m_SendPacketsSendSize = value; }
  7457. }
  7458. // SocketError property.
  7459. public SocketError SocketError {
  7460. get { return m_SocketError; }
  7461. set { m_SocketError = value; }
  7462. }
  7463. public Exception ConnectByNameError {
  7464. get { return m_ConnectByNameError; }
  7465. }
  7466. // SocketFlags property.
  7467. public SocketFlags SocketFlags {
  7468. get { return m_SocketFlags; }
  7469. set { m_SocketFlags = value; }
  7470. }
  7471. // UserToken property.
  7472. public object UserToken {
  7473. get { return m_UserToken; }
  7474. set { m_UserToken = value; }
  7475. }
  7476. // SetBuffer(byte[], int, int) method.
  7477. public void SetBuffer(byte [] buffer, int offset, int count) {
  7478. SetBufferInternal(buffer, offset, count);
  7479. }
  7480. // SetBuffer(int, int) method.
  7481. public void SetBuffer(int offset, int count) {
  7482. SetBufferInternal(m_Buffer, offset, count);
  7483. }
  7484. private void SetBufferInternal(byte [] buffer, int offset, int count) {
  7485. StartConfiguring();
  7486. try {
  7487. if (buffer == null) {
  7488. // Clear out existing buffer.
  7489. m_Buffer = null;
  7490. m_Offset = 0;
  7491. m_Count = 0;
  7492. } else {
  7493. // Can't have both Buffer and BufferList
  7494. if(m_BufferList != null) {
  7495. throw new ArgumentException(SR.GetString(SR.net_ambiguousbuffers, "BufferList"));
  7496. }
  7497. // Offset and count can't be negative and the
  7498. // combination must be in bounds of the array.
  7499. if (offset < 0 || offset > buffer.Length) {
  7500. throw new ArgumentOutOfRangeException("offset");
  7501. }
  7502. if (count < 0 || count > (buffer.Length - offset)) {
  7503. throw new ArgumentOutOfRangeException("count");
  7504. }
  7505. m_Buffer = buffer;
  7506. m_Offset = offset;
  7507. m_Count = count;
  7508. }
  7509. // Pin new or unpin old buffer.
  7510. CheckPinSingleBuffer(true);
  7511. } finally {
  7512. Complete();
  7513. }
  7514. }
  7515. // Method to update internal state after sync or async completion.
  7516. internal void SetResults(SocketError socketError, int bytesTransferred, SocketFlags flags) {
  7517. m_SocketError = socketError;
  7518. m_ConnectByNameError = null;
  7519. m_BytesTransferred = bytesTransferred;
  7520. m_SocketFlags = flags;
  7521. }
  7522. internal void SetResults(Exception exception, int bytesTransferred, SocketFlags flags) {
  7523. m_ConnectByNameError = exception;
  7524. m_BytesTransferred = bytesTransferred;
  7525. m_SocketFlags = flags;
  7526. if (exception == null) {
  7527. m_SocketError = SocketError.Success;
  7528. }
  7529. else {
  7530. SocketException socketException = exception as SocketException;
  7531. if (socketException != null) {
  7532. m_SocketError = socketException.SocketErrorCode;
  7533. }
  7534. else {
  7535. m_SocketError = SocketError.SocketError;
  7536. }
  7537. }
  7538. }
  7539. // Context callback delegate.
  7540. private void ExecutionCallback(object ignored) {
  7541. OnCompleted(this);
  7542. }
  7543. // Method to mark this object as no longer "in-use".
  7544. // Will also execute a Dispose deferred because I/O was in progress.
  7545. internal void Complete() {
  7546. // Mark as not in-use
  7547. m_Operating = Free;
  7548. // Check for deferred Dispose().
  7549. // The deferred Dispose is not guaranteed if Dispose is called while an operation is in progress.
  7550. // The m_DisposeCalled variable is not managed in a thread-safe manner on purpose for performance.
  7551. if (m_DisposeCalled) {
  7552. Dispose();
  7553. }
  7554. }
  7555. // Dispose call to implement IDisposable.
  7556. public void Dispose() {
  7557. // Remember that Dispose was called.
  7558. m_DisposeCalled = true;
  7559. // Check if this object is in-use for an async socket operation.
  7560. if(Interlocked.CompareExchange(ref m_Operating, Disposed, Free) != Free) {
  7561. // Either already disposed or will be disposed when current operation completes.
  7562. return;
  7563. }
  7564. // OK to dispose now.
  7565. // Free native overlapped data.
  7566. FreeOverlapped(false);
  7567. // Don't bother finalizing later.
  7568. GC.SuppressFinalize(this);
  7569. }
  7570. // Finalizer
  7571. ~SocketAsyncEventArgs() {
  7572. FreeOverlapped(true);
  7573. }
  7574. // Us a try/Finally to make sure Complete is called when you're done
  7575. private void StartConfiguring() {
  7576. int status = Interlocked.CompareExchange(ref m_Operating, Configuring, Free);
  7577. if (status == InProgress || status == Configuring) {
  7578. throw new InvalidOperationException(SR.GetString(SR.net_socketopinprogress));
  7579. }
  7580. else if (status == Disposed)
  7581. {
  7582. throw new ObjectDisposedException(GetType().FullName);
  7583. }
  7584. }
  7585. // Method called to prepare for a native async socket call.
  7586. // This method performs the tasks common to all socket operations.
  7587. internal void StartOperationCommon(Socket socket) {
  7588. // Change status to "in-use".
  7589. if(Interlocked.CompareExchange(ref m_Operating, InProgress, Free) != Free) {
  7590. // If it was already "in-use" check if Dispose was called.
  7591. if(m_DisposeCalled) {
  7592. // Dispose was called - throw ObjectDisposed.
  7593. throw new ObjectDisposedException(GetType().FullName);
  7594. }
  7595. // Only one at a time.
  7596. throw new InvalidOperationException(SR.GetString(SR.net_socketopinprogress));
  7597. }
  7598. // Prepare execution context for callback.
  7599. if (ExecutionContext.IsFlowSuppressed()) {
  7600. // Fast path for when flow is suppressed.
  7601. m_Context = null;
  7602. m_ContextCopy = null;
  7603. } else {
  7604. // Flow is not suppressed.
  7605. // If event delegates have changed or socket has changed
  7606. // then discard any existing context.
  7607. if (m_CompletedChanged || socket != m_CurrentSocket) {
  7608. m_CompletedChanged = false;
  7609. m_Context = null;
  7610. m_ContextCopy = null;
  7611. }
  7612. // Capture execution context if none already.
  7613. if (m_Context == null) {
  7614. m_Context = ExecutionContext.Capture();
  7615. }
  7616. // If there is an execution context we need a fresh copy for each completion.
  7617. if(m_Context != null) {
  7618. m_ContextCopy = m_Context.CreateCopy();
  7619. }
  7620. }
  7621. // Remember current socket.
  7622. m_CurrentSocket = socket;
  7623. }
  7624. internal void StartOperationAccept() {
  7625. // Remember the operation type.
  7626. m_CompletedOperation = SocketAsyncOperation.Accept;
  7627. // AcceptEx needs a single buffer with room for two special sockaddr data structures.
  7628. // It can also take additional buffer space in front of those special sockaddr
  7629. // structures that can be filled in with initial data coming in on a connection.
  7630. // First calculate the special AcceptEx address buffer size.
  7631. // It is the size of two native sockaddr buffers with 16 extra bytes each.
  7632. // The native sockaddr buffers vary by address family so must reference the current socket.
  7633. m_AcceptAddressBufferCount = 2 * (m_CurrentSocket.m_RightEndPoint.Serialize().Size + 16);
  7634. // If our caller specified a buffer (willing to get received data with the Accept) then
  7635. // it needs to be large enough for the two special sockaddr buffers that AcceptEx requires.
  7636. // Throw if that buffer is not large enough.
  7637. if(m_Buffer != null) {
  7638. // Caller specified a buffer - see if it is large enough
  7639. if(m_Count < m_AcceptAddressBufferCount) {
  7640. throw new ArgumentException(SR.GetString(SR.net_buffercounttoosmall, "Count"));
  7641. }
  7642. // Buffer is already pinned.
  7643. } else {
  7644. // Caller didn't specify a buffer so use an internal one.
  7645. // See if current internal one is big enough, otherwise create a new one.
  7646. if(m_AcceptBuffer == null || m_AcceptBuffer.Length < m_AcceptAddressBufferCount) {
  7647. m_AcceptBuffer = new byte[m_AcceptAddressBufferCount];
  7648. }
  7649. CheckPinSingleBuffer(false);
  7650. }
  7651. }
  7652. internal void StartOperationConnect() {
  7653. // Remember the operation type.
  7654. m_CompletedOperation = SocketAsyncOperation.Connect;
  7655. m_MultipleConnect = null;
  7656. m_ConnectSocket = null;
  7657. // ConnectEx uses a sockaddr buffer containing he remote address to which to connect.
  7658. // It can also optionally take a single buffer of data to send after the connection is complete.
  7659. //
  7660. // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
  7661. // The optional buffer is pinned using the Overlapped.UnsafePack method that takes a single object to pin.
  7662. PinSocketAddressBuffer();
  7663. CheckPinNoBuffer();
  7664. }
  7665. internal void StartOperationWrapperConnect(MultipleConnectAsync args) {
  7666. m_CompletedOperation = SocketAsyncOperation.Connect;
  7667. m_MultipleConnect = args;
  7668. m_ConnectSocket = null;
  7669. }
  7670. internal void CancelConnectAsync() {
  7671. if (m_Operating == InProgress && m_CompletedOperation == SocketAsyncOperation.Connect) {
  7672. if (m_MultipleConnect != null) {
  7673. // if a multiple connect is in progress, abort it
  7674. m_MultipleConnect.Cancel();
  7675. }
  7676. else {
  7677. // otherwise we're doing a normal ConnectAsync - cancel it by closing the socket
  7678. // m_CurrentSocket will only be null if m_MultipleConnect was set, so we don't have to check
  7679. GlobalLog.Assert(m_CurrentSocket != null, "SocketAsyncEventArgs::CancelConnectAsync - CurrentSocket and MultipleConnect both null!");
  7680. m_CurrentSocket.Close();
  7681. }
  7682. }
  7683. }
  7684. internal void StartOperationDisconnect() {
  7685. // Remember the operation type.
  7686. m_CompletedOperation = SocketAsyncOperation.Disconnect;
  7687. CheckPinNoBuffer();
  7688. }
  7689. internal void StartOperationReceive() {
  7690. // Remember the operation type.
  7691. m_CompletedOperation = SocketAsyncOperation.Receive;
  7692. // WWSARecv uses a WSABuffer array describing buffers of data to send.
  7693. // Single and multiple buffers are handled differently so as to optimize
  7694. // performance for the more common single buffer case.
  7695. // For a single buffer:
  7696. // The Overlapped.UnsafePack method is used that takes a single object to pin.
  7697. // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
  7698. // For multiple buffers:
  7699. // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
  7700. // An array to reference the multiple buffer is allocated.
  7701. // An array of WSABuffer descriptors is allocated.
  7702. }
  7703. internal void StartOperationReceiveFrom() {
  7704. // Remember the operation type.
  7705. m_CompletedOperation = SocketAsyncOperation.ReceiveFrom;
  7706. // WSARecvFrom uses e a WSABuffer array describing buffers in which to
  7707. // receive data and from which to send data respectively. Single and multiple buffers
  7708. // are handled differently so as to optimize performance for the more common single buffer case.
  7709. // For a single buffer:
  7710. // The Overlapped.UnsafePack method is used that takes a single object to pin.
  7711. // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
  7712. // For multiple buffers:
  7713. // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
  7714. // An array to reference the multiple buffer is allocated.
  7715. // An array of WSABuffer descriptors is allocated.
  7716. // WSARecvFrom and WSASendTo also uses a sockaddr buffer in which to store the address from which the data was received.
  7717. // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
  7718. PinSocketAddressBuffer();
  7719. }
  7720. internal void StartOperationReceiveMessageFrom() {
  7721. // Remember the operation type.
  7722. m_CompletedOperation = SocketAsyncOperation.ReceiveMessageFrom;
  7723. // WSARecvMsg uses a WSAMsg descriptor.
  7724. // The WSAMsg buffer is pinned with a GCHandle to avoid complicating the use of Overlapped.
  7725. // WSAMsg contains a pointer to a sockaddr.
  7726. // The sockaddr is pinned with a GCHandle to avoid complicating the use of Overlapped.
  7727. // WSAMsg contains a pointer to a WSABuffer array describing data buffers.
  7728. // WSAMsg also contains a single WSABuffer describing a control buffer.
  7729. //
  7730. PinSocketAddressBuffer();
  7731. // Create and pin a WSAMessageBuffer if none already.
  7732. if(m_WSAMessageBuffer == null) {
  7733. m_WSAMessageBuffer = new byte[s_WSAMsgSize];
  7734. m_WSAMessageBufferGCHandle = GCHandle.Alloc(m_WSAMessageBuffer, GCHandleType.Pinned);
  7735. m_PtrWSAMessageBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSAMessageBuffer, 0);
  7736. }
  7737. // Create and pin an appropriately sized control buffer if none already
  7738. IPAddress ipAddress = (m_SocketAddress.Family == AddressFamily.InterNetworkV6
  7739. ? m_SocketAddress.GetIPAddress() : null);
  7740. bool ipv4 = (m_CurrentSocket.AddressFamily == AddressFamily.InterNetwork
  7741. || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode
  7742. bool ipv6 = m_CurrentSocket.AddressFamily == AddressFamily.InterNetworkV6;
  7743. if(ipv4 && (m_ControlBuffer == null || m_ControlBuffer.Length != s_ControlDataSize)) {
  7744. if(m_ControlBufferGCHandle.IsAllocated) {
  7745. m_ControlBufferGCHandle.Free();
  7746. }
  7747. m_ControlBuffer = new byte[s_ControlDataSize];
  7748. } else if(ipv6 && (m_ControlBuffer == null || m_ControlBuffer.Length != s_ControlDataIPv6Size)) {
  7749. if(m_ControlBufferGCHandle.IsAllocated) {
  7750. m_ControlBufferGCHandle.Free();
  7751. }
  7752. m_ControlBuffer = new byte[s_ControlDataIPv6Size];
  7753. }
  7754. if(!m_ControlBufferGCHandle.IsAllocated) {
  7755. m_ControlBufferGCHandle = GCHandle.Alloc(m_ControlBuffer, GCHandleType.Pinned);
  7756. m_PtrControlBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_ControlBuffer, 0);
  7757. }
  7758. // If single buffer we need a pinned 1 element WSABuffer.
  7759. if(m_Buffer != null) {
  7760. if(m_WSARecvMsgWSABufferArray == null) {
  7761. m_WSARecvMsgWSABufferArray = new WSABuffer[1];
  7762. }
  7763. m_WSARecvMsgWSABufferArray[0].Pointer = m_PtrSingleBuffer;
  7764. m_WSARecvMsgWSABufferArray[0].Length = m_Count;
  7765. m_WSARecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(m_WSARecvMsgWSABufferArray, GCHandleType.Pinned);
  7766. m_PtrWSARecvMsgWSABufferArray = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSARecvMsgWSABufferArray, 0);
  7767. } else {
  7768. // just pin the multi-buffer WSABuffer
  7769. m_WSARecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(m_WSABufferArray, GCHandleType.Pinned);
  7770. m_PtrWSARecvMsgWSABufferArray = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSABufferArray, 0);
  7771. }
  7772. // Fill in WSAMessageBuffer
  7773. unsafe {
  7774. UnsafeNclNativeMethods.OSSOCK.WSAMsg* pMessage = (UnsafeNclNativeMethods.OSSOCK.WSAMsg*)m_PtrWSAMessageBuffer;;
  7775. pMessage->socketAddress = m_PtrSocketAddressBuffer;
  7776. pMessage->addressLength = (uint)m_SocketAddress.Size;
  7777. pMessage->buffers = m_PtrWSARecvMsgWSABufferArray;
  7778. if(m_Buffer != null) {
  7779. pMessage->count = (uint)1;
  7780. } else {
  7781. pMessage->count = (uint)m_WSABufferArray.Length;
  7782. }
  7783. if(m_ControlBuffer != null) {
  7784. pMessage->controlBuffer.Pointer = m_PtrControlBuffer;
  7785. pMessage->controlBuffer.Length = m_ControlBuffer.Length;
  7786. }
  7787. pMessage->flags = m_SocketFlags;
  7788. }
  7789. }
  7790. internal void StartOperationSend() {
  7791. // Remember the operation type.
  7792. m_CompletedOperation = SocketAsyncOperation.Send;
  7793. // WSASend uses a WSABuffer array describing buffers of data to send.
  7794. // Single and multiple buffers are handled differently so as to optimize
  7795. // performance for the more common single buffer case.
  7796. // For a single buffer:
  7797. // The Overlapped.UnsafePack method is used that takes a single object to pin.
  7798. // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
  7799. // For multiple buffers:
  7800. // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
  7801. // An array to reference the multiple buffer is allocated.
  7802. // An array of WSABuffer descriptors is allocated.
  7803. }
  7804. internal void StartOperationSendPackets() {
  7805. // Remember the operation type.
  7806. m_CompletedOperation = SocketAsyncOperation.SendPackets;
  7807. // Prevent mutithreaded manipulation of the list.
  7808. if (m_SendPacketsElements != null) {
  7809. m_SendPacketsElementsInternal = (SendPacketsElement[])m_SendPacketsElements.Clone();
  7810. }
  7811. // TransmitPackets uses an array of TRANSMIT_PACKET_ELEMENT structs as
  7812. // descriptors for buffers and files to be sent. It also takes a send size
  7813. // and some flags. The TRANSMIT_PACKET_ELEMENT for a file contains a native file handle.
  7814. // This function basically opens the files to get the file handles, pins down any buffers
  7815. // specified and builds the native TRANSMIT_PACKET_ELEMENT array that will be passed
  7816. // to TransmitPackets.
  7817. // Scan the elements to count files and buffers
  7818. m_SendPacketsElementsFileCount = 0;
  7819. m_SendPacketsElementsBufferCount = 0;
  7820. foreach (SendPacketsElement spe in m_SendPacketsElementsInternal) {
  7821. if(spe != null) {
  7822. if(spe.m_FilePath != null) {
  7823. m_SendPacketsElementsFileCount++;
  7824. }
  7825. if(spe.m_Buffer != null && spe.m_Count > 0) {
  7826. m_SendPacketsElementsBufferCount++;
  7827. }
  7828. }
  7829. }
  7830. // Attempt to open the files if any
  7831. if(m_SendPacketsElementsFileCount > 0) {
  7832. // Create arrays for streams and handles
  7833. m_SendPacketsFileStreams = new FileStream[m_SendPacketsElementsFileCount];
  7834. m_SendPacketsFileHandles = new SafeHandle[m_SendPacketsElementsFileCount];
  7835. // Loop through the elements attempting to open each files and get its handle
  7836. int index = 0;
  7837. foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
  7838. if(spe != null && spe.m_FilePath != null) {
  7839. Exception fileStreamException = null;
  7840. try {
  7841. // Create a FileStream to open the file
  7842. m_SendPacketsFileStreams[index] =
  7843. new FileStream(spe.m_FilePath,FileMode.Open,FileAccess.Read,FileShare.Read);
  7844. }
  7845. catch (Exception ex) {
  7846. // Save the exception to throw after closing any previous successful file opens
  7847. fileStreamException = ex;
  7848. }
  7849. if (fileStreamException != null) {
  7850. // Got exception opening a file - do some cleanup then throw
  7851. for(int i = 0; i < m_SendPacketsElementsFileCount; i++) {
  7852. // Dereference handles
  7853. m_SendPacketsFileHandles[i] = null;
  7854. // Close any open streams
  7855. if(m_SendPacketsFileStreams[i] != null) {
  7856. m_SendPacketsFileStreams[i].Close();
  7857. m_SendPacketsFileStreams[i] = null;
  7858. }
  7859. }
  7860. throw fileStreamException;
  7861. }
  7862. // Get the file handle from the stream
  7863. ExceptionHelper.UnmanagedPermission.Assert();
  7864. try {
  7865. m_SendPacketsFileHandles[index] = m_SendPacketsFileStreams[index].SafeFileHandle;
  7866. }
  7867. finally {
  7868. SecurityPermission.RevertAssert();
  7869. }
  7870. index++;
  7871. }
  7872. }
  7873. }
  7874. CheckPinSendPackets();
  7875. }
  7876. internal void StartOperationSendTo() {
  7877. // Remember the operation type.
  7878. m_CompletedOperation = SocketAsyncOperation.SendTo;
  7879. // WSASendTo uses a WSABuffer array describing buffers in which to
  7880. // receive data and from which to send data respectively. Single and multiple buffers
  7881. // are handled differently so as to optimize performance for the more common single buffer case.
  7882. // For a single buffer:
  7883. // The Overlapped.UnsafePack method is used that takes a single object to pin.
  7884. // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
  7885. // For multiple buffers:
  7886. // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
  7887. // An array to reference the multiple buffer is allocated.
  7888. // An array of WSABuffer descriptors is allocated.
  7889. // WSARecvFrom and WSASendTo also uses a sockaddr buffer in which to store the address from which the data was received.
  7890. // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
  7891. PinSocketAddressBuffer();
  7892. }
  7893. // Method to ensure Overlapped object exists for operations that need no data buffer.
  7894. private void CheckPinNoBuffer() {
  7895. if (m_PinState == PinState.None) {
  7896. SetupOverlappedSingle(true);
  7897. }
  7898. }
  7899. // Method to maintain pinned state of single buffer
  7900. private void CheckPinSingleBuffer(bool pinUsersBuffer) {
  7901. if (pinUsersBuffer) {
  7902. // Using app supplied buffer.
  7903. if (m_Buffer == null) {
  7904. // No user buffer is set so unpin any existing single buffer pinning.
  7905. if(m_PinState == PinState.SingleBuffer) {
  7906. FreeOverlapped(false);
  7907. }
  7908. } else {
  7909. if(m_PinState == PinState.SingleBuffer && m_PinnedSingleBuffer == m_Buffer) {
  7910. // This buffer is already pinned - update if offset or count has changed.
  7911. if (m_Offset != m_PinnedSingleBufferOffset) {
  7912. m_PinnedSingleBufferOffset = m_Offset;
  7913. m_PtrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, m_Offset);
  7914. m_WSABuffer.Pointer = m_PtrSingleBuffer;
  7915. }
  7916. if (m_Count != m_PinnedSingleBufferCount) {
  7917. m_PinnedSingleBufferCount = m_Count;
  7918. m_WSABuffer.Length = m_Count;
  7919. }
  7920. } else {
  7921. FreeOverlapped(false);
  7922. SetupOverlappedSingle(true);
  7923. }
  7924. }
  7925. } else {
  7926. // Using internal accept buffer.
  7927. if(!(m_PinState == PinState.SingleAcceptBuffer) || !(m_PinnedSingleBuffer == m_AcceptBuffer)) {
  7928. // Not already pinned - so pin it.
  7929. FreeOverlapped(false);
  7930. SetupOverlappedSingle(false);
  7931. }
  7932. }
  7933. }
  7934. // Method to ensure Overlapped object exists with appropriate multiple buffers pinned.
  7935. private void CheckPinMultipleBuffers() {
  7936. if (m_BufferList == null) {
  7937. // No buffer list is set so unpin any existing multiple buffer pinning.
  7938. if(m_PinState == PinState.MultipleBuffer) {
  7939. FreeOverlapped(false);
  7940. }
  7941. } else {
  7942. if(!(m_PinState == PinState.MultipleBuffer) || m_BufferListChanged) {
  7943. // Need to setup new Overlapped
  7944. m_BufferListChanged = false;
  7945. FreeOverlapped(false);
  7946. try
  7947. {
  7948. SetupOverlappedMultiple();
  7949. }
  7950. catch (Exception)
  7951. {
  7952. FreeOverlapped(false);
  7953. throw;
  7954. }
  7955. }
  7956. }
  7957. }
  7958. // Method to ensure Overlapped object exists with appropriate buffers pinned.
  7959. private void CheckPinSendPackets() {
  7960. if(m_PinState != PinState.None) {
  7961. FreeOverlapped(false);
  7962. }
  7963. SetupOverlappedSendPackets();
  7964. }
  7965. // Method to ensure appropriate SocketAddress buffer is pinned.
  7966. private void PinSocketAddressBuffer() {
  7967. // Check if already pinned.
  7968. if(m_PinnedSocketAddress == m_SocketAddress) {
  7969. return;
  7970. }
  7971. // Unpin any existing.
  7972. if(m_SocketAddressGCHandle.IsAllocated) {
  7973. m_SocketAddressGCHandle.Free();
  7974. }
  7975. // Pin down the new one.
  7976. m_SocketAddressGCHandle = GCHandle.Alloc(m_SocketAddress.m_Buffer, GCHandleType.Pinned);
  7977. m_SocketAddress.CopyAddressSizeIntoBuffer();
  7978. m_PtrSocketAddressBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_SocketAddress.m_Buffer, 0);
  7979. m_PtrSocketAddressBufferSize = Marshal.UnsafeAddrOfPinnedArrayElement(m_SocketAddress.m_Buffer, m_SocketAddress.GetAddressSizeOffset());
  7980. m_PinnedSocketAddress = m_SocketAddress;
  7981. }
  7982. // Method to clean up any existing Overlapped object and related state variables.
  7983. private void FreeOverlapped(bool checkForShutdown) {
  7984. if (!checkForShutdown || !NclUtilities.HasShutdownStarted) {
  7985. // Free the overlapped object
  7986. if(m_PtrNativeOverlapped != null && !m_PtrNativeOverlapped.IsInvalid) {
  7987. m_PtrNativeOverlapped.Dispose();
  7988. m_PtrNativeOverlapped = null;
  7989. m_Overlapped = null;
  7990. m_PinState = PinState.None;
  7991. m_PinnedAcceptBuffer = null;
  7992. m_PinnedSingleBuffer = null;
  7993. m_PinnedSingleBufferOffset = 0;
  7994. m_PinnedSingleBufferCount = 0;
  7995. }
  7996. // Free any alloc'd GCHandles
  7997. if(m_SocketAddressGCHandle.IsAllocated) {
  7998. m_SocketAddressGCHandle.Free();
  7999. }
  8000. if(m_WSAMessageBufferGCHandle.IsAllocated) {
  8001. m_WSAMessageBufferGCHandle.Free();
  8002. }
  8003. if(m_WSARecvMsgWSABufferArrayGCHandle.IsAllocated) {
  8004. m_WSARecvMsgWSABufferArrayGCHandle.Free();
  8005. }
  8006. if(m_ControlBufferGCHandle.IsAllocated) {
  8007. m_ControlBufferGCHandle.Free();
  8008. }
  8009. }
  8010. }
  8011. // Method to setup an Overlapped object with either m_Buffer or m_AcceptBuffer pinned.
  8012. unsafe private void SetupOverlappedSingle(bool pinSingleBuffer) {
  8013. // Alloc new Overlapped.
  8014. m_Overlapped = new Overlapped();
  8015. // Pin buffer, get native pointers, and fill in WSABuffer descriptor.
  8016. if(pinSingleBuffer) {
  8017. if(m_Buffer != null) {
  8018. #if SOCKETTHREADPOOL
  8019. m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
  8020. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_Buffer));
  8021. #else
  8022. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_Buffer));
  8023. #endif
  8024. m_PinnedSingleBuffer = m_Buffer;
  8025. m_PinnedSingleBufferOffset = m_Offset;
  8026. m_PinnedSingleBufferCount = m_Count;
  8027. m_PtrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, m_Offset);
  8028. m_PtrAcceptBuffer = IntPtr.Zero;
  8029. m_WSABuffer.Pointer = m_PtrSingleBuffer;
  8030. m_WSABuffer.Length = m_Count;
  8031. m_PinState = PinState.SingleBuffer;
  8032. } else {
  8033. #if SOCKETTHREADPOOL
  8034. m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
  8035. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, null));
  8036. #else
  8037. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, null));
  8038. #endif
  8039. m_PinnedSingleBuffer = null;
  8040. m_PinnedSingleBufferOffset = 0;
  8041. m_PinnedSingleBufferCount = 0;
  8042. m_PtrSingleBuffer = IntPtr.Zero;
  8043. m_PtrAcceptBuffer = IntPtr.Zero;
  8044. m_WSABuffer.Pointer = m_PtrSingleBuffer;
  8045. m_WSABuffer.Length = m_Count;
  8046. m_PinState = PinState.NoBuffer;
  8047. }
  8048. } else {
  8049. #if SOCKETTHREADPOOL
  8050. m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
  8051. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_AcceptBuffer));
  8052. #else
  8053. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_AcceptBuffer));
  8054. #endif
  8055. m_PinnedAcceptBuffer = m_AcceptBuffer;
  8056. m_PtrAcceptBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_AcceptBuffer, 0);
  8057. m_PtrSingleBuffer = IntPtr.Zero;
  8058. m_PinState = PinState.SingleAcceptBuffer;
  8059. }
  8060. }
  8061. // Method to setup an Overlapped object with with multiple buffers pinned.
  8062. unsafe private void SetupOverlappedMultiple() {
  8063. ArraySegment<byte>[] tempList = new ArraySegment<byte>[m_BufferList.Count];
  8064. m_BufferList.CopyTo(tempList, 0);
  8065. // Alloc new Overlapped.
  8066. m_Overlapped = new Overlapped();
  8067. // Number of things to pin is number of buffers.
  8068. // Ensure we have properly sized object array.
  8069. if(m_ObjectsToPin == null || (m_ObjectsToPin.Length != tempList.Length)) {
  8070. m_ObjectsToPin = new object[tempList.Length];
  8071. }
  8072. // Fill in object array.
  8073. for(int i = 0; i < (tempList.Length); i++) {
  8074. m_ObjectsToPin[i] = tempList[i].Array;
  8075. }
  8076. if(m_WSABufferArray == null || m_WSABufferArray.Length != tempList.Length) {
  8077. m_WSABufferArray = new WSABuffer[tempList.Length];
  8078. }
  8079. // Pin buffers and fill in WSABuffer descriptor pointers and lengths
  8080. #if SOCKETTHREADPOOL
  8081. m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
  8082. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_ObjectsToPin));
  8083. #else
  8084. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_ObjectsToPin));
  8085. #endif
  8086. for(int i = 0; i < tempList.Length; i++) {
  8087. ArraySegment<byte> localCopy = tempList[i];
  8088. ValidationHelper.ValidateSegment(localCopy);
  8089. m_WSABufferArray[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(localCopy.Array, localCopy.Offset);
  8090. m_WSABufferArray[i].Length = localCopy.Count;
  8091. }
  8092. m_PinState = PinState.MultipleBuffer;
  8093. }
  8094. // Method to setup an Overlapped object for SendPacketsAsync.
  8095. unsafe private void SetupOverlappedSendPackets() {
  8096. int index;
  8097. // Alloc new Overlapped.
  8098. m_Overlapped = new Overlapped();
  8099. // Alloc native descriptor.
  8100. m_SendPacketsDescriptor =
  8101. new UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElement[m_SendPacketsElementsFileCount + m_SendPacketsElementsBufferCount];
  8102. // Number of things to pin is number of buffers + 1 (native descriptor).
  8103. // Ensure we have properly sized object array.
  8104. if(m_ObjectsToPin == null || (m_ObjectsToPin.Length != m_SendPacketsElementsBufferCount + 1)) {
  8105. m_ObjectsToPin = new object[m_SendPacketsElementsBufferCount + 1];
  8106. }
  8107. // Fill in objects to pin array. Native descriptor buffer first and then user specified buffers.
  8108. m_ObjectsToPin[0] = m_SendPacketsDescriptor;
  8109. index = 1;
  8110. foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
  8111. if(spe != null && spe.m_Buffer != null && spe.m_Count > 0) {
  8112. m_ObjectsToPin[index] = spe.m_Buffer;
  8113. index++;
  8114. }
  8115. }
  8116. // Pin buffers
  8117. #if SOCKETTHREADPOOL
  8118. m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
  8119. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_ObjectsToPin));
  8120. #else
  8121. m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_ObjectsToPin));
  8122. #endif
  8123. // Get pointer to native descriptor.
  8124. m_PtrSendPacketsDescriptor = Marshal.UnsafeAddrOfPinnedArrayElement(m_SendPacketsDescriptor, 0);
  8125. // Fill in native descriptor.
  8126. int descriptorIndex = 0;
  8127. int fileIndex = 0;
  8128. foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
  8129. if (spe != null) {
  8130. if(spe.m_Buffer != null && spe.m_Count > 0) {
  8131. // a buffer
  8132. m_SendPacketsDescriptor[descriptorIndex].buffer = Marshal.UnsafeAddrOfPinnedArrayElement(spe.m_Buffer, spe.m_Offset);
  8133. m_SendPacketsDescriptor[descriptorIndex].length = (uint)spe.m_Count;
  8134. m_SendPacketsDescriptor[descriptorIndex].flags = spe.m_Flags;
  8135. descriptorIndex++;
  8136. } else if (spe.m_FilePath != null) {
  8137. // a file
  8138. m_SendPacketsDescriptor[descriptorIndex].fileHandle = m_SendPacketsFileHandles[fileIndex].DangerousGetHandle();
  8139. m_SendPacketsDescriptor[descriptorIndex].fileOffset = spe.m_Offset;
  8140. m_SendPacketsDescriptor[descriptorIndex].length = (uint)spe.m_Count;
  8141. m_SendPacketsDescriptor[descriptorIndex].flags = spe.m_Flags;
  8142. fileIndex++;
  8143. descriptorIndex++;
  8144. }
  8145. }
  8146. }
  8147. m_PinState = PinState.SendPackets;
  8148. }
  8149. internal void LogBuffer(int size) {
  8150. switch(m_PinState) {
  8151. case PinState.SingleAcceptBuffer:
  8152. Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", m_AcceptBuffer, 0, size);
  8153. break;
  8154. case PinState.SingleBuffer:
  8155. Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", m_Buffer, m_Offset, size);
  8156. break;
  8157. case PinState.MultipleBuffer:
  8158. foreach(WSABuffer wsaBuffer in m_WSABufferArray) {
  8159. Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", wsaBuffer.Pointer, Math.Min(wsaBuffer.Length, size));
  8160. if((size -= wsaBuffer.Length) <= 0)
  8161. break;
  8162. }
  8163. break;
  8164. default:
  8165. break;
  8166. }
  8167. }
  8168. internal void LogSendPacketsBuffers(int size) {
  8169. foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
  8170. if (spe != null) {
  8171. if(spe.m_Buffer != null && spe.m_Count > 0) {
  8172. // a buffer
  8173. Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)Buffer", spe.m_Buffer, spe.m_Offset, Math.Min(spe.m_Count, size));
  8174. } else if(spe.m_FilePath != null) {
  8175. // a file
  8176. Logging.PrintInfo(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", SR.GetString(SR.net_log_socket_not_logged_file, spe.m_FilePath));
  8177. }
  8178. }
  8179. }
  8180. }
  8181. internal void UpdatePerfCounters(int size, bool sendOp) {
  8182. #if !FEATURE_PAL // perfcounter
  8183. if(sendOp) {
  8184. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, size);
  8185. if(m_CurrentSocket.Transport == TransportType.Udp) {
  8186. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
  8187. }
  8188. } else {
  8189. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, size);
  8190. if(m_CurrentSocket.Transport == TransportType.Udp) {
  8191. NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
  8192. }
  8193. }
  8194. #endif
  8195. }
  8196. internal void FinishOperationSyncFailure(SocketError socketError, int bytesTransferred, SocketFlags flags) {
  8197. SetResults(socketError, bytesTransferred, flags);
  8198. // this will be null if we're doing a static ConnectAsync to a DnsEndPoint with AddressFamily.Unspecified;
  8199. // the attempt socket will be closed anyways, so not updating the state is OK
  8200. if (m_CurrentSocket != null) {
  8201. m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
  8202. }
  8203. Complete();
  8204. }
  8205. internal void FinishConnectByNameSyncFailure(Exception exception, int bytesTransferred, SocketFlags flags) {
  8206. SetResults(exception, bytesTransferred, flags);
  8207. if (m_CurrentSocket != null) {
  8208. m_CurrentSocket.UpdateStatusAfterSocketError(m_SocketError);
  8209. }
  8210. Complete();
  8211. }
  8212. internal void FinishOperationAsyncFailure(SocketError socketError, int bytesTransferred, SocketFlags flags) {
  8213. SetResults(socketError, bytesTransferred, flags);
  8214. // this will be null if we're doing a static ConnectAsync to a DnsEndPoint with AddressFamily.Unspecified;
  8215. // the attempt socket will be closed anyways, so not updating the state is OK
  8216. if (m_CurrentSocket != null) {
  8217. m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
  8218. }
  8219. Complete();
  8220. if(m_Context == null) {
  8221. OnCompleted(this);
  8222. } else {
  8223. ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
  8224. }
  8225. }
  8226. internal void FinishOperationAsyncFailure(Exception exception, int bytesTransferred, SocketFlags flags) {
  8227. SetResults(exception, bytesTransferred, flags);
  8228. if (m_CurrentSocket != null) {
  8229. m_CurrentSocket.UpdateStatusAfterSocketError(m_SocketError);
  8230. }
  8231. Complete();
  8232. if (m_Context == null) {
  8233. OnCompleted(this);
  8234. } else {
  8235. ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
  8236. }
  8237. }
  8238. internal void FinishWrapperConnectSuccess(Socket connectSocket, int bytesTransferred, SocketFlags flags) {
  8239. SetResults(SocketError.Success, bytesTransferred, flags);
  8240. m_CurrentSocket = connectSocket;
  8241. m_ConnectSocket = connectSocket;
  8242. // Complete the operation and raise the event
  8243. Complete();
  8244. if (m_ContextCopy == null) {
  8245. OnCompleted(this);
  8246. } else {
  8247. ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
  8248. }
  8249. }
  8250. internal void FinishOperationSuccess(SocketError socketError, int bytesTransferred, SocketFlags flags) {
  8251. SetResults(socketError, bytesTransferred, flags);
  8252. switch(m_CompletedOperation) {
  8253. case SocketAsyncOperation.Accept:
  8254. if (bytesTransferred > 0) {
  8255. // Log and Perf counters.
  8256. if (s_LoggingEnabled) LogBuffer(bytesTransferred);
  8257. if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
  8258. }
  8259. // Get the endpoint.
  8260. SocketAddress remoteSocketAddress = m_CurrentSocket.m_RightEndPoint.Serialize();
  8261. IntPtr localAddr;
  8262. int localAddrLength;
  8263. IntPtr remoteAddr;
  8264. try {
  8265. m_CurrentSocket.GetAcceptExSockaddrs(
  8266. m_PtrSingleBuffer != IntPtr.Zero ? m_PtrSingleBuffer : m_PtrAcceptBuffer,
  8267. m_Count != 0 ? m_Count - m_AcceptAddressBufferCount : 0,
  8268. m_AcceptAddressBufferCount / 2,
  8269. m_AcceptAddressBufferCount / 2,
  8270. out localAddr,
  8271. out localAddrLength,
  8272. out remoteAddr,
  8273. out remoteSocketAddress.m_Size
  8274. );
  8275. Marshal.Copy(remoteAddr, remoteSocketAddress.m_Buffer, 0, remoteSocketAddress.m_Size);
  8276. // Set the socket context.
  8277. IntPtr handle = m_CurrentSocket.SafeHandle.DangerousGetHandle();
  8278. socketError = UnsafeNclNativeMethods.OSSOCK.setsockopt(
  8279. m_AcceptSocket.SafeHandle,
  8280. SocketOptionLevel.Socket,
  8281. SocketOptionName.UpdateAcceptContext,
  8282. ref handle,
  8283. Marshal.SizeOf(handle));
  8284. if(socketError == SocketError.SocketError) {
  8285. socketError = (SocketError)Marshal.GetLastWin32Error();
  8286. }
  8287. }
  8288. catch(ObjectDisposedException) {
  8289. socketError = SocketError.OperationAborted;
  8290. }
  8291. if(socketError == SocketError.Success) {
  8292. m_AcceptSocket = m_CurrentSocket.UpdateAcceptSocket(m_AcceptSocket, m_CurrentSocket.m_RightEndPoint.Create(remoteSocketAddress), false);
  8293. if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, m_AcceptSocket,
  8294. SR.GetString(SR.net_log_socket_accepted, m_AcceptSocket.RemoteEndPoint, m_AcceptSocket.LocalEndPoint));
  8295. } else {
  8296. SetResults(socketError, bytesTransferred, SocketFlags.None);
  8297. m_AcceptSocket = null;
  8298. }
  8299. break;
  8300. case SocketAsyncOperation.Connect:
  8301. if (bytesTransferred > 0) {
  8302. // Log and Perf counters.
  8303. if (s_LoggingEnabled) LogBuffer(bytesTransferred);
  8304. if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
  8305. }
  8306. // Update the socket context.
  8307. try {
  8308. socketError = UnsafeNclNativeMethods.OSSOCK.setsockopt(
  8309. m_CurrentSocket.SafeHandle,
  8310. SocketOptionLevel.Socket,
  8311. SocketOptionName.UpdateConnectContext,
  8312. null,
  8313. 0);
  8314. if(socketError == SocketError.SocketError) {
  8315. socketError = (SocketError)Marshal.GetLastWin32Error();
  8316. }
  8317. }
  8318. catch(ObjectDisposedException) {
  8319. socketError = SocketError.OperationAborted;
  8320. }
  8321. // Mark socket connected.
  8322. if(socketError == SocketError.Success) {
  8323. if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, m_CurrentSocket,
  8324. SR.GetString(SR.net_log_socket_connected, m_CurrentSocket.LocalEndPoint, m_CurrentSocket.RemoteEndPoint));
  8325. m_CurrentSocket.SetToConnected();
  8326. m_ConnectSocket = m_CurrentSocket;
  8327. }
  8328. break;
  8329. case SocketAsyncOperation.Disconnect:
  8330. m_CurrentSocket.SetToDisconnected();
  8331. m_CurrentSocket.m_RemoteEndPoint = null;
  8332. break;
  8333. case SocketAsyncOperation.Receive:
  8334. if (bytesTransferred > 0) {
  8335. // Log and Perf counters.
  8336. if (s_LoggingEnabled) LogBuffer(bytesTransferred);
  8337. if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
  8338. }
  8339. break;
  8340. case SocketAsyncOperation.ReceiveFrom:
  8341. if (bytesTransferred > 0) {
  8342. // Log and Perf counters.
  8343. if (s_LoggingEnabled) LogBuffer(bytesTransferred);
  8344. if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
  8345. }
  8346. // Deal with incoming address.
  8347. m_SocketAddress.SetSize(m_PtrSocketAddressBufferSize);
  8348. SocketAddress socketAddressOriginal = m_RemoteEndPoint.Serialize();
  8349. if(!socketAddressOriginal.Equals(m_SocketAddress)) {
  8350. try {
  8351. m_RemoteEndPoint = m_RemoteEndPoint.Create(m_SocketAddress);
  8352. }
  8353. catch {
  8354. }
  8355. }
  8356. break;
  8357. case SocketAsyncOperation.ReceiveMessageFrom:
  8358. if (bytesTransferred > 0) {
  8359. // Log and Perf counters.
  8360. if (s_LoggingEnabled) LogBuffer(bytesTransferred);
  8361. if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
  8362. }
  8363. // Deal with incoming address.
  8364. m_SocketAddress.SetSize(m_PtrSocketAddressBufferSize);
  8365. socketAddressOriginal = m_RemoteEndPoint.Serialize();
  8366. if(!socketAddressOriginal.Equals(m_SocketAddress)) {
  8367. try {
  8368. m_RemoteEndPoint = m_RemoteEndPoint.Create(m_SocketAddress);
  8369. }
  8370. catch {
  8371. }
  8372. }
  8373. // Extract the packet information.
  8374. unsafe {
  8375. IPAddress address = null;
  8376. UnsafeNclNativeMethods.OSSOCK.WSAMsg* PtrMessage = (UnsafeNclNativeMethods.OSSOCK.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(m_WSAMessageBuffer, 0);
  8377. //ipv4
  8378. if(m_ControlBuffer.Length == s_ControlDataSize) {
  8379. UnsafeNclNativeMethods.OSSOCK.ControlData controlData = (UnsafeNclNativeMethods.OSSOCK.ControlData)Marshal.PtrToStructure(PtrMessage->controlBuffer.Pointer, typeof(UnsafeNclNativeMethods.OSSOCK.ControlData));
  8380. if(controlData.length != UIntPtr.Zero) {
  8381. address = new IPAddress((long)controlData.address);
  8382. }
  8383. m_ReceiveMessageFromPacketInfo = new IPPacketInformation(((address != null) ? address : IPAddress.None), (int)controlData.index);
  8384. }
  8385. //ipv6
  8386. else if(m_ControlBuffer.Length == s_ControlDataIPv6Size) {
  8387. UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6 controlData = (UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6)Marshal.PtrToStructure(PtrMessage->controlBuffer.Pointer, typeof(UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6));
  8388. if(controlData.length != UIntPtr.Zero) {
  8389. address = new IPAddress(controlData.address);
  8390. }
  8391. m_ReceiveMessageFromPacketInfo = new IPPacketInformation(((address != null) ? address : IPAddress.IPv6None), (int)controlData.index);
  8392. }
  8393. //other
  8394. else {
  8395. m_ReceiveMessageFromPacketInfo = new IPPacketInformation();
  8396. }
  8397. }
  8398. break;
  8399. case SocketAsyncOperation.Send:
  8400. if (bytesTransferred > 0) {
  8401. // Log and Perf counters.
  8402. if (s_LoggingEnabled) LogBuffer(bytesTransferred);
  8403. if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
  8404. }
  8405. break;
  8406. case SocketAsyncOperation.SendPackets:
  8407. if(bytesTransferred > 0) {
  8408. // Log and Perf counters.
  8409. if(s_LoggingEnabled) LogSendPacketsBuffers(bytesTransferred);
  8410. if(Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
  8411. }
  8412. // Close the files if open
  8413. if (m_SendPacketsFileStreams != null) {
  8414. for(int i = 0; i < m_SendPacketsElementsFileCount; i++) {
  8415. // Dereference handles
  8416. m_SendPacketsFileHandles[i] = null;
  8417. // Close any open streams
  8418. if(m_SendPacketsFileStreams[i] != null) {
  8419. m_SendPacketsFileStreams[i].Close();
  8420. m_SendPacketsFileStreams[i] = null;
  8421. }
  8422. }
  8423. }
  8424. m_SendPacketsFileStreams = null;
  8425. m_SendPacketsFileHandles = null;
  8426. break;
  8427. case SocketAsyncOperation.SendTo:
  8428. if (bytesTransferred > 0) {
  8429. // Log and Perf counters.
  8430. if (s_LoggingEnabled) LogBuffer(bytesTransferred);
  8431. if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
  8432. }
  8433. break;
  8434. }
  8435. if(socketError != SocketError.Success) {
  8436. // Asynchronous failure or something went wrong after async success.
  8437. SetResults(socketError, bytesTransferred, flags);
  8438. m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
  8439. }
  8440. // Complete the operation and raise completion event.
  8441. Complete();
  8442. if(m_ContextCopy == null) {
  8443. OnCompleted(this);
  8444. } else {
  8445. ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
  8446. }
  8447. }
  8448. private unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) {
  8449. #if DEBUG
  8450. GlobalLog.SetThreadSource(ThreadKinds.CompletionPort);
  8451. using(GlobalLog.SetThreadKind(ThreadKinds.System)) {
  8452. #endif
  8453. SocketFlags socketFlags = SocketFlags.None;
  8454. SocketError socketError = (SocketError)errorCode;
  8455. if(socketError == SocketError.Success) {
  8456. FinishOperationSuccess(socketError, (int)numBytes, socketFlags);
  8457. } else {
  8458. if(socketError != SocketError.OperationAborted) {
  8459. if(m_CurrentSocket.CleanedUp) {
  8460. socketError = SocketError.OperationAborted;
  8461. } else {
  8462. try {
  8463. // This is the same NativeOverlapped* as we already have a SafeHandle for, re-use the orriginal.
  8464. Debug.Assert((IntPtr)nativeOverlapped == m_PtrNativeOverlapped.DangerousGetHandle(), "Handle mismatch");
  8465. // The Async IO completed with a failure.
  8466. // here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error.
  8467. bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult(
  8468. m_CurrentSocket.SafeHandle,
  8469. m_PtrNativeOverlapped,
  8470. out numBytes,
  8471. false,
  8472. out socketFlags);
  8473. socketError = (SocketError)Marshal.GetLastWin32Error();
  8474. }
  8475. catch {
  8476. // m_CurrentSocket.CleanedUp check above does not always work since this code is subject to race conditions
  8477. socketError = SocketError.OperationAborted;
  8478. }
  8479. }
  8480. }
  8481. FinishOperationAsyncFailure(socketError, (int)numBytes, socketFlags);
  8482. }
  8483. #if DEBUG
  8484. }
  8485. #endif
  8486. }
  8487. } // class SocketAsyncContext
  8488. #if SOCKETTHREADPOOL
  8489. internal static class SocketThreadPool
  8490. {
  8491. private static readonly int c_threadIOCPTimeout = 15000; // milliseconds
  8492. private static readonly IntPtr c_InvalidHandleValue = new IntPtr(-1);
  8493. private static readonly int m_maxThreadsAllowed = System.Int32.MaxValue; //Maybe (Environment.ProcessorCount * some_factor) ?
  8494. private static int m_numThreadsInPool = 0;
  8495. private static int m_maxThreadsEverInPool = 0;
  8496. private static int m_numBusyThreads = 0;
  8497. private static int m_numCallbacks = 0;
  8498. private static int m_numBoundHandles = 0;
  8499. private static object s_InternalSyncObject;
  8500. private static bool initialized = false;
  8501. private static IntPtr m_hIOCP = c_InvalidHandleValue;
  8502. public static bool BindHandle(SafeHandle osHandle)
  8503. {
  8504. // ensure initialized
  8505. Init();
  8506. // bind to completion port
  8507. IntPtr handle = UnsafeNclNativeMethods.OSSOCK.CreateIoCompletionPort(osHandle, m_hIOCP, 1111, 0);
  8508. if (handle == IntPtr.Zero)
  8509. {
  8510. throw new Exception(string.Format("CreateIoCompletionPort failed with Win32 error {0}.", Marshal.GetLastWin32Error()));
  8511. }
  8512. // count handle
  8513. Interlocked.Increment(ref m_numBoundHandles);
  8514. if (m_numThreadsInPool == 0)
  8515. {
  8516. // add thread to pool if none
  8517. AddThreadToPool();
  8518. }
  8519. return true;
  8520. }
  8521. public static void UnBindHandle(SafeHandle osHandle)
  8522. {
  8523. // take count to zero
  8524. Interlocked.Decrement(ref m_numBoundHandles);
  8525. }
  8526. private static void Init()
  8527. {
  8528. if (!initialized)
  8529. {
  8530. lock (InternalSyncObject)
  8531. {
  8532. if (!initialized)
  8533. {
  8534. // Create completion port
  8535. m_hIOCP = UnsafeNclNativeMethods.OSSOCK.CreateIoCompletionPort(c_InvalidHandleValue, IntPtr.Zero, 1111, 0);
  8536. if (m_hIOCP == c_InvalidHandleValue)
  8537. {
  8538. throw new Exception(string.Format("CreateIoCompletionPort failed with Win32 error {0}.", Marshal.GetLastWin32Error()));
  8539. }
  8540. initialized = true;
  8541. }
  8542. }
  8543. }
  8544. }
  8545. private static object InternalSyncObject
  8546. {
  8547. get
  8548. {
  8549. if (s_InternalSyncObject == null)
  8550. {
  8551. object o = new object();
  8552. Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  8553. }
  8554. return s_InternalSyncObject;
  8555. }
  8556. }
  8557. private unsafe static void ThreadPoolFunc()
  8558. {
  8559. try
  8560. {
  8561. for (Boolean fStayInPool = true; fStayInPool; /*empty*/ )
  8562. {
  8563. bool result;
  8564. uint status;
  8565. uint bytesTransferred;
  8566. int completionKey;
  8567. NativeOverlapped* nativeOverlappedPtr;
  8568. // Thread no longer busy.
  8569. Interlocked.Decrement(ref m_numBusyThreads);
  8570. // Read the completion port queue.
  8571. result = UnsafeNclNativeMethods.OSSOCK.GetQueuedCompletionStatus(
  8572. m_hIOCP,
  8573. out bytesTransferred,
  8574. out completionKey,
  8575. out nativeOverlappedPtr,
  8576. c_threadIOCPTimeout);
  8577. // Thread woke up and might have something to do.
  8578. Int32 busyThreads = Interlocked.Increment(ref m_numBusyThreads);
  8579. // Get win32 status only if GQCS returned false.
  8580. status = 0;
  8581. if (!result)
  8582. {
  8583. status = (uint)Marshal.GetLastWin32Error();
  8584. }
  8585. // Handle the case where GQCS itself fails without dequeueing a completion packet.
  8586. if (nativeOverlappedPtr == null)
  8587. {
  8588. // Could be a timeout.
  8589. if (status == (uint)258) // WAIT_TIMEOUT
  8590. {
  8591. // On timeout let thread go away
  8592. fStayInPool = false;
  8593. break; // Leave the loop
  8594. }
  8595. // Some other win32 failure - try GQCS again.
  8596. continue;
  8597. }
  8598. // Heuristic to add another thread to pool.
  8599. if ((busyThreads == m_numThreadsInPool) && (busyThreads < m_maxThreadsAllowed))
  8600. {
  8601. AddThreadToPool();
  8602. }
  8603. // Unpack the native overlapped structure into managed Overlapped object
  8604. Overlapped overlapped = Overlapped.Unpack(nativeOverlappedPtr);
  8605. // See if we have a SocketOperationAsyncResult.
  8606. // Otherwise we have something derived from BaseOverlappedAsyncResult.
  8607. DummyAsyncResult ar = overlapped.AsyncResult as DummyAsyncResult;
  8608. if (ar == null)
  8609. {
  8610. // Is child of BaseOverlappedAsyncResult. Callback is static function in BaseOverlappedAsyncResult.
  8611. // call the callback
  8612. BaseOverlappedAsyncResult.s_IOCallback(status, bytesTransferred, nativeOverlappedPtr);
  8613. }
  8614. else
  8615. {
  8616. // Must be SocAsyncResult. Callback is in the AsyncResult.
  8617. // call the callback
  8618. ar.IOCompletionCallBack(status, bytesTransferred, nativeOverlappedPtr);
  8619. }
  8620. // count the completion
  8621. Interlocked.Increment(ref m_numCallbacks);
  8622. } // for loop
  8623. } // try
  8624. finally
  8625. {
  8626. // Thread is leaving pool.
  8627. Interlocked.Decrement(ref m_numBusyThreads);
  8628. if (Interlocked.Decrement(ref m_numThreadsInPool) == 0)
  8629. {
  8630. // No more threads in the pool.
  8631. }
  8632. }
  8633. }
  8634. private static void AddThreadToPool()
  8635. {
  8636. // suppress flow if not already
  8637. if (!ExecutionContext.IsFlowSuppressed()) ExecutionContext.SuppressFlow();
  8638. // Adding a thread to the thread pool
  8639. Interlocked.Increment(ref m_numThreadsInPool);
  8640. // Track max threads in pool
  8641. InterlockedMax(ref m_maxThreadsEverInPool, m_numThreadsInPool);
  8642. // Thread is busy until it blocks on GQCS
  8643. Interlocked.Increment(ref m_numBusyThreads);
  8644. // Start it up.
  8645. Thread t = new Thread(new ThreadStart(ThreadPoolFunc));
  8646. t.IsBackground = true;
  8647. t.Start();
  8648. }
  8649. private static Int32 InterlockedMax(ref Int32 target, Int32 val)
  8650. {
  8651. Int32 i, j = target;
  8652. do
  8653. {
  8654. i = j;
  8655. j = Interlocked.CompareExchange(ref target, Math.Max(i, val), i);
  8656. } while (i != j);
  8657. return j;
  8658. }
  8659. }
  8660. // internal minimal IAsyncResult class to pass completion routine across native overlapped calls via Overlapped magic internals
  8661. internal class DummyAsyncResult : IAsyncResult {
  8662. IOCompletionCallback m_iocb;
  8663. public DummyAsyncResult() : this(null) {
  8664. }
  8665. public DummyAsyncResult(IOCompletionCallback iocb) {
  8666. m_iocb = iocb;
  8667. }
  8668. public IOCompletionCallback IOCompletionCallBack {
  8669. get { return m_iocb; }
  8670. }
  8671. public object AsyncObject {
  8672. get { return null; }
  8673. }
  8674. public object AsyncState {
  8675. get { return null; }
  8676. }
  8677. public bool IsCompleted {
  8678. get { return false; }
  8679. }
  8680. public WaitHandle AsyncWaitHandle {
  8681. get { return null; }
  8682. }
  8683. public bool CompletedSynchronously {
  8684. get { return false; }
  8685. }
  8686. }
  8687. #endif // SOCKETTHREADPOOL
  8688. #endif // !MONO
  8689. }