1 //------------------------------------------------------------------------------
2 // <copyright file="Socket.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
11 namespace System.Net.Sockets {
12 using System.Collections;
13 using System.Collections.Generic;
14 using System.Diagnostics;
15 using System.Globalization;
18 using System.Net.Configuration;
19 using System.Runtime.InteropServices;
20 using System.Security.Permissions;
21 using System.Threading;
22 using System.Runtime.Versioning;
23 using System.Diagnostics.Contracts;
24 using System.ComponentModel;
27 /// <para>The <see cref='Sockets.Socket'/> class implements the Berkeley sockets
31 public partial class Socket : IDisposable
34 internal const int DefaultCloseTimeout = -1; // don't change for default, otherwise breaking change
36 // AcceptQueue - queued list of accept requests for BeginAccept or async Result for Begin Connect
37 private object m_AcceptQueueOrConnectResult;
39 // the following 8 members represent the state of the socket
40 private SafeCloseSocket m_Handle;
42 // m_RightEndPoint is null if the socket has not been bound. Otherwise, it is any EndPoint of the
43 // correct type (IPEndPoint, etc).
44 internal EndPoint m_RightEndPoint;
45 internal EndPoint m_RemoteEndPoint;
46 // this flags monitor if the socket was ever connected at any time and if it still is.
47 private bool m_IsConnected; // = false;
48 private bool m_IsDisconnected; // = false;
50 // when the socket is created it will be in blocking mode
51 // we'll only be able to Accept or Connect, so we only need
52 // to handle one of these cases at a time
53 private bool willBlock = true; // desired state of the socket for the user
54 private bool willBlockInternal = true; // actual win32 state of the socket
55 private bool isListening = false;
57 // Our internal state doesn't automatically get updated after a non-blocking connect
58 // completes. Keep track of whether we're doing a non-blocking connect, and make sure
59 // to poll for the real state until we're done connecting.
60 private bool m_NonBlockingConnectInProgress;
62 // Keep track of the kind of endpoint used to do a non-blocking connect, so we can set
63 // it to m_RightEndPoint when we discover we're connected.
64 private EndPoint m_NonBlockingConnectRightEndPoint;
66 // These are constants initialized by constructor
67 private AddressFamily addressFamily;
68 private SocketType socketType;
69 private ProtocolType protocolType;
71 // These caches are one degree off of Socket since they're not used in the [....] case/when disabled in config.
72 private CacheSet m_Caches;
74 private class CacheSet
76 internal CallbackClosure ConnectClosureCache;
77 internal CallbackClosure AcceptClosureCache;
78 internal CallbackClosure SendClosureCache;
79 internal CallbackClosure ReceiveClosureCache;
81 internal OverlappedCache SendOverlappedCache;
82 internal OverlappedCache ReceiveOverlappedCache;
86 // Overlapped constants.
88 #if !(FEATURE_PAL && !MONO) || CORIOLIS
89 internal static volatile bool UseOverlappedIO;
91 // Disable the I/O completion port for Rotor
92 internal static volatile bool UseOverlappedIO = true;
93 #endif // !(FEATURE_PAL && !MONO) || CORIOLIS
94 private bool useOverlappedIO;
96 // Bool marked true if the native socket m_Handle was bound to the ThreadPool
97 private bool m_BoundToThreadPool; // = false;
99 // Bool marked true if the native socket option IP_PKTINFO or IPV6_PKTINFO has been set
100 private bool m_ReceivingPacketInformation;
102 // Event used for async Connect/Accept calls
103 private ManualResetEvent m_AsyncEvent;
104 private RegisteredWaitHandle m_RegisteredWait;
105 private AsyncEventBits m_BlockEventBits = AsyncEventBits.FdNone;
107 //These members are to cache permission checks
108 private SocketAddress m_PermittedRemoteAddress;
110 private DynamicWinsockMethods m_DynamicWinsockMethods;
113 private static object s_InternalSyncObject;
115 private int m_CloseTimeout = Socket.DefaultCloseTimeout;
116 private int m_IntCleanedUp; // 0 if not completed >0 otherwise.
117 private const int microcnv = 1000000;
118 private readonly static int protocolInformationSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
121 internal static volatile bool s_SupportsIPv4;
122 internal static volatile bool s_SupportsIPv6;
123 internal static volatile bool s_OSSupportsIPv6;
124 internal static volatile bool s_Initialized;
125 private static volatile WaitOrTimerCallback s_RegisteredWaitCallback;
126 private static volatile bool s_LoggingEnabled;
127 #if !FEATURE_PAL // perfcounter
128 internal static volatile bool s_PerfCountersEnabled;
131 //************* constructors *************************
133 //------------------------------------
135 // Creates a Dual Mode socket for working with both IPv4 and IPv6
136 public Socket(SocketType socketType, ProtocolType protocolType)
137 : this(AddressFamily.InterNetworkV6, socketType, protocolType) {
143 /// Initializes a new instance of the <see cref='Sockets.Socket'/> class.
146 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) {
147 s_LoggingEnabled = Logging.On;
148 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
153 m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
155 m_Handle = SafeCloseSocket.CreateWSASocket(
161 if (m_Handle.IsInvalid) {
163 // failed to create the win32 socket, throw
165 throw new SocketException();
168 this.addressFamily = addressFamily;
169 this.socketType = socketType;
170 this.protocolType = protocolType;
172 IPProtectionLevel defaultProtectionLevel = SettingsSectionInternal.Section.IPProtectionLevel;
173 if (defaultProtectionLevel != IPProtectionLevel.Unspecified) {
174 SetIPProtectionLevel(defaultProtectionLevel);
181 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
185 public Socket(SocketInformation socketInformation) {
186 s_LoggingEnabled = Logging.On;
187 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
189 ExceptionHelper.UnrestrictedSocketPermission.Demand();
192 if(socketInformation.ProtocolInformation == null || socketInformation.ProtocolInformation.Length < protocolInformationSize){
193 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation.ProtocolInformation");
197 fixed(byte * pinnedBuffer = socketInformation.ProtocolInformation){
198 m_Handle = SafeCloseSocket.CreateWSASocket(pinnedBuffer);
200 UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO protocolInfo = (UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO)Marshal.PtrToStructure((IntPtr)pinnedBuffer, typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
201 addressFamily = protocolInfo.iAddressFamily;
202 socketType = (SocketType)protocolInfo.iSocketType;
203 protocolType = (ProtocolType)protocolInfo.iProtocol;
207 if (m_Handle.IsInvalid) {
208 SocketException e = new SocketException();
209 if(e.ErrorCode == (int)SocketError.InvalidArgument){
210 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation");
217 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
218 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
221 m_IsConnected = socketInformation.IsConnected;
222 willBlock = !socketInformation.IsNonBlocking;
223 InternalSetBlocking(willBlock);
224 isListening = socketInformation.IsListening;
225 UseOnlyOverlappedIO = socketInformation.UseOnlyOverlappedIO;
228 //are we bound? if so, what's the local endpoint?
230 if (socketInformation.RemoteEndPoint != null) {
231 m_RightEndPoint = socketInformation.RemoteEndPoint;
232 m_RemoteEndPoint = socketInformation.RemoteEndPoint;
236 if (addressFamily == AddressFamily.InterNetwork ) {
239 else if(addressFamily == AddressFamily.InterNetworkV6) {
240 ep = IPEndPoint.IPv6Any;
243 SocketAddress socketAddress = ep.Serialize();
244 SocketError errorCode;
247 errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
249 socketAddress.m_Buffer,
250 ref socketAddress.m_Size);
252 catch (ObjectDisposedException)
254 errorCode = SocketError.NotSocket;
257 if (errorCode == SocketError.Success) {
260 m_RightEndPoint = ep.Create(socketAddress);
267 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
273 /// Called by the class to create a socket to accept an
274 /// incoming request.
277 private Socket(SafeCloseSocket fd) {
278 s_LoggingEnabled = Logging.On;
279 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", null);
281 // ExceptionHelper.UnmanagedPermission.Demand();
289 // this should never happen, let's check anyway
291 if (fd == null || fd.IsInvalid) {
292 throw new ArgumentException(SR.GetString(SR.net_InvalidSocketHandle));
297 addressFamily = Sockets.AddressFamily.Unknown;
298 socketType = Sockets.SocketType.Unknown;
299 protocolType = Sockets.ProtocolType.Unknown;
300 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
305 //************* properties *************************
309 /// <para>Indicates whether IPv4 support is available and enabled on this machine.</para>
311 [Obsolete("SupportsIPv4 is obsoleted for this type, please use OSSupportsIPv4 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
312 public static bool SupportsIPv4 {
315 return s_SupportsIPv4;
319 // Renamed to be consistent with OSSupportsIPv6
320 public static bool OSSupportsIPv4 {
323 return s_SupportsIPv4;
328 /// <para>Indicates whether IPv6 support is available and enabled on this machine.</para>
331 [Obsolete("SupportsIPv6 is obsoleted for this type, please use OSSupportsIPv6 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
332 public static bool SupportsIPv6 {
335 return s_SupportsIPv6;
339 internal static bool LegacySupportsIPv6 {
342 return s_SupportsIPv6;
346 public static bool OSSupportsIPv6 {
349 return s_OSSupportsIPv6;
356 /// Gets the amount of data pending in the network's input buffer that can be
357 /// read from the socket.
360 public int Available {
363 throw new ObjectDisposedException(this.GetType().FullName);
368 // This may throw ObjectDisposedException.
369 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
371 IoctlSocketConstants.FIONREAD,
374 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Available_get() UnsafeNclNativeMethods.OSSOCK.ioctlsocket returns errorCode:" + errorCode);
377 // if the native call fails we'll throw a SocketException
379 if (errorCode==SocketError.SocketError) {
381 // update our internal state after this socket error and throw
383 SocketException socketException = new SocketException();
384 UpdateStatusAfterSocketError(socketException);
385 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Available", socketException);
386 throw socketException;
399 /// Gets the local end point.
402 public EndPoint LocalEndPoint {
405 throw new ObjectDisposedException(this.GetType().FullName);
408 if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
410 // update the state if we've become connected after a non-blocking connect
411 m_IsConnected = true;
412 m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
413 m_NonBlockingConnectInProgress = false;
416 if (m_RightEndPoint == null) {
420 SocketAddress socketAddress = m_RightEndPoint.Serialize();
422 // This may throw ObjectDisposedException.
423 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
425 socketAddress.m_Buffer,
426 ref socketAddress.m_Size);
428 if (errorCode!=SocketError.Success) {
430 // update our internal state after this socket error and throw
432 SocketException socketException = new SocketException();
433 UpdateStatusAfterSocketError(socketException);
434 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "LocalEndPoint", socketException);
435 throw socketException;
438 return m_RightEndPoint.Create(socketAddress);
444 /// Gets the remote end point
447 public EndPoint RemoteEndPoint {
450 throw new ObjectDisposedException(this.GetType().FullName);
453 if (m_RemoteEndPoint==null) {
455 if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
457 // update the state if we've become connected after a non-blocking connect
458 m_IsConnected = true;
459 m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
460 m_NonBlockingConnectInProgress = false;
463 if (m_RightEndPoint==null) {
467 SocketAddress socketAddress = m_RightEndPoint.Serialize();
469 // This may throw ObjectDisposedException.
470 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getpeername(
472 socketAddress.m_Buffer,
473 ref socketAddress.m_Size);
475 if (errorCode!=SocketError.Success) {
477 // update our internal state after this socket error and throw
479 SocketException socketException = new SocketException();
480 UpdateStatusAfterSocketError(socketException);
481 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "RemoteEndPoint", socketException);
482 throw socketException;
486 m_RemoteEndPoint = m_RightEndPoint.Create(socketAddress);
492 return m_RemoteEndPoint;
499 /// Gets the operating system m_Handle for the socket.
500 ///YUKON: should we cut this method off, who are the users?
503 public IntPtr Handle {
506 ExceptionHelper.UnmanagedPermission.Demand();
508 return m_Handle.DangerousGetHandle();
512 internal SafeCloseSocket SafeHandle {
519 // Non-blocking I/O control
522 /// Gets and sets the blocking mode of a socket.
525 public bool Blocking {
528 // return the user's desired blocking behaviour (not the actual win32 state)
534 throw new ObjectDisposedException(this.GetType().FullName);
537 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::set_Blocking() value:" + value.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
541 SocketError errorCode = InternalSetBlocking(value, out current);
543 if (errorCode!=SocketError.Success) {
545 // update our internal state after this socket error and throw
546 SocketException socketException = new SocketException(errorCode);
547 UpdateStatusAfterSocketError(socketException);
548 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Blocking", socketException);
549 throw socketException;
553 // win32 call succeeded, update desired state
560 public bool UseOnlyOverlappedIO{
563 // return the user's desired blocking behaviour (not the actual win32 state)
565 return useOverlappedIO;
570 if (m_BoundToThreadPool) {
571 throw new InvalidOperationException(SR.GetString(SR.net_io_completionportwasbound));
575 useOverlappedIO = value;
582 /// Gets the connection state of the Socket. This property will return the latest
583 /// known state of the Socket. When it returns false, the Socket was either never connected
584 /// or it is not connected anymore. When it returns true, though, there's no guarantee that the Socket
585 /// is still connected, but only that it was connected at the time of the last IO operation.
588 public bool Connected {
590 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connected() m_IsConnected:"+m_IsConnected);
592 if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
594 // update the state if we've become connected after a non-blocking connect
595 m_IsConnected = true;
596 m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
597 m_NonBlockingConnectInProgress = false;
600 return m_IsConnected;
607 /// Gets the socket's address family.
610 public AddressFamily AddressFamily {
612 return addressFamily;
618 /// Gets the socket's socketType.
621 public SocketType SocketType {
629 /// Gets the socket's protocol socketType.
632 public ProtocolType ProtocolType {
641 return (m_RightEndPoint != null);
646 public bool ExclusiveAddressUse{
648 return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse) != 0 ? true : false;
652 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotbebound));
654 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
659 public int ReceiveBufferSize {
661 return (int)GetSocketOption(SocketOptionLevel.Socket,
662 SocketOptionName.ReceiveBuffer);
666 throw new ArgumentOutOfRangeException("value");
669 SetSocketOption(SocketOptionLevel.Socket,
670 SocketOptionName.ReceiveBuffer, value);
674 public int SendBufferSize {
676 return (int)GetSocketOption(SocketOptionLevel.Socket,
677 SocketOptionName.SendBuffer);
682 throw new ArgumentOutOfRangeException("value");
685 SetSocketOption(SocketOptionLevel.Socket,
686 SocketOptionName.SendBuffer, value);
690 public int ReceiveTimeout {
692 return (int)GetSocketOption(SocketOptionLevel.Socket,
693 SocketOptionName.ReceiveTimeout);
697 throw new ArgumentOutOfRangeException("value");
703 SetSocketOption(SocketOptionLevel.Socket,
704 SocketOptionName.ReceiveTimeout, value);
708 public int SendTimeout {
710 return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
715 throw new ArgumentOutOfRangeException("value");
721 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
725 public LingerOption LingerState {
727 return (LingerOption)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
730 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value);
735 public bool NoDelay {
737 return (int)GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) != 0 ? true : false;
740 SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
747 if (addressFamily == AddressFamily.InterNetwork) {
748 return (short)(int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
750 else if (addressFamily == AddressFamily.InterNetworkV6) {
751 return (short)(int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive);
754 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
760 // valid values are from 0 to 255 since Ttl is really just a byte value on the wire
761 if (value < 0 || value > 255) {
762 throw new ArgumentOutOfRangeException("value");
765 if (addressFamily == AddressFamily.InterNetwork) {
766 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
769 else if (addressFamily == AddressFamily.InterNetworkV6) {
770 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive, value);
773 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
778 public bool DontFragment{
780 if (addressFamily == AddressFamily.InterNetwork) {
781 return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment) != 0 ? true : false;
784 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
789 if (addressFamily == AddressFamily.InterNetwork) {
790 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
793 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
799 public bool MulticastLoopback{
801 if (addressFamily == AddressFamily.InterNetwork) {
802 return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback) != 0 ? true : false;
804 else if (addressFamily == AddressFamily.InterNetworkV6) {
805 return (int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback) != 0 ? true : false;
808 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
813 if (addressFamily == AddressFamily.InterNetwork) {
814 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
817 else if (addressFamily == AddressFamily.InterNetworkV6) {
818 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
821 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
826 public bool EnableBroadcast{
828 return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast) != 0 ? true : false;
831 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
836 public bool DualMode {
838 if (AddressFamily != AddressFamily.InterNetworkV6) {
839 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
841 return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
844 if (AddressFamily != AddressFamily.InterNetworkV6) {
845 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
847 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
851 private bool IsDualMode {
853 return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
857 internal bool CanTryAddressFamily(AddressFamily family) {
858 return (family == addressFamily) || (family == AddressFamily.InterNetwork && IsDualMode);
862 //************* public methods *************************
869 /// <para>Associates a socket with an end point.</para>
871 public void Bind(EndPoint localEP) {
873 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Bind", localEP);
876 throw new ObjectDisposedException(this.GetType().FullName);
879 // parameter validation
882 throw new ArgumentNullException("localEP");
885 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() localEP:" + localEP.ToString());
887 EndPoint endPointSnapshot = localEP;
888 IPEndPoint ipSnapshot = localEP as IPEndPoint;
891 // for now security is implemented only on IPEndPoint
892 // If EndPoint is of other type - unmanaged code permisison is demanded
894 if (ipSnapshot != null)
896 // Take a snapshot that will make it immutable and not derived.
897 ipSnapshot = ipSnapshot.Snapshot();
898 // DualMode: Do the security check on the users IPv4 address, but map to IPv6 before binding.
899 endPointSnapshot = RemapIPEndPoint(ipSnapshot);
902 // create the permissions the user would need for the call
904 SocketPermission socketPermission
905 = new SocketPermission(
906 NetworkAccess.Accept,
908 ipSnapshot.Address.ToString(),
913 socketPermission.Demand();
915 // Here the permission check has succeded.
916 // NB: if local port is 0, then winsock will assign some>1024,
917 // so assuming that this is safe. We will not check the
918 // NetworkAccess.Accept permissions in Receive.
927 ExceptionHelper.UnmanagedPermission.Demand();
931 // ask the EndPoint to generate a SocketAddress that we
932 // can pass down to winsock
934 SocketAddress socketAddress = CallSerializeCheckDnsEndPoint(endPointSnapshot);
935 DoBind(endPointSnapshot, socketAddress);
936 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Bind", "");
939 internal void InternalBind(EndPoint localEP)
941 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "InternalBind", localEP);
945 throw new ObjectDisposedException(GetType().FullName);
948 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalBind() localEP:" + localEP.ToString());
949 GlobalLog.Assert(!(localEP is DnsEndPoint), "Calling InternalBind with a DnsEndPoint, about to get NotImplementedException");
952 // ask the EndPoint to generate a SocketAddress that we
953 // can pass down to winsock
955 EndPoint endPointSnapshot = localEP;
956 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
957 DoBind(endPointSnapshot, socketAddress);
959 if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "InternalBind", "");
962 private void DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
964 // Mitigation for Blue Screen of Death (Win7, maybe others)
965 IPEndPoint ipEndPoint = endPointSnapshot as IPEndPoint;
966 if (!OSSupportsIPv4 && ipEndPoint != null && ipEndPoint.Address.IsIPv4MappedToIPv6)
968 SocketException socketException = new SocketException(SocketError.InvalidArgument);
969 UpdateStatusAfterSocketError(socketException);
970 if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
971 throw socketException;
974 // This may throw ObjectDisposedException.
975 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.bind(
977 socketAddress.m_Buffer,
978 socketAddress.m_Size);
983 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.bind returns errorCode:" + errorCode);
985 catch (ObjectDisposedException) { }
989 // if the native call fails we'll throw a SocketException
991 if (errorCode != SocketError.Success)
994 // update our internal state after this socket error and throw
996 SocketException socketException = new SocketException();
997 UpdateStatusAfterSocketError(socketException);
998 if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
999 throw socketException;
1002 if (m_RightEndPoint == null)
1005 // save a copy of the EndPoint so we can use it for Create()
1007 m_RightEndPoint = endPointSnapshot;
1013 /// <para>Establishes a connection to a remote system.</para>
1015 public void Connect(EndPoint remoteEP) {
1017 throw new ObjectDisposedException(this.GetType().FullName);
1020 // parameter validation
1022 if (remoteEP==null) {
1023 throw new ArgumentNullException("remoteEP");
1026 if(m_IsDisconnected){
1027 throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedConnect));
1032 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
1035 ValidateBlockingMode();
1036 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connect() DST:" + ValidationHelper.ToString(remoteEP));
1038 DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
1041 if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily))
1043 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
1046 Connect(dnsEP.Host, dnsEP.Port);
1050 //This will check the permissions for connect
1051 EndPoint endPointSnapshot = remoteEP;
1052 SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true);
1056 m_NonBlockingConnectRightEndPoint = endPointSnapshot;
1057 m_NonBlockingConnectInProgress = true;
1060 DoConnect(endPointSnapshot, socketAddress);
1064 public void Connect(IPAddress address, int port){
1066 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", address);
1069 throw new ObjectDisposedException(this.GetType().FullName);
1071 //if address family isn't the socket address family throw
1072 if (address==null) {
1073 throw new ArgumentNullException("address");
1076 if (!ValidationHelper.ValidateTcpPort(port)) {
1077 throw new ArgumentOutOfRangeException("port");
1079 if (!CanTryAddressFamily(address.AddressFamily)) {
1080 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
1083 IPEndPoint remoteEP = new IPEndPoint(address, port);
1085 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
1089 public void Connect(string host, int port){
1090 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", host);
1093 throw new ObjectDisposedException(this.GetType().FullName);
1096 throw new ArgumentNullException("host");
1098 if (!ValidationHelper.ValidateTcpPort(port)){
1099 throw new ArgumentOutOfRangeException("port");
1101 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
1102 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
1105 IPAddress[] addresses = Dns.GetHostAddresses(host);
1106 Connect(addresses,port);
1107 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
1110 public void Connect(IPAddress[] addresses, int port){
1111 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", addresses);
1114 throw new ObjectDisposedException(this.GetType().FullName);
1116 if (addresses==null) {
1117 throw new ArgumentNullException("addresses");
1119 if (addresses.Length == 0) {
1120 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_ipaddress_length), "addresses");
1122 if (!ValidationHelper.ValidateTcpPort(port)) {
1123 throw new ArgumentOutOfRangeException("port");
1125 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
1126 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
1129 Exception lastex = null;
1130 foreach ( IPAddress address in addresses ) {
1131 if (CanTryAddressFamily(address.AddressFamily)) {
1134 Connect(new IPEndPoint(address,port) );
1138 catch ( Exception ex )
1140 if (NclUtilities.IsFatal(ex)) throw;
1146 if ( lastex != null )
1149 //if we're not connected, then we didn't get a valid ipaddress in the list
1151 throw new ArgumentException(SR.GetString(SR.net_invalidAddressList), "addresses");
1154 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
1160 /// Forces a socket connection to close.
1165 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
1166 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Close", null);
1167 ((IDisposable)this).Dispose();
1168 if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "Close", null);
1171 public void Close(int timeout)
1175 throw new ArgumentOutOfRangeException("timeout");
1177 m_CloseTimeout = timeout;
1178 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
1179 ((IDisposable)this).Dispose();
1185 /// Places a socket in a listening state.
1188 public void Listen(int backlog) {
1189 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Listen", backlog);
1191 throw new ObjectDisposedException(this.GetType().FullName);
1194 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() backlog:" + backlog.ToString());
1196 // No access permissions are necessary here because
1197 // the verification is done for Bind
1199 // This may throw ObjectDisposedException.
1200 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.listen(
1207 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.listen returns errorCode:" + errorCode);
1209 catch (ObjectDisposedException) { }
1213 // if the native call fails we'll throw a SocketException
1215 if (errorCode!=SocketError.Success) {
1217 // update our internal state after this socket error and throw
1219 SocketException socketException = new SocketException();
1220 UpdateStatusAfterSocketError(socketException);
1221 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Listen", socketException);
1222 throw socketException;
1225 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Listen", "");
1230 /// Creates a new <see cref='Sockets.Socket'/> instance to handle an incoming
1234 public Socket Accept() {
1235 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Accept", "");
1238 // parameter validation
1242 throw new ObjectDisposedException(this.GetType().FullName);
1245 if (m_RightEndPoint==null) {
1246 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
1250 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
1253 if(m_IsDisconnected){
1254 throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedAccept));
1257 ValidateBlockingMode();
1258 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Accept() SRC:" + ValidationHelper.ToString(LocalEndPoint));
1260 SocketAddress socketAddress = m_RightEndPoint.Serialize();
1262 // This may throw ObjectDisposedException.
1263 SafeCloseSocket acceptedSocketHandle = SafeCloseSocket.Accept(
1265 socketAddress.m_Buffer,
1266 ref socketAddress.m_Size);
1269 // if the native call fails we'll throw a SocketException
1271 if (acceptedSocketHandle.IsInvalid) {
1273 // update our internal state after this socket error and throw
1275 SocketException socketException = new SocketException();
1276 UpdateStatusAfterSocketError(socketException);
1277 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Accept", socketException);
1278 throw socketException;
1281 Socket socket = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress), false);
1282 if (s_LoggingEnabled) {
1283 Logging.PrintInfo(Logging.Sockets, socket, SR.GetString(SR.net_log_socket_accepted, socket.RemoteEndPoint, socket.LocalEndPoint));
1284 Logging.Exit(Logging.Sockets, this, "Accept", socket);
1291 /// <para>Sends a data buffer to a connected socket.</para>
1293 public int Send(byte[] buffer, int size, SocketFlags socketFlags) {
1294 return Send(buffer, 0, size, socketFlags);
1297 /// <para>[To be supplied.]</para>
1299 public int Send(byte[] buffer, SocketFlags socketFlags) {
1300 return Send(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags);
1303 /// <para>[To be supplied.]</para>
1305 public int Send(byte[] buffer) {
1306 return Send(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None);
1312 /// <para>[To be supplied.]</para>
1314 public int Send(IList<ArraySegment<byte>> buffers) {
1315 return Send(buffers,SocketFlags.None);
1319 /// <para>[To be supplied.]</para>
1321 public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) {
1322 SocketError errorCode;
1323 int bytesTransferred = Send(buffers, socketFlags, out errorCode);
1324 if(errorCode != SocketError.Success){
1325 throw new SocketException(errorCode);
1327 return bytesTransferred;
1331 public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode) {
1332 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Send", "");
1334 throw new ObjectDisposedException(this.GetType().FullName);
1336 if (buffers==null) {
1337 throw new ArgumentNullException("buffers");
1340 if(buffers.Count == 0){
1341 throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
1344 ValidateBlockingMode();
1345 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
1347 //make sure we don't let the app mess up the buffer array enough to cause
1350 errorCode = SocketError.Success;
1351 int count = buffers.Count;
1352 WSABuffer[] WSABuffers = new WSABuffer[count];
1353 GCHandle[] objectsToPin = null;
1354 int bytesTransferred;
1357 objectsToPin = new GCHandle[count];
1358 for (int i = 0; i < count; ++i)
1360 ArraySegment<byte> buffer = buffers[i];
1361 ValidationHelper.ValidateSegment(buffer);
1362 objectsToPin[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
1363 WSABuffers[i].Length = buffer.Count;
1364 WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset);
1367 // This may throw ObjectDisposedException.
1368 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend_Blocking(
1369 m_Handle.DangerousGetHandle(),
1372 out bytesTransferred,
1374 SafeNativeOverlapped.Zero,
1377 if ((SocketError)errorCode==SocketError.SocketError) {
1378 errorCode = (SocketError)Marshal.GetLastWin32Error();
1384 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.send returns errorCode:" + errorCode + " bytesTransferred:" + bytesTransferred);
1386 catch (ObjectDisposedException) { }
1390 if (objectsToPin != null)
1391 for (int i = 0; i < objectsToPin.Length; ++i)
1392 if (objectsToPin[i].IsAllocated)
1393 objectsToPin[i].Free();
1396 if (errorCode != SocketError.Success) {
1398 // update our internal state after this socket error and throw
1400 UpdateStatusAfterSocketError(errorCode);
1401 if(s_LoggingEnabled){
1402 Logging.Exception(Logging.Sockets, this, "Send", new SocketException(errorCode));
1403 Logging.Exit(Logging.Sockets, this, "Send", 0);
1408 #if !FEATURE_PAL // perfcounter
1409 if (s_PerfCountersEnabled)
1411 if (bytesTransferred>0) {
1412 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
1413 if (Transport==TransportType.Udp) {
1414 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
1419 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Send", bytesTransferred);
1420 return bytesTransferred;
1425 /// <para>Sends a file to
1426 /// a connected socket.</para>
1428 [ResourceExposure(ResourceScope.Machine)]
1429 [ResourceConsumption(ResourceScope.Machine)]
1430 public void SendFile(string fileName)
1432 SendFile(fileName,null,null,TransmitFileOptions.UseDefaultWorkerThread);
1437 /// <para>Sends a file to
1438 /// a connected socket.</para>
1440 [ResourceExposure(ResourceScope.Machine)]
1441 [ResourceConsumption(ResourceScope.Machine)]
1442 public void SendFile(string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags) {
1443 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "SendFile", "");
1446 throw new ObjectDisposedException(this.GetType().FullName);
1450 throw new NotSupportedException(SR.GetString(SR.net_notconnected));
1453 ValidateBlockingMode();
1454 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " fileName:" + fileName);
1456 TransmitFileOverlappedAsyncResult asyncResult = new TransmitFileOverlappedAsyncResult(this);
1458 FileStream fileStream = null;
1459 if (fileName != null && fileName.Length>0) {
1460 fileStream = new FileStream(fileName,FileMode.Open,FileAccess.Read,FileShare.Read);
1463 SafeHandle fileHandle = null;
1465 if (fileStream != null) {
1466 ExceptionHelper.UnmanagedPermission.Assert();
1468 fileHandle = fileStream.SafeFileHandle;
1471 SecurityPermission.RevertAssert();
1475 SocketError errorCode = SocketError.Success;
1477 asyncResult.SetUnmanagedStructures(preBuffer, postBuffer, fileStream, 0, true);
1479 // This can throw ObjectDisposedException.
1480 if (fileHandle != null ?
1481 !UnsafeNclNativeMethods.OSSOCK.TransmitFile_Blocking(m_Handle.DangerousGetHandle(), fileHandle, 0, 0, SafeNativeOverlapped.Zero, asyncResult.TransmitFileBuffers, flags) :
1482 !UnsafeNclNativeMethods.OSSOCK.TransmitFile_Blocking2(m_Handle.DangerousGetHandle(), IntPtr.Zero, 0, 0, SafeNativeOverlapped.Zero, asyncResult.TransmitFileBuffers, flags))
1484 errorCode = (SocketError) Marshal.GetLastWin32Error();
1488 asyncResult.SyncReleaseUnmanagedStructures();
1494 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.TransmitFile returns errorCode:" + errorCode);
1496 catch (ObjectDisposedException) { }
1500 // if the native call fails we'll throw a SocketException
1502 if (errorCode!=SocketError.Success) {
1504 // update our internal state after this socket error and throw
1506 SocketException socketException = new SocketException(errorCode);
1507 UpdateStatusAfterSocketError(socketException);
1508 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SendFile", socketException);
1509 throw socketException;
1512 if ((asyncResult.Flags & (TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket) )!=0) {
1513 SetToDisconnected();
1514 m_RemoteEndPoint = null;
1517 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "SendFile", errorCode);
1521 #endif // !FEATURE_PAL
1525 /// <para>Sends data to
1526 /// a connected socket, starting at the indicated location in the
1531 public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) {
1532 SocketError errorCode;
1533 int bytesTransferred = Send(buffer, offset, size, socketFlags, out errorCode);
1534 if(errorCode != SocketError.Success){
1535 throw new SocketException(errorCode);
1537 return bytesTransferred;
1541 public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) {
1542 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Send", "");
1545 throw new ObjectDisposedException(this.GetType().FullName);
1548 // parameter validation
1551 throw new ArgumentNullException("buffer");
1553 if (offset<0 || offset>buffer.Length) {
1554 throw new ArgumentOutOfRangeException("offset");
1556 if (size<0 || size>buffer.Length-offset) {
1557 throw new ArgumentOutOfRangeException("size");
1561 errorCode = SocketError.Success;
1562 ValidateBlockingMode();
1563 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size);
1565 // This can throw ObjectDisposedException.
1566 int bytesTransferred;
1568 if (buffer.Length == 0)
1569 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.send(m_Handle.DangerousGetHandle(), null, 0, socketFlags);
1571 fixed (byte* pinnedBuffer = buffer) {
1572 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.send(
1573 m_Handle.DangerousGetHandle(),
1574 pinnedBuffer+offset,
1582 // if the native call fails we'll throw a SocketException
1584 if ((SocketError)bytesTransferred==SocketError.SocketError) {
1586 // update our internal state after this socket error and throw
1588 errorCode = (SocketError)Marshal.GetLastWin32Error();
1589 UpdateStatusAfterSocketError(errorCode);
1590 if(s_LoggingEnabled){
1591 Logging.Exception(Logging.Sockets, this, "Send", new SocketException(errorCode));
1592 Logging.Exit(Logging.Sockets, this, "Send", 0);
1597 #if !FEATURE_PAL // perfcounter
1598 if (s_PerfCountersEnabled)
1600 if (bytesTransferred>0) {
1601 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
1602 if (Transport==TransportType.Udp) {
1603 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
1607 #endif //!FEATURE_PAL
1609 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() UnsafeNclNativeMethods.OSSOCK.send returns:" + bytesTransferred.ToString());
1610 GlobalLog.Dump(buffer, offset, bytesTransferred);
1611 if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "Send", buffer, offset, size);
1612 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Send", bytesTransferred);
1613 return bytesTransferred;
1618 /// <para>Sends data to a specific end point, starting at the indicated location in the
1621 public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP) {
1622 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "SendTo", "");
1624 throw new ObjectDisposedException(this.GetType().FullName);
1627 // parameter validation
1630 throw new ArgumentNullException("buffer");
1632 if (remoteEP==null) {
1633 throw new ArgumentNullException("remoteEP");
1635 if (offset<0 || offset>buffer.Length) {
1636 throw new ArgumentOutOfRangeException("offset");
1638 if (size<0 || size>buffer.Length-offset) {
1639 throw new ArgumentOutOfRangeException("size");
1642 ValidateBlockingMode();
1643 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendTo() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " size:" + size + " remoteEP:" + ValidationHelper.ToString(remoteEP));
1645 //That will check ConnectPermission for remoteEP
1646 EndPoint endPointSnapshot = remoteEP;
1647 SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, false);
1649 // This can throw ObjectDisposedException.
1650 int bytesTransferred;
1653 if (buffer.Length == 0)
1655 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.sendto(
1656 m_Handle.DangerousGetHandle(),
1660 socketAddress.m_Buffer,
1661 socketAddress.m_Size);
1665 fixed (byte* pinnedBuffer = buffer)
1667 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.sendto(
1668 m_Handle.DangerousGetHandle(),
1669 pinnedBuffer+offset,
1672 socketAddress.m_Buffer,
1673 socketAddress.m_Size);
1679 // if the native call fails we'll throw a SocketException
1681 if ((SocketError)bytesTransferred==SocketError.SocketError) {
1683 // update our internal state after this socket error and throw
1685 SocketException socketException = new SocketException();
1686 UpdateStatusAfterSocketError(socketException);
1687 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SendTo", socketException);
1688 throw socketException;
1691 if (m_RightEndPoint==null) {
1693 // save a copy of the EndPoint so we can use it for Create()
1695 m_RightEndPoint = endPointSnapshot;
1698 #if !FEATURE_PAL // perfcounter
1699 if (s_PerfCountersEnabled)
1701 if (bytesTransferred>0) {
1702 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
1703 if (Transport==TransportType.Udp) {
1704 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
1708 #endif //!FEATURE_PAL
1710 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendTo() returning bytesTransferred:" + bytesTransferred.ToString());
1711 GlobalLog.Dump(buffer, offset, bytesTransferred);
1712 if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "SendTo", buffer, offset, size);
1713 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "SendTo", bytesTransferred);
1714 return bytesTransferred;
1719 /// <para>Sends data to a specific end point, starting at the indicated location in the data.</para>
1721 public int SendTo(byte[] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP) {
1722 return SendTo(buffer, 0, size, socketFlags, remoteEP);
1726 /// <para>[To be supplied.]</para>
1728 public int SendTo(byte[] buffer, SocketFlags socketFlags, EndPoint remoteEP) {
1729 return SendTo(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags, remoteEP);
1733 /// <para>[To be supplied.]</para>
1735 public int SendTo(byte[] buffer, EndPoint remoteEP) {
1736 return SendTo(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None, remoteEP);
1741 /// <para>Receives data from a connected socket.</para>
1743 public int Receive(byte[] buffer, int size, SocketFlags socketFlags) {
1744 return Receive(buffer, 0, size, socketFlags);
1747 /// <para>[To be supplied.]</para>
1749 public int Receive(byte[] buffer, SocketFlags socketFlags) {
1750 return Receive(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags);
1753 /// <para>[To be supplied.]</para>
1755 public int Receive(byte[] buffer) {
1756 return Receive(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None);
1760 /// <para>Receives data from a connected socket into a specific location of the receive
1764 public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags) {
1765 SocketError errorCode;
1766 int bytesTransferred = Receive(buffer, offset, size, socketFlags, out errorCode);
1767 if(errorCode != SocketError.Success){
1768 throw new SocketException(errorCode);
1770 return bytesTransferred;
1774 public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) {
1775 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Receive", "");
1777 throw new ObjectDisposedException(this.GetType().FullName);
1780 // parameter validation
1784 throw new ArgumentNullException("buffer");
1786 if (offset<0 || offset>buffer.Length) {
1787 throw new ArgumentOutOfRangeException("offset");
1789 if (size<0 || size>buffer.Length-offset) {
1790 throw new ArgumentOutOfRangeException("size");
1794 ValidateBlockingMode();
1795 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size);
1797 // This can throw ObjectDisposedException.
1798 int bytesTransferred;
1799 errorCode = SocketError.Success;
1801 if (buffer.Length == 0)
1803 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), null, 0, socketFlags);
1805 else fixed (byte* pinnedBuffer = buffer) {
1806 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), pinnedBuffer+offset, size, socketFlags);
1810 if ((SocketError)bytesTransferred==SocketError.SocketError) {
1812 // update our internal state after this socket error and throw
1814 errorCode = (SocketError)Marshal.GetLastWin32Error();
1815 UpdateStatusAfterSocketError(errorCode);
1816 if(s_LoggingEnabled){
1817 Logging.Exception(Logging.Sockets, this, "Receive", new SocketException(errorCode));
1818 Logging.Exit(Logging.Sockets, this, "Receive", 0);
1823 #if !FEATURE_PAL // perfcounter
1824 if (s_PerfCountersEnabled)
1826 bool peek = ((int)socketFlags & (int)SocketFlags.Peek)!=0;
1828 if (bytesTransferred>0 && !peek) {
1829 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
1830 if (Transport==TransportType.Udp) {
1831 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
1835 #endif //!FEATURE_PAL
1840 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred);
1842 catch (ObjectDisposedException) { }
1844 GlobalLog.Dump(buffer, offset, bytesTransferred);
1846 if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "Receive", buffer, offset, bytesTransferred);
1847 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Receive", bytesTransferred);
1849 return bytesTransferred;
1853 public int Receive(IList<ArraySegment<byte>> buffers) {
1854 return Receive(buffers,SocketFlags.None);
1858 public int Receive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) {
1859 SocketError errorCode;
1860 int bytesTransferred = Receive(buffers, socketFlags, out errorCode);
1861 if(errorCode != SocketError.Success){
1862 throw new SocketException(errorCode);
1864 return bytesTransferred;
1868 public int Receive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode) {
1869 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Receive", "");
1871 throw new ObjectDisposedException(this.GetType().FullName);
1874 if (buffers==null) {
1875 throw new ArgumentNullException("buffers");
1878 if(buffers.Count == 0){
1879 throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
1883 ValidateBlockingMode();
1884 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
1886 //make sure we don't let the app mess up the buffer array enough to cause
1888 int count = buffers.Count;
1889 WSABuffer[] WSABuffers = new WSABuffer[count];
1890 GCHandle[] objectsToPin = null;
1891 int bytesTransferred;
1892 errorCode = SocketError.Success;
1895 objectsToPin = new GCHandle[count];
1896 for (int i = 0; i < count; ++i)
1898 ArraySegment<byte> buffer = buffers[i];
1899 ValidationHelper.ValidateSegment(buffer);
1900 objectsToPin[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
1901 WSABuffers[i].Length = buffer.Count;
1902 WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset);
1905 // This can throw ObjectDisposedException.
1906 errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv_Blocking(
1907 m_Handle.DangerousGetHandle(),
1910 out bytesTransferred,
1912 SafeNativeOverlapped.Zero,
1915 if ((SocketError)errorCode==SocketError.SocketError) {
1916 errorCode = (SocketError)Marshal.GetLastWin32Error();
1921 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.send returns errorCode:" + errorCode + " bytesTransferred:" + bytesTransferred);
1923 catch (ObjectDisposedException) { }
1927 if (objectsToPin != null)
1928 for (int i = 0; i < objectsToPin.Length; ++i)
1929 if (objectsToPin[i].IsAllocated)
1930 objectsToPin[i].Free();
1933 if (errorCode != SocketError.Success) {
1935 // update our internal state after this socket error and throw
1937 UpdateStatusAfterSocketError(errorCode);
1938 if(s_LoggingEnabled){
1939 Logging.Exception(Logging.Sockets, this, "Receive", new SocketException(errorCode));
1940 Logging.Exit(Logging.Sockets, this, "Receive", 0);
1947 #if !FEATURE_PAL // perfcounter
1948 if (s_PerfCountersEnabled)
1950 bool peek = ((int)socketFlags & (int)SocketFlags.Peek)!=0;
1952 if (bytesTransferred>0 && !peek) {
1953 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
1954 if (Transport==TransportType.Udp) {
1955 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
1959 #endif //!FEATURE_PAL
1964 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred);
1966 catch (ObjectDisposedException) { }
1969 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Receive", bytesTransferred);
1971 return bytesTransferred;
1978 /// <para>Receives a datagram into a specific location in the data buffer and stores
1979 /// the end point.</para>
1981 public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation) {
1982 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "ReceiveMessageFrom", "");
1985 throw new ObjectDisposedException(this.GetType().FullName);
1988 throw new ArgumentNullException("buffer");
1990 if (remoteEP==null) {
1991 throw new ArgumentNullException("remoteEP");
1993 if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
1994 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
1995 remoteEP.AddressFamily, addressFamily), "remoteEP");
1997 if (offset<0 || offset>buffer.Length) {
1998 throw new ArgumentOutOfRangeException("offset");
2000 if (size<0 || size>buffer.Length-offset) {
2001 throw new ArgumentOutOfRangeException("size");
2003 if (m_RightEndPoint==null) {
2004 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
2008 ValidateBlockingMode();
2010 // We don't do a CAS demand here because the contents of remoteEP aren't used by
2011 // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
2012 // with the right address family
2013 EndPoint endPointSnapshot = remoteEP;
2014 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
2016 ReceiveMessageOverlappedAsyncResult asyncResult = new ReceiveMessageOverlappedAsyncResult(this,null,null);
2017 asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, socketFlags);
2019 // save a copy of the original EndPoint
2020 SocketAddress socketAddressOriginal = endPointSnapshot.Serialize();
2023 int bytesTransfered = 0;
2024 SocketError errorCode = SocketError.Success;
2026 SetReceivingPacketInformation();
2030 // This can throw ObjectDisposedException (retrieving the delegate AND resolving the handle).
2031 if (WSARecvMsg_Blocking(
2032 m_Handle.DangerousGetHandle(),
2033 Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.m_MessageBuffer,0),
2034 out bytesTransfered,
2036 IntPtr.Zero) == SocketError.SocketError)
2038 errorCode = (SocketError)Marshal.GetLastWin32Error();
2042 asyncResult.SyncReleaseUnmanagedStructures();
2047 // if the native call fails we'll throw a SocketException
2049 if (errorCode!=SocketError.Success && errorCode != SocketError.MessageSize) {
2051 // update our internal state after this socket error and throw
2053 SocketException socketException = new SocketException(errorCode);
2054 UpdateStatusAfterSocketError(socketException);
2055 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "ReceiveMessageFrom", socketException);
2056 throw socketException;
2060 if (!socketAddressOriginal.Equals(asyncResult.m_SocketAddress))
2063 remoteEP = endPointSnapshot.Create(asyncResult.m_SocketAddress);
2067 if (m_RightEndPoint==null) {
2069 // save a copy of the EndPoint so we can use it for Create()
2071 m_RightEndPoint = endPointSnapshot;
2075 socketFlags = asyncResult.m_flags;
2076 ipPacketInformation = asyncResult.m_IPPacketInformation;
2078 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "ReceiveMessageFrom", errorCode);
2079 return bytesTransfered;
2083 /// <para>Receives a datagram into a specific location in the data buffer and stores
2084 /// the end point.</para>
2086 public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP) {
2087 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "ReceiveFrom", "");
2089 throw new ObjectDisposedException(this.GetType().FullName);
2092 // parameter validation
2095 throw new ArgumentNullException("buffer");
2097 if (remoteEP==null) {
2098 throw new ArgumentNullException("remoteEP");
2100 if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
2101 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
2102 remoteEP.AddressFamily, addressFamily), "remoteEP");
2104 if (offset<0 || offset>buffer.Length) {
2105 throw new ArgumentOutOfRangeException("offset");
2107 if (size<0 || size>buffer.Length-offset) {
2108 throw new ArgumentOutOfRangeException("size");
2110 if (m_RightEndPoint==null) {
2111 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
2115 ValidateBlockingMode();
2116 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ReceiveFrom() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " size:" + size + " remoteEP:" + remoteEP.ToString());
2118 // We don't do a CAS demand here because the contents of remoteEP aren't used by
2119 // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
2120 // with the right address family
2121 EndPoint endPointSnapshot = remoteEP;
2122 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
2123 SocketAddress socketAddressOriginal = endPointSnapshot.Serialize();
2125 // This can throw ObjectDisposedException.
2126 int bytesTransferred;
2128 if (buffer.Length == 0)
2129 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recvfrom(m_Handle.DangerousGetHandle(), null, 0, socketFlags, socketAddress.m_Buffer, ref socketAddress.m_Size );
2130 else fixed (byte* pinnedBuffer = buffer) {
2131 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recvfrom(m_Handle.DangerousGetHandle(), pinnedBuffer+offset, size, socketFlags, socketAddress.m_Buffer, ref socketAddress.m_Size );
2135 // If the native call fails we'll throw a SocketException.
2136 // Must do this immediately after the native call so that the SocketException() constructor can pick up the error code.
2137 SocketException socketException = null;
2138 if ((SocketError) bytesTransferred == SocketError.SocketError)
2140 socketException = new SocketException();
2141 UpdateStatusAfterSocketError(socketException);
2142 if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "ReceiveFrom", socketException);
2144 if(socketException.ErrorCode != (int)SocketError.MessageSize){
2145 throw socketException;
2149 if (!socketAddressOriginal.Equals(socketAddress)) {
2151 remoteEP = endPointSnapshot.Create(socketAddress);
2155 if (m_RightEndPoint==null) {
2157 // save a copy of the EndPoint so we can use it for Create()
2159 m_RightEndPoint = endPointSnapshot;
2163 if(socketException != null){
2164 throw socketException;
2168 #if !FEATURE_PAL // perfcounter
2169 if (s_PerfCountersEnabled)
2171 if (bytesTransferred>0) {
2172 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
2173 if (Transport==TransportType.Udp) {
2174 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
2178 #endif //!FEATURE_PAL
2179 GlobalLog.Dump(buffer, offset, bytesTransferred);
2181 if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "ReceiveFrom", buffer, offset, size);
2182 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "ReceiveFrom", bytesTransferred);
2183 return bytesTransferred;
2188 /// <para>Receives a datagram and stores the source end point.</para>
2190 public int ReceiveFrom(byte[] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP) {
2191 return ReceiveFrom(buffer, 0, size, socketFlags, ref remoteEP);
2194 /// <para>[To be supplied.]</para>
2196 public int ReceiveFrom(byte[] buffer, SocketFlags socketFlags, ref EndPoint remoteEP) {
2197 return ReceiveFrom(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags, ref remoteEP);
2200 /// <para>[To be supplied.]</para>
2202 public int ReceiveFrom(byte[] buffer, ref EndPoint remoteEP) {
2203 return ReceiveFrom(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None, ref remoteEP);
2209 /// <para>[To be supplied.]</para>
2211 public int IOControl(int ioControlCode, byte[] optionInValue, byte[] optionOutValue) {
2213 throw new ObjectDisposedException(this.GetType().FullName);
2215 if (ioControlCode==IoctlSocketConstants.FIONBIO) {
2216 throw new InvalidOperationException(SR.GetString(SR.net_sockets_useblocking));
2219 ExceptionHelper.UnmanagedPermission.Demand();
2221 int realOptionLength = 0;
2223 // This can throw ObjectDisposedException.
2224 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
2225 m_Handle.DangerousGetHandle(),
2228 optionInValue!=null ? optionInValue.Length : 0,
2230 optionOutValue!=null ? optionOutValue.Length : 0,
2231 out realOptionLength,
2232 SafeNativeOverlapped.Zero,
2235 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::IOControl() UnsafeNclNativeMethods.OSSOCK.WSAIoctl returns errorCode:" + errorCode);
2238 // if the native call fails we'll throw a SocketException
2240 if (errorCode==SocketError.SocketError) {
2242 // update our internal state after this socket error and throw
2244 SocketException socketException = new SocketException();
2245 UpdateStatusAfterSocketError(socketException);
2246 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "IOControl", socketException);
2247 throw socketException;
2250 return realOptionLength;
2256 /// <para>[To be supplied.]</para>
2258 public int IOControl(IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue) {
2259 return IOControl(unchecked((int)ioControlCode),optionInValue,optionOutValue);
2263 internal int IOControl( IOControlCode ioControlCode,
2264 IntPtr optionInValue,
2266 IntPtr optionOutValue,
2270 throw new ObjectDisposedException(this.GetType().FullName);
2272 if ( (unchecked((int)ioControlCode)) ==IoctlSocketConstants.FIONBIO) {
2273 throw new InvalidOperationException(SR.GetString(SR.net_sockets_useblocking));
2276 int realOptionLength = 0;
2278 // This can throw ObjectDisposedException.
2279 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking_Internal(
2280 m_Handle.DangerousGetHandle(),
2281 (uint)ioControlCode,
2286 out realOptionLength,
2287 SafeNativeOverlapped.Zero,
2290 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::IOControl() UnsafeNclNativeMethods.OSSOCK.WSAIoctl returns errorCode:" + errorCode);
2293 // if the native call fails we'll throw a SocketException
2295 if (errorCode==SocketError.SocketError) {
2297 // update our internal state after this socket error and throw
2299 SocketException socketException = new SocketException();
2300 UpdateStatusAfterSocketError(socketException);
2301 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "IOControl", socketException);
2302 throw socketException;
2305 return realOptionLength;
2309 public void SetIPProtectionLevel(IPProtectionLevel level) {
2310 if (level == IPProtectionLevel.Unspecified) {
2311 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue_all), "level");
2314 if (addressFamily == AddressFamily.InterNetworkV6) {
2315 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPProtectionLevel, (int)level);
2317 else if (addressFamily == AddressFamily.InterNetwork) {
2318 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IPProtectionLevel, (int)level);
2321 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
2328 /// Sets the specified option to the specified value.
2331 public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue) {
2333 throw new ObjectDisposedException(this.GetType().FullName);
2335 CheckSetOptionPermissions(optionLevel, optionName);
2336 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
2337 SetSocketOption(optionLevel, optionName, optionValue, false);
2342 /// <para>[To be supplied.]</para>
2344 public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue) {
2346 throw new ObjectDisposedException(this.GetType().FullName);
2349 CheckSetOptionPermissions(optionLevel, optionName);
2351 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
2353 // This can throw ObjectDisposedException.
2354 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
2359 optionValue != null ? optionValue.Length : 0);
2361 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
2364 // if the native call fails we'll throw a SocketException
2366 if (errorCode==SocketError.SocketError) {
2368 // update our internal state after this socket error and throw
2370 SocketException socketException = new SocketException();
2371 UpdateStatusAfterSocketError(socketException);
2372 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SetSocketOption", socketException);
2373 throw socketException;
2378 /// <para>Sets the specified option to the specified value.</para>
2381 public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue) {
2382 SetSocketOption(optionLevel,optionName,(optionValue?1:0));
2386 /// <para>Sets the specified option to the specified value.</para>
2388 public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue) {
2390 throw new ObjectDisposedException(this.GetType().FullName);
2393 // parameter validation
2395 if (optionValue==null) {
2396 throw new ArgumentNullException("optionValue");
2399 CheckSetOptionPermissions(optionLevel, optionName);
2401 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
2403 if (optionLevel==SocketOptionLevel.Socket && optionName==SocketOptionName.Linger) {
2404 LingerOption lingerOption = optionValue as LingerOption;
2405 if (lingerOption==null) {
2406 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "LingerOption"), "optionValue");
2408 if (lingerOption.LingerTime < 0 || lingerOption.LingerTime>(int)UInt16.MaxValue) {
2409 throw new ArgumentException(SR.GetString(SR.ArgumentOutOfRange_Bounds_Lower_Upper, 0, (int)UInt16.MaxValue), "optionValue.LingerTime");
2411 setLingerOption(lingerOption);
2413 else if (optionLevel==SocketOptionLevel.IP && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
2414 MulticastOption multicastOption = optionValue as MulticastOption;
2415 if (multicastOption==null) {
2416 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "MulticastOption"), "optionValue");
2418 setMulticastOption(optionName, multicastOption);
2421 // IPv6 Changes: Handle IPv6 Multicast Add / Drop
2423 else if (optionLevel==SocketOptionLevel.IPv6 && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
2424 IPv6MulticastOption multicastOption = optionValue as IPv6MulticastOption;
2425 if (multicastOption==null) {
2426 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "IPv6MulticastOption"), "optionValue");
2428 setIPv6MulticastOption(optionName, multicastOption);
2431 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue_all), "optionValue");
2438 /// Gets the value of a socket option.
2442 public object GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName) {
2444 throw new ObjectDisposedException(this.GetType().FullName);
2446 if (optionLevel==SocketOptionLevel.Socket && optionName==SocketOptionName.Linger) {
2447 return getLingerOpt();
2449 else if (optionLevel==SocketOptionLevel.IP && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
2450 return getMulticastOpt(optionName);
2455 else if (optionLevel==SocketOptionLevel.IPv6 && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
2456 return getIPv6MulticastOpt(optionName);
2459 int optionValue = 0;
2460 int optionLength = 4;
2462 // This can throw ObjectDisposedException.
2463 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
2470 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
2473 // if the native call fails we'll throw a SocketException
2475 if (errorCode==SocketError.SocketError) {
2477 // update our internal state after this socket error and throw
2479 SocketException socketException = new SocketException();
2480 UpdateStatusAfterSocketError(socketException);
2481 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
2482 throw socketException;
2491 /// <para>[To be supplied.]</para>
2493 public void GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue) {
2495 throw new ObjectDisposedException(this.GetType().FullName);
2498 int optionLength = optionValue!=null ? optionValue.Length : 0;
2500 // This can throw ObjectDisposedException.
2501 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
2508 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
2511 // if the native call fails we'll throw a SocketException
2513 if (errorCode==SocketError.SocketError) {
2515 // update our internal state after this socket error and throw
2517 SocketException socketException = new SocketException();
2518 UpdateStatusAfterSocketError(socketException);
2519 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
2520 throw socketException;
2526 /// <para>[To be supplied.]</para>
2528 public byte[] GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength) {
2530 throw new ObjectDisposedException(this.GetType().FullName);
2533 byte[] optionValue = new byte[optionLength];
2534 int realOptionLength = optionLength;
2536 // This can throw ObjectDisposedException.
2537 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
2542 ref realOptionLength);
2544 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
2547 // if the native call fails we'll throw a SocketException
2549 if (errorCode==SocketError.SocketError) {
2551 // update our internal state after this socket error and throw
2553 SocketException socketException = new SocketException();
2554 UpdateStatusAfterSocketError(socketException);
2555 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
2556 throw socketException;
2559 if (optionLength!=realOptionLength) {
2560 byte[] newOptionValue = new byte[realOptionLength];
2561 Buffer.BlockCopy(optionValue, 0, newOptionValue, 0, realOptionLength);
2562 optionValue = newOptionValue;
2571 /// Determines the status of the socket.
2574 public bool Poll(int microSeconds, SelectMode mode) {
2576 throw new ObjectDisposedException(this.GetType().FullName);
2579 IntPtr handle = m_Handle.DangerousGetHandle();
2580 IntPtr[] fileDescriptorSet = new IntPtr[2] { (IntPtr) 1, handle };
2581 TimeValue IOwait = new TimeValue();
2584 // negative timeout value implies indefinite wait
2587 if (microSeconds != -1) {
2588 MicrosecondsToTimeValue((long)(uint)microSeconds, ref IOwait);
2590 UnsafeNclNativeMethods.OSSOCK.select(
2592 mode==SelectMode.SelectRead ? fileDescriptorSet : null,
2593 mode==SelectMode.SelectWrite ? fileDescriptorSet : null,
2594 mode==SelectMode.SelectError ? fileDescriptorSet : null,
2599 UnsafeNclNativeMethods.OSSOCK.select(
2601 mode==SelectMode.SelectRead ? fileDescriptorSet : null,
2602 mode==SelectMode.SelectWrite ? fileDescriptorSet : null,
2603 mode==SelectMode.SelectError ? fileDescriptorSet : null,
2606 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Poll() UnsafeNclNativeMethods.OSSOCK.select returns socketCount:" + socketCount);
2609 // if the native call fails we'll throw a SocketException
2611 if ((SocketError)socketCount==SocketError.SocketError) {
2613 // update our internal state after this socket error and throw
2615 SocketException socketException = new SocketException();
2616 UpdateStatusAfterSocketError(socketException);
2617 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Poll", socketException);
2618 throw socketException;
2620 if ((int)fileDescriptorSet[0]==0) {
2623 return fileDescriptorSet[1] == handle;
2627 /// <para>Determines the status of a socket.</para>
2629 public static void Select(IList checkRead, IList checkWrite, IList checkError, int microSeconds) {
2630 // parameter validation
2631 if ((checkRead==null || checkRead.Count==0) && (checkWrite==null || checkWrite.Count==0) && (checkError==null || checkError.Count==0)) {
2632 throw new ArgumentNullException(SR.GetString(SR.net_sockets_empty_select));
2634 const int MaxSelect = 65536;
2635 if (checkRead!=null && checkRead.Count>MaxSelect) {
2636 throw new ArgumentOutOfRangeException("checkRead", SR.GetString(SR.net_sockets_toolarge_select, "checkRead", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
2638 if (checkWrite!=null && checkWrite.Count>MaxSelect) {
2639 throw new ArgumentOutOfRangeException("checkWrite", SR.GetString(SR.net_sockets_toolarge_select, "checkWrite", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
2641 if (checkError!=null && checkError.Count>MaxSelect) {
2642 throw new ArgumentOutOfRangeException("checkError", SR.GetString(SR.net_sockets_toolarge_select, "checkError", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
2644 IntPtr[] readfileDescriptorSet = SocketListToFileDescriptorSet(checkRead);
2645 IntPtr[] writefileDescriptorSet = SocketListToFileDescriptorSet(checkWrite);
2646 IntPtr[] errfileDescriptorSet = SocketListToFileDescriptorSet(checkError);
2648 // This code used to erroneously pass a non-null timeval structure containing zeroes
2649 // to select() when the caller specified (-1) for the microseconds parameter. That
2650 // caused select to actually have a *zero* timeout instead of an infinite timeout
2651 // turning the operation into a non-blocking poll.
2653 // Now we pass a null timeval struct when microseconds is (-1).
2655 // Negative microsecond values that weren't exactly (-1) were originally successfully
2656 // converted to a timeval struct containing unsigned non-zero integers. This code
2657 // retains that behavior so that any app working around the original bug with,
2658 // for example, (-2) specified for microseconds, will continue to get the same behavior.
2662 if (microSeconds != -1) {
2663 TimeValue IOwait = new TimeValue();
2664 MicrosecondsToTimeValue((long)(uint)microSeconds, ref IOwait);
2667 UnsafeNclNativeMethods.OSSOCK.select(
2669 readfileDescriptorSet,
2670 writefileDescriptorSet,
2671 errfileDescriptorSet,
2676 UnsafeNclNativeMethods.OSSOCK.select(
2678 readfileDescriptorSet,
2679 writefileDescriptorSet,
2680 errfileDescriptorSet,
2684 GlobalLog.Print("Socket::Select() UnsafeNclNativeMethods.OSSOCK.select returns socketCount:" + socketCount);
2687 // if the native call fails we'll throw a SocketException
2689 if ((SocketError)socketCount==SocketError.SocketError) {
2690 throw new SocketException();
2692 SelectFileDescriptor(checkRead, readfileDescriptorSet);
2693 SelectFileDescriptor(checkWrite, writefileDescriptorSet);
2694 SelectFileDescriptor(checkError, errfileDescriptorSet);
2700 /// <para>[To be supplied.]</para>
2703 [HostProtection(ExternalThreading=true)]
2704 [ResourceExposure(ResourceScope.Machine)]
2705 [ResourceConsumption(ResourceScope.Machine)]
2706 public IAsyncResult BeginSendFile(
2708 AsyncCallback callback,
2711 return BeginSendFile(fileName,null,null,TransmitFileOptions.UseDefaultWorkerThread,callback,state);
2717 // Async Winsock Support, the following functions use either
2718 // the Async Winsock support to do overlapped I/O WSASend/WSARecv
2719 // or a WSAEventSelect call to enable selection and non-blocking mode
2720 // of otherwise normal Winsock calls.
2722 // Currently the following Async Socket calls are supported:
2723 // Send, Recv, SendTo, RecvFrom, Connect, Accept
2728 Routine Description:
2730 BeginConnect - Does a async winsock connect, by calling
2731 WSAEventSelect to enable Connect Events to signal an event and
2732 wake up a callback which involkes a callback.
2734 So note: This routine may go pending at which time,
2735 but any case the callback Delegate will be called upon completion
2739 remoteEP - status line that we wish to parse
2740 Callback - Async Callback Delegate that is called upon Async Completion
2741 State - State used to track callback, set by caller, not required
2745 IAsyncResult - Async result used to retreive result
2751 /// <para>[To be supplied.]</para>
2753 [HostProtection(ExternalThreading=true)]
2754 public IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)
2757 // parameter validation
2759 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", remoteEP);
2762 throw new ObjectDisposedException(this.GetType().FullName);
2765 if (remoteEP==null) {
2766 throw new ArgumentNullException("remoteEP");
2771 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
2774 DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
2777 if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily))
2779 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
2782 return BeginConnect(dnsEP.Host, dnsEP.Port, callback, state);
2785 if (CanUseConnectEx(remoteEP))
2787 return BeginConnectEx(remoteEP, true, callback, state);
2790 // This will check the permissions for connect.
2791 EndPoint endPointSnapshot = remoteEP;
2792 SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true);
2794 // Flow the context. No need to lock it since we don't use it until the callback.
2795 ConnectAsyncResult asyncResult = new ConnectAsyncResult(this, endPointSnapshot, state, callback);
2796 asyncResult.StartPostingAsyncOp(false);
2798 // Post the connect.
2799 DoBeginConnect(endPointSnapshot, socketAddress, asyncResult);
2801 // We didn't throw, so finish the posting op. This will call the callback if the operation already completed.
2802 asyncResult.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
2804 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", asyncResult);
2811 public SocketInformation DuplicateAndClose(int targetProcessId){
2812 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "DuplicateAndClose", null);
2816 throw new ObjectDisposedException(GetType().FullName);
2819 ExceptionHelper.UnrestrictedSocketPermission.Demand();
2821 SocketInformation info = new SocketInformation();
2822 info.ProtocolInformation = new byte[protocolInformationSize];
2824 // This can throw ObjectDisposedException.
2825 SocketError errorCode;
2828 fixed (byte* pinnedBuffer = info.ProtocolInformation) {
2829 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSADuplicateSocket(m_Handle, (uint)targetProcessId, pinnedBuffer);
2833 errorCode = SocketError.SocketError;
2834 #endif // !FEATURE_PAL
2836 if (errorCode!=SocketError.Success) {
2837 SocketException socketException = new SocketException();
2838 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "DuplicateAndClose", socketException);
2839 throw socketException;
2843 info.IsConnected = Connected;
2844 info.IsNonBlocking = !Blocking;
2845 info.IsListening = isListening;
2846 info.UseOnlyOverlappedIO = UseOnlyOverlappedIO;
2847 info.RemoteEndPoint = m_RemoteEndPoint;
2849 //make sure we don't shutdown, etc.
2852 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "DuplicateAndClose", null);
2859 internal IAsyncResult UnsafeBeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)
2861 if (CanUseConnectEx(remoteEP))
2863 return BeginConnectEx(remoteEP, false, callback, state);
2865 EndPoint endPointSnapshot = remoteEP;
2866 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
2868 // No context flow here. Can use Lazy.
2869 ConnectAsyncResult asyncResult = new ConnectAsyncResult(this, endPointSnapshot, state, callback);
2870 DoBeginConnect(endPointSnapshot, socketAddress, asyncResult);
2874 // Leaving the public logging as "BeginConnect" since that makes sense to the people looking at the output.
2875 // Private logging can remain "DoBeginConnect".
2876 private void DoBeginConnect(EndPoint endPointSnapshot, SocketAddress socketAddress, LazyAsyncResult asyncResult)
2878 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() endPointSnapshot:" + endPointSnapshot.ToString());
2880 EndPoint oldEndPoint = m_RightEndPoint;
2883 if (m_AcceptQueueOrConnectResult != null)
2885 throw new InvalidOperationException(SR.GetString(SR.net_sockets_no_duplicate_async));
2888 m_AcceptQueueOrConnectResult = asyncResult;
2890 if (!SetAsyncEventSelect(AsyncEventBits.FdConnect)){
2891 m_AcceptQueueOrConnectResult = null;
2892 throw new ObjectDisposedException(this.GetType().FullName);
2895 // This can throw ObjectDisposedException.
2896 IntPtr handle = m_Handle.DangerousGetHandle();
2898 //we should fix this in Whidbey.
2899 if (m_RightEndPoint == null) {
2900 m_RightEndPoint = endPointSnapshot;
2903 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAConnect(
2905 socketAddress.m_Buffer,
2906 socketAddress.m_Size,
2912 if (errorCode!=SocketError.Success) {
2913 errorCode = (SocketError)Marshal.GetLastWin32Error();
2915 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() UnsafeNclNativeMethods.OSSOCK.WSAConnect returns errorCode:" + errorCode);
2917 if (errorCode != SocketError.WouldBlock)
2919 bool completeSynchronously = true;
2920 if (errorCode == SocketError.Success)
2926 asyncResult.ErrorCode = (int) errorCode;
2929 // Using interlocked to avoid a race condition with RegisteredWaitCallback
2930 // Although UnsetAsyncEventSelect() below should cancel the callback, but
2931 // it may already be in progress and therefore resulting in simultaneous
2932 // registeredWaitCallback calling ConnectCallback() and the synchronous
2934 if (Interlocked.Exchange(ref m_RegisteredWait, null) == null)
2935 completeSynchronously = false;
2937 // Cancel async event and go back to blocking mode.
2939 UnsetAsyncEventSelect();
2941 if (errorCode == SocketError.Success)
2944 // synchronously complete the IO and call the user's callback.
2946 if (completeSynchronously)
2947 asyncResult.InvokeCallback();
2952 // if the asynchronous native call fails synchronously
2953 // we'll throw a SocketException
2955 m_RightEndPoint = oldEndPoint;
2956 SocketException socketException = new SocketException(errorCode);
2957 UpdateStatusAfterSocketError(socketException);
2958 m_AcceptQueueOrConnectResult = null;
2959 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginConnect", socketException);
2960 throw socketException;
2964 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() to:" + endPointSnapshot.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
2967 // Begin ConnectEx is only supported for connection oriented protocols
2968 // for now this is only supported on win32 platforms. We need to fix this
2969 // when the getdelegatefrom function methods are available on 64bit.
2970 // to use this, the endpoint must either be an IP endpoint, or the
2971 // socket must already be bound.
2972 private bool CanUseConnectEx(EndPoint remoteEP)
2975 return socketType == SocketType.Stream &&
2976 (m_RightEndPoint != null || remoteEP.GetType() == typeof(IPEndPoint)) &&
2977 (Thread.CurrentThread.IsThreadPoolThread || SettingsSectionInternal.Section.AlwaysUseCompletionPortsForConnect || m_IsDisconnected);
2984 // This is the internal callback that will be called when
2985 // the IO we issued for the user to winsock has completed.
2986 // when this function gets called it must:
2987 // 1) update the AsyncResult object with the results of the completed IO
2988 // 2) signal events that the user might be waiting on
2989 // 3) call the callback function that the user might have specified
2991 // This method was copied from a ConnectAsyncResult class that became useless.
2992 private void ConnectCallback()
2994 LazyAsyncResult asyncResult = (LazyAsyncResult) m_AcceptQueueOrConnectResult;
2997 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback");
2999 // If we came here due to a ---- between BeginConnect and Dispose
3001 if (asyncResult.InternalPeekCompleted)
3003 GlobalLog.Assert(CleanedUp, "Socket#{0}::ConnectCallback()|asyncResult is compelted but the socket does not have CleanedUp set.", ValidationHelper.HashString(this));
3004 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback", "Already completed, socket must be closed");
3021 // get async completion
3024 int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
3025 GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString());
3028 NetworkEvents networkEvents = new NetworkEvents();
3029 networkEvents.Events = AsyncEventBits.FdConnect;
3031 SocketError errorCode = SocketError.OperationAborted;
3032 object result = null;
3040 errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents(
3042 m_AsyncEvent.SafeWaitHandle,
3045 if (errorCode != SocketError.Success)
3047 errorCode = (SocketError) Marshal.GetLastWin32Error();
3048 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString());
3052 errorCode = (SocketError) networkEvents.ErrorCodes[(int) AsyncEventBitsPos.FdConnectBit];
3053 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString());
3056 // Cancel async event and go back to blocking mode.
3058 UnsetAsyncEventSelect();
3060 catch (ObjectDisposedException)
3062 errorCode = SocketError.OperationAborted;
3067 // if the native non-blocking call failed we'll throw a SocketException in EndConnect()
3069 if (errorCode == SocketError.Success)
3072 // the Socket is connected, update our state and performance counter
3077 catch (Exception exception)
3079 if (NclUtilities.IsFatal(exception)) throw;
3081 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() caught exception:" + exception.Message + ", CleanedUp:" + CleanedUp);
3085 if (!asyncResult.InternalPeekCompleted)
3087 // A "ErrorCode" concept is questionable, for ex. below lines are subject to a race condition
3088 asyncResult.ErrorCode = (int) errorCode;
3089 asyncResult.InvokeCallback(result);
3092 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback", errorCode.ToString());
3095 [HostProtection(ExternalThreading=true)]
3096 public IAsyncResult BeginConnect(string host, int port, AsyncCallback requestCallback, object state){
3097 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", host);
3100 throw new ObjectDisposedException(this.GetType().FullName);
3104 throw new ArgumentNullException("host");
3106 if (!ValidationHelper.ValidateTcpPort(port)){
3107 throw new ArgumentOutOfRangeException("port");
3109 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
3110 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
3115 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
3118 // Here, want to flow the context. No need to lock.
3119 MultipleAddressConnectAsyncResult result = new MultipleAddressConnectAsyncResult(null, port, this, state, requestCallback);
3120 result.StartPostingAsyncOp(false);
3122 IAsyncResult dnsResult = Dns.UnsafeBeginGetHostAddresses(host, new AsyncCallback(DnsCallback), result);
3123 if (dnsResult.CompletedSynchronously)
3125 if (DoDnsCallback(dnsResult, result))
3127 result.InvokeCallback();
3132 result.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
3134 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
3139 [HostProtection(ExternalThreading=true)]
3140 public IAsyncResult BeginConnect(IPAddress address, int port, AsyncCallback requestCallback, object state){
3141 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", address);
3143 throw new ObjectDisposedException(this.GetType().FullName);
3146 if (address==null) {
3147 throw new ArgumentNullException("address");
3149 if (!ValidationHelper.ValidateTcpPort(port)){
3150 throw new ArgumentOutOfRangeException("port");
3152 //if address family isn't the socket address family throw
3153 if (!CanTryAddressFamily(address.AddressFamily)) {
3154 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
3157 IAsyncResult result = BeginConnect(new IPEndPoint(address,port),requestCallback,state);
3158 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
3163 [HostProtection(ExternalThreading=true)]
3164 public IAsyncResult BeginConnect(IPAddress[] addresses, int port, AsyncCallback requestCallback, object state)
3166 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", addresses);
3168 throw new ObjectDisposedException(this.GetType().FullName);
3171 if (addresses==null) {
3172 throw new ArgumentNullException("addresses");
3174 if (addresses.Length == 0) {
3175 throw new ArgumentException(SR.GetString(SR.net_invalidAddressList), "addresses");
3177 if (!ValidationHelper.ValidateTcpPort(port)) {
3178 throw new ArgumentOutOfRangeException("port");
3180 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
3181 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
3186 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
3189 // Set up the result to capture the context. No need for a lock.
3190 MultipleAddressConnectAsyncResult result = new MultipleAddressConnectAsyncResult(addresses, port, this, state, requestCallback);
3191 result.StartPostingAsyncOp(false);
3193 if (DoMultipleAddressConnectCallback(PostOneBeginConnect(result), result))
3195 // if it completes synchronously, invoke the callback from here
3196 result.InvokeCallback();
3199 // Finished posting async op. Possibly will call callback.
3200 result.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
3202 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
3206 // Supports DisconnectEx - this provides completion port IO and support for
3207 //disconnect and reconnects
3208 [HostProtection(ExternalThreading=true)]
3209 public IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback callback, object state)
3211 // Start context-flowing op. No need to lock - we don't use the context till the callback.
3212 DisconnectOverlappedAsyncResult asyncResult = new DisconnectOverlappedAsyncResult(this, state, callback);
3213 asyncResult.StartPostingAsyncOp(false);
3215 // Post the disconnect.
3216 DoBeginDisconnect(reuseSocket, asyncResult);
3218 // Finish flowing (or call the callback), and return.
3219 asyncResult.FinishPostingAsyncOp();
3223 private void DoBeginDisconnect(bool reuseSocket, DisconnectOverlappedAsyncResult asyncResult)
3225 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginDisconnect",null);
3227 throw new ObjectDisposedException(this.GetType().FullName);
3230 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() ");
3232 #if FEATURE_PAL && !MONO
3233 throw new PlatformNotSupportedException(SR.GetString(SR.WinXPRequired));
3237 asyncResult.SetUnmanagedStructures(null);
3239 SocketError errorCode=SocketError.Success;
3241 // This can throw ObjectDisposedException (handle, and retrieving the delegate).
3242 if (!DisconnectEx(m_Handle,asyncResult.OverlappedHandle, (int)(reuseSocket?TransmitFileOptions.ReuseSocket:0),0)) {
3243 errorCode = (SocketError)Marshal.GetLastWin32Error();
3246 if (errorCode == SocketError.Success) {
3247 SetToDisconnected();
3248 m_RemoteEndPoint = null;
3251 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() UnsafeNclNativeMethods.OSSOCK.DisConnectEx returns:" + errorCode.ToString());
3253 // if the asynchronous native call fails synchronously
3254 // we'll throw a SocketException
3256 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
3258 if (errorCode!= SocketError.Success) {
3260 // update our internal state after this socket error and throw
3262 SocketException socketException = new SocketException(errorCode);
3263 UpdateStatusAfterSocketError(socketException);
3264 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"BeginDisconnect", socketException);
3265 throw socketException;
3268 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
3269 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginDisconnect", asyncResult);
3273 // Supports DisconnectEx - this provides support for disconnect and reconnects
3274 public void Disconnect(bool reuseSocket) {
3276 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Disconnect",null);
3278 throw new ObjectDisposedException(this.GetType().FullName);
3281 #if FEATURE_PAL && !MONO
3282 throw new PlatformNotSupportedException(SR.GetString(SR.WinXPRequired));
3283 #endif // FEATURE_PAL && !MONO
3286 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Disconnect() ");
3288 SocketError errorCode = SocketError.Success;
3290 // This can throw ObjectDisposedException (handle, and retrieving the delegate).
3291 if (!DisconnectEx_Blocking(m_Handle.DangerousGetHandle(), IntPtr.Zero, (int) (reuseSocket ? TransmitFileOptions.ReuseSocket : 0), 0))
3293 errorCode = (SocketError)Marshal.GetLastWin32Error();
3296 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Disconnect() UnsafeNclNativeMethods.OSSOCK.DisConnectEx returns:" + errorCode.ToString());
3299 if (errorCode!= SocketError.Success) {
3301 // update our internal state after this socket error and throw
3303 SocketException socketException = new SocketException(errorCode);
3304 UpdateStatusAfterSocketError(socketException);
3305 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"Disconnect", socketException);
3306 throw socketException;
3309 SetToDisconnected();
3310 m_RemoteEndPoint = null;
3312 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Disconnect", null);
3317 Routine Description:
3319 EndConnect - Called addressFamilyter receiving callback from BeginConnect,
3320 in order to retrive the result of async call
3324 AsyncResult - the AsyncResult Returned fron BeginConnect call
3328 int - Return code from aync Connect, 0 for success, SocketError.NotConnected otherwise
3332 /// <para>[To be supplied.]</para>
3334 public void EndConnect(IAsyncResult asyncResult) {
3335 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndConnect", asyncResult);
3337 throw new ObjectDisposedException(this.GetType().FullName);
3340 // parameter validation
3342 if (asyncResult==null) {
3343 throw new ArgumentNullException("asyncResult");
3346 LazyAsyncResult castedAsyncResult = null;
3347 EndPoint remoteEndPoint = null;
3348 ConnectOverlappedAsyncResult coar;
3349 MultipleAddressConnectAsyncResult macar;
3350 ConnectAsyncResult car;
3352 coar = asyncResult as ConnectOverlappedAsyncResult;
3354 macar = asyncResult as MultipleAddressConnectAsyncResult;
3355 if (macar == null) {
3356 car = asyncResult as ConnectAsyncResult;
3358 remoteEndPoint = car.RemoteEndPoint;
3359 castedAsyncResult = car;
3362 remoteEndPoint = macar.RemoteEndPoint;
3363 castedAsyncResult = macar;
3366 remoteEndPoint = coar.RemoteEndPoint;
3367 castedAsyncResult = coar;
3370 if (castedAsyncResult == null || castedAsyncResult.AsyncObject!=this) {
3371 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
3373 if (castedAsyncResult.EndCalled) {
3374 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndConnect"));
3377 castedAsyncResult.InternalWaitForCompletion();
3378 castedAsyncResult.EndCalled = true;
3379 m_AcceptQueueOrConnectResult = null;
3381 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndConnect() asyncResult:" + ValidationHelper.HashString(asyncResult));
3383 if (castedAsyncResult.Result is Exception) {
3384 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndConnect", (Exception)castedAsyncResult.Result);
3385 throw (Exception)castedAsyncResult.Result;
3387 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
3389 // update our internal state after this socket error and throw
3391 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode, remoteEndPoint);
3392 UpdateStatusAfterSocketError(socketException);
3393 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndConnect", socketException);
3394 throw socketException;
3396 if (s_LoggingEnabled) {
3397 Logging.PrintInfo(Logging.Sockets, this, SR.GetString(SR.net_log_socket_connected, LocalEndPoint, RemoteEndPoint));
3398 Logging.Exit(Logging.Sockets, this, "EndConnect", "");
3402 public void EndDisconnect(IAsyncResult asyncResult) {
3404 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndDisconnect", asyncResult);
3406 throw new ObjectDisposedException(this.GetType().FullName);
3409 #if FEATURE_PAL && !MONO
3410 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
3411 #endif // FEATURE_PAL && !MONO
3413 if (asyncResult==null) {
3414 throw new ArgumentNullException("asyncResult");
3418 //get async result and check for errors
3419 LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
3420 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
3421 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
3423 if (castedAsyncResult.EndCalled) {
3424 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndDisconnect"));
3427 //wait for completion if it hasn't occured
3428 castedAsyncResult.InternalWaitForCompletion();
3429 castedAsyncResult.EndCalled = true;
3432 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndDisconnect()");
3435 // if the asynchronous native call failed asynchronously
3436 // we'll throw a SocketException
3438 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
3440 // update our internal state after this socket error and throw
3442 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
3443 UpdateStatusAfterSocketError(socketException);
3444 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"EndDisconnect", socketException);
3445 throw socketException;
3448 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndDisconnect", null);
3455 Routine Description:
3457 BeginSend - Async implimentation of Send call, mirrored addressFamilyter BeginReceive
3458 This routine may go pending at which time,
3459 but any case the callback Delegate will be called upon completion
3463 WriteBuffer - status line that we wish to parse
3464 Index - Offset into WriteBuffer to begin sending from
3465 Size - Size of Buffer to transmit
3466 Callback - Delegate function that holds callback, called on completeion of I/O
3467 State - State used to track callback, set by caller, not required
3471 IAsyncResult - Async result used to retreive result
3476 /// <para>[To be supplied.]</para>
3479 [HostProtection(ExternalThreading=true)]
3480 public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
3482 SocketError errorCode;
3483 IAsyncResult result = BeginSend(buffer, offset, size, socketFlags, out errorCode, callback, state);
3484 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3485 throw new SocketException(errorCode);
3491 [HostProtection(ExternalThreading=true)]
3492 public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
3495 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSend", "");
3498 throw new ObjectDisposedException(this.GetType().FullName);
3501 // parameter validation
3505 throw new ArgumentNullException("buffer");
3507 if (offset < 0 || offset > buffer.Length)
3509 throw new ArgumentOutOfRangeException("offset");
3511 if (size < 0 || size > buffer.Length - offset)
3513 throw new ArgumentOutOfRangeException("size");
3516 // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
3517 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
3518 asyncResult.StartPostingAsyncOp(false);
3520 // Run the send with this asyncResult.
3521 errorCode = DoBeginSend(buffer, offset, size, socketFlags, asyncResult);
3523 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3528 // We're not throwing, so finish the async op posting code so we can return to the user.
3529 // If the operation already finished, the callback will be called from here.
3530 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
3533 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSend", asyncResult);
3538 internal IAsyncResult UnsafeBeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
3540 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "UnsafeBeginSend", "");
3543 throw new ObjectDisposedException(this.GetType().FullName);
3546 // No need to flow the context.
3547 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
3549 SocketError errorCode = DoBeginSend(buffer, offset, size, socketFlags, asyncResult);
3550 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3551 throw new SocketException(errorCode);
3554 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "UnsafeBeginSend", asyncResult);
3558 private SocketError DoBeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
3561 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size.ToString());
3563 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
3564 // avoid a Socket leak in case of error.
3565 SocketError errorCode = SocketError.SocketError;
3568 // Set up asyncResult for overlapped WSASend.
3569 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
3570 asyncResult.SetUnmanagedStructures(buffer, offset, size, null, false /*don't pin null remoteEP*/, ref Caches.SendOverlappedCache);
3573 // Get the Send going.
3575 GlobalLog.Print("BeginSend: asyncResult:" + ValidationHelper.HashString(asyncResult) + " size:" + size.ToString());
3576 int bytesTransferred;
3578 // This can throw ObjectDisposedException.
3579 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
3581 ref asyncResult.m_SingleBuffer,
3582 1, // only ever 1 buffer being sent
3583 out bytesTransferred,
3585 asyncResult.OverlappedHandle,
3588 if (errorCode!=SocketError.Success) {
3589 errorCode = (SocketError)Marshal.GetLastWin32Error();
3591 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
3595 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
3599 // if the asynchronous native call fails synchronously
3600 // we'll throw a SocketException
3602 if (errorCode != SocketError.Success)
3604 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3605 UpdateStatusAfterSocketError(errorCode);
3606 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSend", new SocketException(errorCode));
3613 /// <para>[To be supplied.]</para>
3617 [HostProtection(ExternalThreading=true)]
3618 [ResourceExposure(ResourceScope.Machine)]
3619 [ResourceConsumption(ResourceScope.Machine)]
3620 public IAsyncResult BeginSendFile(
3624 TransmitFileOptions flags,
3625 AsyncCallback callback,
3629 // Start the context flowing. No lock necessary.
3630 TransmitFileOverlappedAsyncResult asyncResult = new TransmitFileOverlappedAsyncResult(this,state,callback);
3631 asyncResult.StartPostingAsyncOp(false);
3633 // Start the operation.
3634 DoBeginSendFile(fileName, preBuffer, postBuffer, flags, asyncResult);
3636 // Finish the op, collect the context or maybe call the callback.
3637 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
3641 [ResourceExposure(ResourceScope.Machine)]
3642 [ResourceConsumption(ResourceScope.Machine)]
3643 private void DoBeginSendFile(
3647 TransmitFileOptions flags,
3648 TransmitFileOverlappedAsyncResult asyncResult)
3650 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSendFile", "");
3653 throw new ObjectDisposedException(this.GetType().FullName);
3657 throw new ObjectDisposedException(this.GetType().FullName);
3660 #if FEATURE_PAL && !MONO
3661 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
3662 #endif // FEATURE_PAL && !MONO
3666 throw new NotSupportedException(SR.GetString(SR.net_notconnected));
3669 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " fileName:" + fileName);
3671 FileStream fileStream = null;
3672 if (fileName != null && fileName.Length>0) {
3673 fileStream = new FileStream(fileName,FileMode.Open,FileAccess.Read,FileShare.Read);
3676 SafeHandle fileHandle = null;
3678 if (fileStream != null) {
3679 ExceptionHelper.UnmanagedPermission.Assert();
3681 fileHandle = fileStream.SafeFileHandle;
3684 SecurityPermission.RevertAssert();
3688 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
3689 // avoid a Socket leak in case of error.
3690 SocketError errorCode = SocketError.SocketError;
3693 asyncResult.SetUnmanagedStructures(preBuffer, postBuffer, fileStream, flags, ref Caches.SendOverlappedCache);
3694 bool result = false;
3696 // This can throw ObjectDisposedException.
3697 if (fileHandle != null){
3698 result = UnsafeNclNativeMethods.OSSOCK.TransmitFile(m_Handle,fileHandle,0,0,asyncResult.OverlappedHandle,asyncResult.TransmitFileBuffers,flags);
3701 result = UnsafeNclNativeMethods.OSSOCK.TransmitFile2(m_Handle,IntPtr.Zero,0,0,asyncResult.OverlappedHandle,asyncResult.TransmitFileBuffers,flags);
3705 errorCode = (SocketError)Marshal.GetLastWin32Error();
3709 errorCode = SocketError.Success;
3714 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
3718 // if the native call fails we'll throw a SocketException
3720 if (errorCode!=SocketError.Success) {
3722 // update our internal state after this socket error and throw
3724 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3725 SocketException socketException = new SocketException(errorCode);
3726 UpdateStatusAfterSocketError(socketException);
3728 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSendFile", socketException);
3729 throw socketException;
3732 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendFile() UnsafeNclNativeMethods.OSSOCK.send returns:" + errorCode.ToString());
3734 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSendFile", errorCode);
3737 #endif // !FEATURE_PAL
3741 /// <para>[To be supplied.]</para>
3743 [HostProtection(ExternalThreading=true)]
3744 public IAsyncResult BeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
3746 SocketError errorCode;
3747 IAsyncResult result = BeginSend(buffers, socketFlags, out errorCode, callback, state);
3748 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3749 throw new SocketException(errorCode);
3755 [HostProtection(ExternalThreading=true)]
3756 public IAsyncResult BeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
3759 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSend", "");
3762 throw new ObjectDisposedException(this.GetType().FullName);
3766 // parameter validation
3768 if (buffers==null) {
3769 throw new ArgumentNullException("buffers");
3772 if(buffers.Count == 0){
3773 throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
3776 // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
3777 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
3778 asyncResult.StartPostingAsyncOp(false);
3780 // Run the send with this asyncResult.
3781 errorCode = DoBeginSend(buffers, socketFlags, asyncResult);
3783 // We're not throwing, so finish the async op posting code so we can return to the user.
3784 // If the operation already finished, the callback will be called from here.
3785 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
3787 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3791 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSend", asyncResult);
3795 private SocketError DoBeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
3798 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " buffers:" + buffers);
3800 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
3801 // avoid a Socket leak in case of error.
3802 SocketError errorCode = SocketError.SocketError;
3805 // Set up asyncResult for overlapped WSASend.
3806 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
3807 asyncResult.SetUnmanagedStructures(buffers, ref Caches.SendOverlappedCache);
3809 GlobalLog.Print("BeginSend: asyncResult:" + ValidationHelper.HashString(asyncResult));
3811 // This can throw ObjectDisposedException.
3812 int bytesTransferred;
3813 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
3815 asyncResult.m_WSABuffers,
3816 asyncResult.m_WSABuffers.Length,
3817 out bytesTransferred,
3819 asyncResult.OverlappedHandle,
3822 if (errorCode!=SocketError.Success) {
3823 errorCode = (SocketError)Marshal.GetLastWin32Error();
3825 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
3829 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
3833 // if the asynchronous native call fails synchronously
3834 // we'll throw a SocketException
3836 if (errorCode != SocketError.Success)
3838 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3839 UpdateStatusAfterSocketError(errorCode);
3840 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSend", new SocketException(errorCode));
3848 Routine Description:
3850 EndSend - Called by user code addressFamilyter I/O is done or the user wants to wait.
3851 until Async completion, needed to retrieve error result from call
3855 AsyncResult - the AsyncResult Returned fron BeginSend call
3859 int - Number of bytes transferred
3863 /// <para>[To be supplied.]</para>
3867 public int EndSend(IAsyncResult asyncResult) {
3868 SocketError errorCode;
3869 int bytesTransferred = EndSend(asyncResult, out errorCode);
3870 if(errorCode != SocketError.Success){
3871 throw new SocketException(errorCode);
3873 return bytesTransferred;
3877 public int EndSend(IAsyncResult asyncResult, out SocketError errorCode) {
3878 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSend", asyncResult);
3880 throw new ObjectDisposedException(this.GetType().FullName);
3883 // parameter validation
3885 if (asyncResult==null) {
3886 throw new ArgumentNullException("asyncResult");
3888 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
3889 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
3890 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
3892 if (castedAsyncResult.EndCalled) {
3893 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSend"));
3896 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
3897 castedAsyncResult.EndCalled = true;
3898 castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3900 #if !FEATURE_PAL // perfcounter
3901 if (s_PerfCountersEnabled)
3903 if (bytesTransferred>0) {
3904 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
3905 if (Transport==TransportType.Udp) {
3906 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
3910 #endif //!FEATURE_PAL
3911 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSend() bytesTransferred:" + bytesTransferred.ToString());
3914 // if the asynchronous native call failed asynchronously
3915 // we'll throw a SocketException
3917 errorCode = (SocketError)castedAsyncResult.ErrorCode;
3918 if (errorCode != SocketError.Success) {
3920 // update our internal state after this socket error and throw
3922 UpdateStatusAfterSocketError(errorCode);
3923 if(s_LoggingEnabled){
3924 Logging.Exception(Logging.Sockets, this, "EndSend", new SocketException(errorCode));
3925 Logging.Exit(Logging.Sockets, this, "EndSend", 0);
3929 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSend", bytesTransferred);
3930 return bytesTransferred;
3936 /// <para>[To be supplied.]</para>
3938 public void EndSendFile(IAsyncResult asyncResult) {
3939 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSendFile", asyncResult);
3941 throw new ObjectDisposedException(this.GetType().FullName);
3944 #if FEATURE_PAL && !MONO
3945 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
3946 #endif // FEATURE_PAL && !MONO
3948 // parameter validation
3950 if (asyncResult==null) {
3951 throw new ArgumentNullException("asyncResult");
3953 TransmitFileOverlappedAsyncResult castedAsyncResult = asyncResult as TransmitFileOverlappedAsyncResult;
3954 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
3955 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
3957 if (castedAsyncResult.EndCalled) {
3958 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSendFile"));
3961 castedAsyncResult.InternalWaitForCompletion();
3962 castedAsyncResult.EndCalled = true;
3963 castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3965 if ((castedAsyncResult.Flags & (TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket) )!=0) {
3966 SetToDisconnected();
3967 m_RemoteEndPoint = null;
3971 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSendFile()");
3974 // if the asynchronous native call failed asynchronously
3975 // we'll throw a SocketException
3977 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
3979 // update our internal state after this socket error and throw
3981 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
3982 UpdateStatusAfterSocketError(socketException);
3983 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndSendFile", socketException);
3984 throw socketException;
3986 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSendFile","");
3989 #endif // !FEATURE_PAL
3994 Routine Description:
3996 BeginSendTo - Async implimentation of SendTo,
3998 This routine may go pending at which time,
3999 but any case the callback Delegate will be called upon completion
4003 WriteBuffer - Buffer to transmit
4004 Index - Offset into WriteBuffer to begin sending from
4005 Size - Size of Buffer to transmit
4006 Flags - Specific Socket flags to pass to winsock
4007 remoteEP - EndPoint to transmit To
4008 Callback - Delegate function that holds callback, called on completeion of I/O
4009 State - State used to track callback, set by caller, not required
4013 IAsyncResult - Async result used to retreive result
4017 /// <para>[To be supplied.]</para>
4019 [HostProtection(ExternalThreading=true)]
4020 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP, AsyncCallback callback, object state)
4023 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSendTo", "");
4026 throw new ObjectDisposedException(this.GetType().FullName);
4030 // parameter validation
4033 throw new ArgumentNullException("buffer");
4035 if (remoteEP==null) {
4036 throw new ArgumentNullException("remoteEP");
4038 if (offset<0 || offset>buffer.Length) {
4039 throw new ArgumentOutOfRangeException("offset");
4041 if (size<0 || size>buffer.Length-offset) {
4042 throw new ArgumentOutOfRangeException("size");
4045 // This will check the permissions for connect.
4046 EndPoint endPointSnapshot = remoteEP;
4047 SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, false);
4049 // Set up the async result and indicate to flow the context.
4050 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4051 asyncResult.StartPostingAsyncOp(false);
4054 DoBeginSendTo(buffer, offset, size, socketFlags, endPointSnapshot, socketAddress, asyncResult);
4056 // Finish, possibly posting the callback. The callback won't be posted before this point is reached.
4057 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
4059 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSendTo", asyncResult);
4063 private void DoBeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint endPointSnapshot, SocketAddress socketAddress, OverlappedAsyncResult asyncResult)
4065 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() size:" + size.ToString());
4066 EndPoint oldEndPoint = m_RightEndPoint;
4068 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4069 // avoid a Socket leak in case of error.
4070 SocketError errorCode = SocketError.SocketError;
4073 // Set up asyncResult for overlapped WSASendTo.
4074 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
4075 asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, false /* don't pin RemoteEP*/, ref Caches.SendOverlappedCache);
4077 if (m_RightEndPoint == null)
4079 m_RightEndPoint = endPointSnapshot;
4082 int bytesTransferred;
4083 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
4085 ref asyncResult.m_SingleBuffer,
4086 1, // only ever 1 buffer being sent
4087 out bytesTransferred,
4089 asyncResult.GetSocketAddressPtr(),
4090 asyncResult.SocketAddress.Size,
4091 asyncResult.OverlappedHandle,
4094 if (errorCode!=SocketError.Success) {
4095 errorCode = (SocketError)Marshal.GetLastWin32Error();
4097 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + size + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4099 catch (ObjectDisposedException)
4101 m_RightEndPoint = oldEndPoint;
4106 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4110 // if the asynchronous native call fails synchronously
4111 // we'll throw a SocketException
4113 if (errorCode!=SocketError.Success) {
4115 // update our internal state after this socket error and throw
4117 m_RightEndPoint = oldEndPoint;
4118 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
4119 SocketException socketException = new SocketException(errorCode);
4120 UpdateStatusAfterSocketError(socketException);
4121 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSendTo", socketException);
4122 throw socketException;
4125 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4130 Routine Description:
4132 EndSendTo - Called by user code addressFamilyter I/O is done or the user wants to wait.
4133 until Async completion, needed to retrieve error result from call
4137 AsyncResult - the AsyncResult Returned fron BeginSend call
4141 int - Number of bytes transferred
4145 /// <para>[To be supplied.]</para>
4147 public int EndSendTo(IAsyncResult asyncResult) {
4148 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSendTo", asyncResult);
4150 throw new ObjectDisposedException(this.GetType().FullName);
4153 // parameter validation
4155 if (asyncResult==null) {
4156 throw new ArgumentNullException("asyncResult");
4158 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
4159 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
4160 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
4162 if (castedAsyncResult.EndCalled) {
4163 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSendTo"));
4166 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
4167 castedAsyncResult.EndCalled = true;
4168 castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
4170 #if !FEATURE_PAL // perfcounter
4171 if (s_PerfCountersEnabled)
4173 if (bytesTransferred>0) {
4174 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
4175 if (Transport==TransportType.Udp) {
4176 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
4180 #endif //!FEATURE_PAL
4182 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSendTo() bytesTransferred:" + bytesTransferred.ToString());
4185 // if the asynchronous native call failed asynchronously
4186 // we'll throw a SocketException
4188 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
4190 // update our internal state after this socket error and throw
4192 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
4193 UpdateStatusAfterSocketError(socketException);
4194 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndSendTo", socketException);
4195 throw socketException;
4197 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSendTo", bytesTransferred);
4198 return bytesTransferred;
4204 Routine Description:
4206 BeginReceive - Async implimentation of Recv call,
4208 Called when we want to start an async receive.
4209 We kick off the receive, and if it completes synchronously we'll
4210 call the callback. Otherwise we'll return an IASyncResult, which
4211 the caller can use to wait on or retrieve the final status, as needed.
4213 Uses Winsock 2 overlapped I/O.
4217 ReadBuffer - status line that we wish to parse
4218 Index - Offset into ReadBuffer to begin reading from
4219 Size - Size of Buffer to recv
4220 Callback - Delegate function that holds callback, called on completeion of I/O
4221 State - State used to track callback, set by caller, not required
4225 IAsyncResult - Async result used to retreive result
4231 /// <para>[To be supplied.]</para>
4234 [HostProtection(ExternalThreading=true)]
4235 public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
4237 SocketError errorCode;
4238 IAsyncResult result = BeginReceive(buffer, offset, size, socketFlags, out errorCode, callback, state);
4239 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
4240 throw new SocketException(errorCode);
4247 [HostProtection(ExternalThreading=true)]
4248 public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
4251 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginReceive", "");
4254 throw new ObjectDisposedException(this.GetType().FullName);
4258 // parameter validation
4261 throw new ArgumentNullException("buffer");
4263 if (offset<0 || offset>buffer.Length) {
4264 throw new ArgumentOutOfRangeException("offset");
4266 if (size<0 || size>buffer.Length-offset) {
4267 throw new ArgumentOutOfRangeException("size");
4270 // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
4271 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4272 asyncResult.StartPostingAsyncOp(false);
4274 // Run the receive with this asyncResult.
4275 errorCode = DoBeginReceive(buffer, offset, size, socketFlags, asyncResult);
4277 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
4282 // We're not throwing, so finish the async op posting code so we can return to the user.
4283 // If the operation already finished, the callback will be called from here.
4284 asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
4287 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceive", asyncResult);
4291 internal IAsyncResult UnsafeBeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
4294 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "UnsafeBeginReceive", "");
4297 throw new ObjectDisposedException(this.GetType().FullName);
4300 // No need to flow the context.
4301 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4302 DoBeginReceive(buffer, offset, size, socketFlags, asyncResult);
4304 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "UnsafeBeginReceive", asyncResult);
4308 private SocketError DoBeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
4310 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() size:" + size.ToString());
4313 IntPtr lastHandle = m_Handle.DangerousGetHandle();
4315 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4316 // avoid a Socket leak in case of error.
4317 SocketError errorCode = SocketError.SocketError;
4320 // Set up asyncResult for overlapped WSARecv.
4321 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
4322 asyncResult.SetUnmanagedStructures(buffer, offset, size, null, false /* don't pin null RemoteEP*/, ref Caches.ReceiveOverlappedCache);
4324 // This can throw ObjectDisposedException.
4325 int bytesTransferred;
4326 errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv(
4328 ref asyncResult.m_SingleBuffer,
4330 out bytesTransferred,
4332 asyncResult.OverlappedHandle,
4335 if (errorCode!=SocketError.Success) {
4336 errorCode = (SocketError)Marshal.GetLastWin32Error();
4337 GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
4339 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " bytesTransferred:" + bytesTransferred.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4343 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4347 // if the asynchronous native call fails synchronously
4348 // we'll throw a SocketException
4350 if (errorCode != SocketError.Success)
4353 // update our internal state after this socket error and throw
4354 asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4355 UpdateStatusAfterSocketError(errorCode);
4356 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
4357 asyncResult.InvokeCallback(new SocketException(errorCode));
4362 m_LastReceiveHandle = lastHandle;
4363 m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
4364 m_LastReceiveTick = Environment.TickCount;
4372 [HostProtection(ExternalThreading=true)]
4373 public IAsyncResult BeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
4375 SocketError errorCode;
4376 IAsyncResult result = BeginReceive(buffers, socketFlags, out errorCode, callback, state);
4377 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
4378 throw new SocketException(errorCode);
4384 [HostProtection(ExternalThreading=true)]
4385 public IAsyncResult BeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
4388 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginReceive", "");
4391 throw new ObjectDisposedException(this.GetType().FullName);
4395 // parameter validation
4397 if (buffers==null) {
4398 throw new ArgumentNullException("buffers");
4401 if(buffers.Count == 0){
4402 throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
4405 // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
4406 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4407 asyncResult.StartPostingAsyncOp(false);
4409 // Run the receive with this asyncResult.
4410 errorCode = DoBeginReceive(buffers, socketFlags, asyncResult);
4412 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
4417 // We're not throwing, so finish the async op posting code so we can return to the user.
4418 // If the operation already finished, the callback will be called from here.
4419 asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
4422 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceive", asyncResult);
4426 private SocketError DoBeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
4429 IntPtr lastHandle = m_Handle.DangerousGetHandle();
4431 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4432 // avoid a Socket leak in case of error.
4433 SocketError errorCode = SocketError.SocketError;
4436 // Set up asyncResult for overlapped WSASend.
4437 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
4438 asyncResult.SetUnmanagedStructures(buffers, ref Caches.ReceiveOverlappedCache);
4440 // This can throw ObjectDisposedException.
4441 int bytesTransferred;
4442 errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv(
4444 asyncResult.m_WSABuffers,
4445 asyncResult.m_WSABuffers.Length,
4446 out bytesTransferred,
4448 asyncResult.OverlappedHandle,
4451 if (errorCode!=SocketError.Success) {
4452 errorCode = (SocketError)Marshal.GetLastWin32Error();
4453 GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
4455 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4459 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4463 // if the asynchronous native call fails synchronously
4464 // we'll throw a SocketException
4466 if (errorCode != SocketError.Success)
4469 // update our internal state after this socket error and throw
4470 asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4471 UpdateStatusAfterSocketError(errorCode);
4472 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
4477 m_LastReceiveHandle = lastHandle;
4478 m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
4479 m_LastReceiveTick = Environment.TickCount;
4487 private IntPtr m_LastReceiveHandle;
4488 private int m_LastReceiveThread;
4489 private int m_LastReceiveTick;
4496 Routine Description:
4498 EndReceive - Called when I/O is done or the user wants to wait. If
4499 the I/O isn't done, we'll wait for it to complete, and then we'll return
4500 the bytes of I/O done.
4504 AsyncResult - the AsyncResult Returned fron BeginSend call
4508 int - Number of bytes transferred
4513 /// <para>[To be supplied.]</para>
4515 public int EndReceive(IAsyncResult asyncResult) {
4516 SocketError errorCode;
4517 int bytesTransferred = EndReceive(asyncResult, out errorCode);
4518 if(errorCode != SocketError.Success){
4519 throw new SocketException(errorCode);
4521 return bytesTransferred;
4525 public int EndReceive(IAsyncResult asyncResult, out SocketError errorCode) {
4526 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceive", asyncResult);
4528 throw new ObjectDisposedException(this.GetType().FullName);
4531 // parameter validation
4533 if (asyncResult==null) {
4534 throw new ArgumentNullException("asyncResult");
4536 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
4537 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
4538 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
4540 if (castedAsyncResult.EndCalled) {
4541 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceive"));
4544 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
4545 castedAsyncResult.EndCalled = true;
4546 castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4548 #if !FEATURE_PAL // perfcounter
4549 if (s_PerfCountersEnabled)
4551 if (bytesTransferred>0) {
4552 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
4553 if (Transport==TransportType.Udp) {
4554 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
4558 #endif //!FEATURE_PAL
4563 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred.ToString());
4565 catch (ObjectDisposedException) { }
4569 // if the asynchronous native call failed asynchronously
4570 // we'll throw a SocketException
4572 errorCode = (SocketError)castedAsyncResult.ErrorCode;
4573 if (errorCode!=SocketError.Success) {
4575 // update our internal state after this socket error and throw
4577 UpdateStatusAfterSocketError(errorCode);
4578 if(s_LoggingEnabled){
4579 Logging.Exception(Logging.Sockets, this, "EndReceive", new SocketException(errorCode));
4580 Logging.Exit(Logging.Sockets, this, "EndReceive", 0);
4584 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceive", bytesTransferred);
4585 return bytesTransferred;
4590 public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state) {
4591 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "BeginReceiveMessageFrom", "");
4592 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() size:" + size.ToString());
4595 throw new ObjectDisposedException(this.GetType().FullName);
4598 throw new ArgumentNullException("buffer");
4600 if (remoteEP==null) {
4601 throw new ArgumentNullException("remoteEP");
4603 if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
4604 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
4605 remoteEP.AddressFamily, addressFamily), "remoteEP");
4607 if (offset<0 || offset>buffer.Length) {
4608 throw new ArgumentOutOfRangeException("offset");
4610 if (size<0 || size>buffer.Length-offset) {
4611 throw new ArgumentOutOfRangeException("size");
4613 if (m_RightEndPoint==null) {
4614 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
4618 // Set up the result and set it to collect the context.
4619 ReceiveMessageOverlappedAsyncResult asyncResult = new ReceiveMessageOverlappedAsyncResult(this, state, callback);
4620 asyncResult.StartPostingAsyncOp(false);
4622 // Start the ReceiveFrom.
4623 EndPoint oldEndPoint = m_RightEndPoint;
4625 // We don't do a CAS demand here because the contents of remoteEP aren't used by
4626 // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
4627 // with the right address family
4628 SocketAddress socketAddress = SnapshotAndSerialize(ref remoteEP);
4630 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4631 // avoid a Socket leak in case of error.
4632 SocketError errorCode = SocketError.SocketError;
4635 asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, socketFlags, ref Caches.ReceiveOverlappedCache);
4637 // save a copy of the original EndPoint in the asyncResult
4638 asyncResult.SocketAddressOriginal = remoteEP.Serialize();
4640 int bytesTransfered;
4642 SetReceivingPacketInformation();
4644 if (m_RightEndPoint == null)
4646 m_RightEndPoint = remoteEP;
4649 errorCode = (SocketError) WSARecvMsg(
4651 Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.m_MessageBuffer,0),
4652 out bytesTransfered,
4653 asyncResult.OverlappedHandle,
4656 if (errorCode!=SocketError.Success) {
4657 errorCode = (SocketError)Marshal.GetLastWin32Error();
4659 // I have guarantees from Brad Williamson that WSARecvMsg() will never return WSAEMSGSIZE directly, since a completion
4660 // is queued in this case. We wouldn't be able to handle this easily because of assumptions OverlappedAsyncResult
4661 // makes about whether there would be a completion or not depending on the error code. If WSAEMSGSIZE would have been
4662 // normally returned, it returns WSA_IO_PENDING instead. That same map is implemented here just in case.
4663 if (errorCode == SocketError.MessageSize)
4665 GlobalLog.Assert("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom()|Returned WSAEMSGSIZE!");
4666 errorCode = SocketError.IOPending;
4670 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() UnsafeNclNativeMethods.OSSOCK.WSARecvMsg returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4672 catch (ObjectDisposedException)
4674 m_RightEndPoint = oldEndPoint;
4679 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4683 // if the asynchronous native call fails synchronously
4684 // we'll throw a SocketException
4686 if (errorCode!=SocketError.Success)
4689 // update our internal state after this socket error and throw
4691 m_RightEndPoint = oldEndPoint;
4692 asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4693 SocketException socketException = new SocketException(errorCode);
4694 UpdateStatusAfterSocketError(socketException);
4695 if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "BeginReceiveMessageFrom", socketException);
4696 throw socketException;
4699 // Capture the context, maybe call the callback, and return.
4700 asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
4702 if (asyncResult.CompletedSynchronously && !asyncResult.SocketAddressOriginal.Equals(asyncResult.SocketAddress)) {
4704 remoteEP = remoteEP.Create(asyncResult.SocketAddress);
4710 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4711 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceiveMessageFrom", asyncResult);
4716 public int EndReceiveMessageFrom(IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation) {
4717 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceiveMessageFrom", asyncResult);
4719 throw new ObjectDisposedException(this.GetType().FullName);
4721 if (endPoint==null) {
4722 throw new ArgumentNullException("endPoint");
4724 if (!CanTryAddressFamily(endPoint.AddressFamily)) {
4725 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
4726 endPoint.AddressFamily, addressFamily), "endPoint");
4728 if (asyncResult==null) {
4729 throw new ArgumentNullException("asyncResult");
4731 ReceiveMessageOverlappedAsyncResult castedAsyncResult = asyncResult as ReceiveMessageOverlappedAsyncResult;
4732 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
4733 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
4735 if (castedAsyncResult.EndCalled) {
4736 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceiveMessageFrom"));
4739 SocketAddress socketAddressOriginal = SnapshotAndSerialize(ref endPoint);
4741 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
4742 castedAsyncResult.EndCalled = true;
4743 castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4745 // Update socket address size
4746 castedAsyncResult.SocketAddress.SetSize(castedAsyncResult.GetSocketAddressSizePtr());
4748 if (!socketAddressOriginal.Equals(castedAsyncResult.SocketAddress)) {
4750 endPoint = endPoint.Create(castedAsyncResult.SocketAddress);
4756 #if !FEATURE_PAL // perfcounter
4757 if (s_PerfCountersEnabled)
4759 if (bytesTransferred>0) {
4760 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
4761 if (Transport==TransportType.Udp) {
4762 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
4766 #endif //!FEATURE_PAL
4768 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceiveMessageFrom() bytesTransferred:" + bytesTransferred.ToString());
4771 // if the asynchronous native call failed asynchronously
4772 // we'll throw a SocketException
4774 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success && (SocketError)castedAsyncResult.ErrorCode != SocketError.MessageSize) {
4776 // update our internal state after this socket error and throw
4778 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
4779 UpdateStatusAfterSocketError(socketException);
4780 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndReceiveMessageFrom", socketException);
4781 throw socketException;
4784 socketFlags = castedAsyncResult.m_flags;
4785 ipPacketInformation = castedAsyncResult.m_IPPacketInformation;
4787 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceiveMessageFrom", bytesTransferred);
4788 return bytesTransferred;
4795 Routine Description:
4797 BeginReceiveFrom - Async implimentation of RecvFrom call,
4799 Called when we want to start an async receive.
4800 We kick off the receive, and if it completes synchronously we'll
4801 call the callback. Otherwise we'll return an IASyncResult, which
4802 the caller can use to wait on or retrieve the final status, as needed.
4804 Uses Winsock 2 overlapped I/O.
4808 ReadBuffer - status line that we wish to parse
4809 Index - Offset into ReadBuffer to begin reading from
4810 Request - Size of Buffer to recv
4811 Flags - Additonal Flags that may be passed to the underlying winsock call
4812 remoteEP - EndPoint that are to receive from
4813 Callback - Delegate function that holds callback, called on completeion of I/O
4814 State - State used to track callback, set by caller, not required
4818 IAsyncResult - Async result used to retreive result
4823 /// <para>[To be supplied.]</para>
4825 [HostProtection(ExternalThreading=true)]
4826 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state) {
4828 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "BeginReceiveFrom", "");
4831 throw new ObjectDisposedException(this.GetType().FullName);
4834 // parameter validation
4837 throw new ArgumentNullException("buffer");
4839 if (remoteEP==null) {
4840 throw new ArgumentNullException("remoteEP");
4842 if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
4843 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
4844 remoteEP.AddressFamily, addressFamily), "remoteEP");
4846 if (offset<0 || offset>buffer.Length) {
4847 throw new ArgumentOutOfRangeException("offset");
4849 if (size<0 || size>buffer.Length-offset) {
4850 throw new ArgumentOutOfRangeException("size");
4852 if (m_RightEndPoint==null) {
4853 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
4856 // We don't do a CAS demand here because the contents of remoteEP aren't used by
4857 // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
4858 // with the right address family
4859 SocketAddress socketAddress = SnapshotAndSerialize(ref remoteEP);
4861 // Set up the result and set it to collect the context.
4862 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4863 asyncResult.StartPostingAsyncOp(false);
4865 // Start the ReceiveFrom.
4866 DoBeginReceiveFrom(buffer, offset, size, socketFlags, remoteEP, socketAddress, asyncResult);
4868 // Capture the context, maybe call the callback, and return.
4869 asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
4871 if (asyncResult.CompletedSynchronously && !asyncResult.SocketAddressOriginal.Equals(asyncResult.SocketAddress)) {
4873 remoteEP = remoteEP.Create(asyncResult.SocketAddress);
4880 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceiveFrom", asyncResult);
4884 private void DoBeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint endPointSnapshot, SocketAddress socketAddress, OverlappedAsyncResult asyncResult)
4886 EndPoint oldEndPoint = m_RightEndPoint;
4887 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() size:" + size.ToString());
4889 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4890 // avoid a Socket leak in case of error.
4891 SocketError errorCode = SocketError.SocketError;
4894 // Set up asyncResult for overlapped WSARecvFrom.
4895 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
4896 asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, true /* pin remoteEP*/, ref Caches.ReceiveOverlappedCache);
4898 // save a copy of the original EndPoint in the asyncResult
4899 asyncResult.SocketAddressOriginal = endPointSnapshot.Serialize();
4901 if (m_RightEndPoint == null) {
4902 m_RightEndPoint = endPointSnapshot;
4905 int bytesTransferred;
4906 errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
4908 ref asyncResult.m_SingleBuffer,
4910 out bytesTransferred,
4912 asyncResult.GetSocketAddressPtr(),
4913 asyncResult.GetSocketAddressSizePtr(),
4914 asyncResult.OverlappedHandle,
4917 if (errorCode!=SocketError.Success) {
4918 errorCode = (SocketError)Marshal.GetLastWin32Error();
4920 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() UnsafeNclNativeMethods.OSSOCK.WSARecvFrom returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4922 catch (ObjectDisposedException)
4924 m_RightEndPoint = oldEndPoint;
4929 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4933 // if the asynchronous native call fails synchronously
4934 // we'll throw a SocketException
4936 if (errorCode!=SocketError.Success) {
4938 // update our internal state after this socket error and throw
4940 m_RightEndPoint = oldEndPoint;
4941 asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4942 SocketException socketException = new SocketException(errorCode);
4943 UpdateStatusAfterSocketError(socketException);
4944 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceiveFrom", socketException);
4945 throw socketException;
4948 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4954 Routine Description:
4956 EndReceiveFrom - Called when I/O is done or the user wants to wait. If
4957 the I/O isn't done, we'll wait for it to complete, and then we'll return
4958 the bytes of I/O done.
4962 AsyncResult - the AsyncResult Returned fron BeginReceiveFrom call
4966 int - Number of bytes transferred
4971 /// <para>[To be supplied.]</para>
4973 public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint) {
4974 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceiveFrom", asyncResult);
4976 throw new ObjectDisposedException(this.GetType().FullName);
4979 // parameter validation
4981 if (endPoint==null) {
4982 throw new ArgumentNullException("endPoint");
4984 if (!CanTryAddressFamily(endPoint.AddressFamily)) {
4985 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
4986 endPoint.AddressFamily, addressFamily), "endPoint");
4988 if (asyncResult==null) {
4989 throw new ArgumentNullException("asyncResult");
4991 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
4992 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
4993 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
4995 if (castedAsyncResult.EndCalled) {
4996 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceiveFrom"));
4999 SocketAddress socketAddressOriginal = SnapshotAndSerialize(ref endPoint);
5001 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
5002 castedAsyncResult.EndCalled = true;
5003 castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
5005 // Update socket address size
5006 castedAsyncResult.SocketAddress.SetSize(castedAsyncResult.GetSocketAddressSizePtr());
5008 if (!socketAddressOriginal.Equals(castedAsyncResult.SocketAddress)) {
5010 endPoint = endPoint.Create(castedAsyncResult.SocketAddress);
5016 #if !FEATURE_PAL // perfcounter
5017 if (s_PerfCountersEnabled)
5019 if (bytesTransferred>0) {
5020 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
5021 if (Transport==TransportType.Udp) {
5022 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
5026 #endif //!FEATURE_PAL
5028 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceiveFrom() bytesTransferred:" + bytesTransferred.ToString());
5031 // if the asynchronous native call failed asynchronously
5032 // we'll throw a SocketException
5034 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
5036 // update our internal state after this socket error and throw
5038 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
5039 UpdateStatusAfterSocketError(socketException);
5040 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndReceiveFrom", socketException);
5041 throw socketException;
5043 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceiveFrom", bytesTransferred);
5044 return bytesTransferred;
5050 Routine Description:
5052 BeginAccept - Does a async winsock accept, creating a new socket on success
5054 Works by creating a pending accept request the first time,
5055 and subsequent calls are queued so that when the first accept completes,
5056 the next accept can be resubmitted in the callback.
5057 this routine may go pending at which time,
5058 but any case the callback Delegate will be called upon completion
5062 Callback - Async Callback Delegate that is called upon Async Completion
5063 State - State used to track callback, set by caller, not required
5067 IAsyncResult - Async result used to retreive resultant new socket
5072 /// <para>[To be supplied.]</para>
5074 [HostProtection(ExternalThreading=true)]
5075 public IAsyncResult BeginAccept(AsyncCallback callback, object state) {
5080 return BeginAccept(0,callback,state);
5083 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginAccept", "");
5085 throw new ObjectDisposedException(this.GetType().FullName);
5088 // Set up the context flow.
5089 AcceptAsyncResult asyncResult = new AcceptAsyncResult(this, state, callback);
5090 asyncResult.StartPostingAsyncOp(false);
5093 DoBeginAccept(asyncResult);
5095 // Set up for return.
5096 asyncResult.FinishPostingAsyncOp(ref Caches.AcceptClosureCache);
5098 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginAccept", asyncResult);
5102 private void DoBeginAccept(LazyAsyncResult asyncResult)
5104 if (m_RightEndPoint==null) {
5105 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
5109 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
5113 // We keep a queue, which lists the set of requests that want to
5114 // be called when an accept queue completes. We call accept
5115 // once, and then as it completes asyncrounsly we pull the
5116 // requests out of the queue and call their callback.
5118 // We start by grabbing Critical Section, then attempt to
5119 // determine if we haven an empty Queue of Accept Sockets
5120 // or if its in a Callback on the Callback thread.
5122 // If its in the callback thread proocessing of the callback, then we
5123 // just need to notify the callback by adding an additional request
5126 // If its an empty queue, and its not in the callback, then
5127 // we just need to get the Accept going, make it go async
5130 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept()");
5132 bool needFinishedCall = false;
5133 SocketError errorCode = 0;
5135 Queue acceptQueue = GetAcceptQueue();
5138 if (acceptQueue.Count == 0)
5140 SocketAddress socketAddress = m_RightEndPoint.Serialize();
5142 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() queue is empty calling UnsafeNclNativeMethods.OSSOCK.accept");
5144 // Check if a socket is already available. We need to be non-blocking to do this.
5145 InternalSetBlocking(false);
5147 SafeCloseSocket acceptedSocketHandle = null;
5150 acceptedSocketHandle = SafeCloseSocket.Accept(
5152 socketAddress.m_Buffer,
5153 ref socketAddress.m_Size);
5154 errorCode = acceptedSocketHandle.IsInvalid ? (SocketError) Marshal.GetLastWin32Error() : SocketError.Success;
5156 catch (ObjectDisposedException)
5158 errorCode = SocketError.NotSocket;
5161 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() UnsafeNclNativeMethods.OSSOCK.accept returns:" + errorCode.ToString());
5163 if (errorCode != SocketError.WouldBlock)
5165 if (errorCode == SocketError.Success)
5167 asyncResult.Result = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress), false);
5171 asyncResult.ErrorCode = (int) errorCode;
5174 // Reset the blocking.
5175 InternalSetBlocking(true);
5177 // Continue outside the lock.
5178 needFinishedCall = true;
5182 // It would block. Start listening for accepts, and add ourselves to the queue.
5183 acceptQueue.Enqueue(asyncResult);
5184 if (!SetAsyncEventSelect(AsyncEventBits.FdAccept))
5186 acceptQueue.Dequeue();
5187 throw new ObjectDisposedException(this.GetType().FullName);
5192 acceptQueue.Enqueue(asyncResult);
5194 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() queue is not empty Count:" + acceptQueue.Count.ToString());
5198 if (needFinishedCall) {
5199 if (errorCode == SocketError.Success)
5201 // Completed synchronously, invoke the callback.
5202 asyncResult.InvokeCallback();
5207 // update our internal state after this socket error and throw
5209 SocketException socketException = new SocketException(errorCode);
5210 UpdateStatusAfterSocketError(socketException);
5211 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginAccept", socketException);
5212 throw socketException;
5216 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
5220 // This is a shortcut to AcceptCallback when called from dispose.
5221 // The only business is lock and complete all results with an error
5223 private void CompleteAcceptResults(object nullState)
5225 Queue acceptQueue = GetAcceptQueue();
5226 bool acceptNeeded = true;
5227 while (acceptNeeded)
5229 LazyAsyncResult asyncResult = null;
5232 // If the queue is empty, cancel the select and indicate not to loop anymore.
5233 if (acceptQueue.Count == 0)
5235 asyncResult = (LazyAsyncResult) acceptQueue.Dequeue();
5237 if (acceptQueue.Count == 0)
5238 acceptNeeded = false;
5241 // Notify about the completion outside the lock.
5243 asyncResult.InvokeCallback(new SocketException(SocketError.OperationAborted));
5246 // Exception from the user callback,
5247 // If we need to loop, offload to a different thread and re-throw for debugging
5249 ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(CompleteAcceptResults), null);
5256 // This method was originally in an AcceptAsyncResult class but that class got useless.
5257 private void AcceptCallback(object nullState)
5259 // We know we need to try completing an accept at first. Keep going until the queue is empty (inside the lock).
5260 // At that point, BeginAccept() takes control of restarting the pump if necessary.
5261 bool acceptNeeded = true;
5262 Queue acceptQueue = GetAcceptQueue();
5264 while (acceptNeeded)
5266 LazyAsyncResult asyncResult = null;
5267 SocketError errorCode = SocketError.OperationAborted;
5268 SocketAddress socketAddress = null;
5269 SafeCloseSocket acceptedSocket = null;
5270 Exception otherException = null;
5271 object result = null;
5276 // Accept Callback - called on the callback path, when we expect to release
5277 // an accept socket that winsock says has completed.
5279 // While we still have items in our Queued list of Accept Requests,
5280 // we recall the Winsock accept, to attempt to gather new
5281 // results, and then match them again the queued items,
5282 // when accept call returns would_block, we reinvoke ourselves
5283 // and rewait for the next asyc callback.
5287 // We may not have items in the queue because of possible ----
5288 // between re-entering this callback manually and from the thread pool.
5290 if (acceptQueue.Count == 0)
5293 // pick an element from the head of the list
5294 asyncResult = (LazyAsyncResult) acceptQueue.Peek();
5298 socketAddress = m_RightEndPoint.Serialize();
5302 // We know we're in non-blocking because of SetAsyncEventSelect().
5303 GlobalLog.Assert(!willBlockInternal, "Socket#{0}::AcceptCallback|Socket should be in non-blocking state.", ValidationHelper.HashString(this));
5304 acceptedSocket = SafeCloseSocket.Accept(
5306 socketAddress.m_Buffer,
5307 ref socketAddress.m_Size);
5309 errorCode = acceptedSocket.IsInvalid ? (SocketError) Marshal.GetLastWin32Error() : SocketError.Success;
5311 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::AcceptCallback() UnsafeNclNativeMethods.OSSOCK.accept returns:" + errorCode.ToString());
5313 catch (ObjectDisposedException)
5315 // Listener socket was closed.
5316 errorCode = SocketError.OperationAborted;
5318 catch (Exception exception)
5320 if (NclUtilities.IsFatal(exception)) throw;
5322 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::AcceptCallback() caught exception:" + exception.Message + " CleanedUp:" + CleanedUp);
5323 otherException = exception;
5327 if (errorCode == SocketError.WouldBlock && otherException == null)
5329 // The accept found no waiting connections, so start listening for more.
5332 m_AsyncEvent.Reset(); // reset event to wait for the next client.
5333 if (SetAsyncEventSelect(AsyncEventBits.FdAccept))
5336 catch (ObjectDisposedException)
5338 // Handle ---- with Dispose, m_AsyncEvent may have been Close()'d already.
5340 otherException = new ObjectDisposedException(this.GetType().FullName);
5343 // CreateAcceptSocket() must be done before InternalSetBlocking() so that the fixup is correct inside
5344 // UpdateAcceptSocket(). InternalSetBlocking() must happen in the lock.
5345 if (otherException != null)
5347 result = otherException;
5349 else if (errorCode == SocketError.Success)
5351 result = CreateAcceptSocket(acceptedSocket, m_RightEndPoint.Create(socketAddress), true);
5355 asyncResult.ErrorCode = (int) errorCode;
5358 // This request completed, so it can be taken off the queue.
5359 acceptQueue.Dequeue();
5361 // If the queue is empty, cancel the select and indicate not to loop anymore.
5362 if (acceptQueue.Count == 0)
5365 UnsetAsyncEventSelect();
5367 acceptNeeded = false;
5371 // Notify about the completion outside the lock.
5373 asyncResult.InvokeCallback(result);
5376 // Exception from the user callback,
5377 // If we need to loop, offload to a different thread and re-throw for debugging
5379 ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(AcceptCallback), nullState);
5389 private bool CanUseAcceptEx
5394 (Thread.CurrentThread.IsThreadPoolThread || SettingsSectionInternal.Section.AlwaysUseCompletionPortsForAccept || m_IsDisconnected);
5400 /// <para>[To be supplied.]</para>
5402 [HostProtection(ExternalThreading=true)]
5403 public IAsyncResult BeginAccept(int receiveSize, AsyncCallback callback, object state) {
5404 return BeginAccept(null,receiveSize,callback,state);
5407 /// This is the true async version that uses AcceptEx
5411 /// <para>[To be supplied.]</para>
5413 [HostProtection(ExternalThreading=true)]
5414 public IAsyncResult BeginAccept(Socket acceptSocket, int receiveSize, AsyncCallback callback, object state) {
5415 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginAccept", "");
5417 throw new ObjectDisposedException(this.GetType().FullName);
5421 // parameter validation
5423 if (receiveSize<0) {
5424 throw new ArgumentOutOfRangeException("size");
5427 // Set up the async result with flowing.
5428 AcceptOverlappedAsyncResult asyncResult = new AcceptOverlappedAsyncResult(this, state, callback);
5429 asyncResult.StartPostingAsyncOp(false);
5431 // Start the accept.
5432 DoBeginAccept(acceptSocket, receiveSize, asyncResult);
5434 // Finish the flow capture, maybe complete here.
5435 asyncResult.FinishPostingAsyncOp(ref Caches.AcceptClosureCache);
5437 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginAccept", asyncResult);
5441 private void DoBeginAccept(Socket acceptSocket, int receiveSize, AcceptOverlappedAsyncResult asyncResult)
5443 if (m_RightEndPoint==null) {
5444 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
5448 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
5451 // if a acceptSocket isn't specified, then we need to create it.
5452 if (acceptSocket == null) {
5453 acceptSocket = new Socket(addressFamily,socketType,protocolType);
5457 if (acceptSocket.m_RightEndPoint != null) {
5458 throw new InvalidOperationException(SR.GetString(SR.net_sockets_namedmustnotbebound, "acceptSocket"));
5461 asyncResult.AcceptSocket = acceptSocket;
5463 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() AcceptSocket:" + ValidationHelper.HashString(acceptSocket));
5465 //the buffer needs to contain the requested data plus room for two sockaddrs and 16 bytes
5466 //of associated data for each.
5467 int addressBufferSize = m_RightEndPoint.Serialize().Size + 16;
5468 byte[] buffer = new byte[receiveSize + ((addressBufferSize) * 2)];
5471 // Set up asyncResult for overlapped AcceptEx.
5472 // This call will use
5473 // completion ports on WinNT
5476 asyncResult.SetUnmanagedStructures(buffer, addressBufferSize);
5478 // This can throw ObjectDisposedException.
5479 int bytesTransferred;
5480 SocketError errorCode = SocketError.Success;
5483 acceptSocket.m_Handle,
5484 Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.Buffer, 0),
5488 out bytesTransferred,
5489 asyncResult.OverlappedHandle))
5491 errorCode = (SocketError)Marshal.GetLastWin32Error();
5493 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
5495 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() UnsafeNclNativeMethods.OSSOCK.AcceptEx returns:" + errorCode.ToString() + ValidationHelper.HashString(asyncResult));
5498 // if the asynchronous native call fails synchronously
5499 // we'll throw a SocketException
5501 if (errorCode!=SocketError.Success) {
5502 SocketException socketException = new SocketException(errorCode);
5503 UpdateStatusAfterSocketError(socketException);
5504 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginAccept", socketException);
5505 throw socketException;
5509 #endif // !FEATURE_PAL
5513 Routine Description:
5515 EndAccept - Called by user code addressFamilyter I/O is done or the user wants to wait.
5516 until Async completion, so it provides End handling for aync Accept calls,
5517 and retrieves new Socket object
5521 AsyncResult - the AsyncResult Returned fron BeginAccept call
5525 Socket - a valid socket if successful
5531 /// <para>[To be supplied.]</para>
5536 public Socket EndAccept(IAsyncResult asyncResult) {
5537 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndAccept", asyncResult);
5539 throw new ObjectDisposedException(this.GetType().FullName);
5543 if (asyncResult != null && (asyncResult is AcceptOverlappedAsyncResult)) {
5544 int bytesTransferred;
5546 return EndAccept(out buffer, out bytesTransferred, asyncResult);
5548 #endif // !FEATURE_PAL
5551 // parameter validation
5553 if (asyncResult==null) {
5554 throw new ArgumentNullException("asyncResult");
5557 AcceptAsyncResult castedAsyncResult = asyncResult as AcceptAsyncResult;
5558 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
5559 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
5561 if (castedAsyncResult.EndCalled) {
5562 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndAccept"));
5565 object result = castedAsyncResult.InternalWaitForCompletion();
5566 castedAsyncResult.EndCalled = true;
5568 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndAccept() acceptedSocket:" + ValidationHelper.HashString(result));
5571 // if the asynchronous native call failed asynchronously
5572 // we'll throw a SocketException
5574 Exception exception = result as Exception;
5575 if (exception != null)
5580 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
5582 // update our internal state after this socket error and throw
5584 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
5585 UpdateStatusAfterSocketError(socketException);
5586 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndAccept", socketException);
5587 throw socketException;
5590 Socket acceptedSocket = (Socket)result;
5592 if (s_LoggingEnabled) {
5593 Logging.PrintInfo(Logging.Sockets, acceptedSocket,
5594 SR.GetString(SR.net_log_socket_accepted, acceptedSocket.RemoteEndPoint, acceptedSocket.LocalEndPoint));
5595 Logging.Exit(Logging.Sockets, this, "EndAccept", result);
5597 return acceptedSocket;
5603 /// <para>[To be supplied.]</para>
5606 public Socket EndAccept( out byte[] buffer, IAsyncResult asyncResult) {
5607 int bytesTransferred;
5610 Socket socket = EndAccept(out innerBuffer,out bytesTransferred, asyncResult);
5611 buffer = new byte[bytesTransferred];
5612 Array.Copy(innerBuffer,buffer,bytesTransferred);
5618 /// <para>[To be supplied.]</para>
5621 public Socket EndAccept( out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) {
5622 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndAccept", asyncResult);
5624 throw new ObjectDisposedException(this.GetType().FullName);
5628 // parameter validation
5630 if (asyncResult==null) {
5631 throw new ArgumentNullException("asyncResult");
5633 AcceptOverlappedAsyncResult castedAsyncResult = asyncResult as AcceptOverlappedAsyncResult;
5634 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
5635 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
5637 if (castedAsyncResult.EndCalled) {
5638 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndAccept"));
5641 Socket socket = (Socket)castedAsyncResult.InternalWaitForCompletion();
5642 bytesTransferred = (int)castedAsyncResult.BytesTransferred;
5643 buffer = castedAsyncResult.Buffer;
5645 castedAsyncResult.EndCalled = true;
5647 #if !FEATURE_PAL // perfcounter
5648 if (s_PerfCountersEnabled)
5650 if (bytesTransferred>0) {
5651 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
5656 // if the asynchronous native call failed asynchronously
5657 // we'll throw a SocketException
5659 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
5661 // update our internal state after this socket error and throw
5663 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
5664 UpdateStatusAfterSocketError(socketException);
5665 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndAccept", socketException);
5666 throw socketException;
5672 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());
5674 catch (ObjectDisposedException) { }
5677 if (s_LoggingEnabled) {
5678 Logging.PrintInfo(Logging.Sockets, socket, SR.GetString(SR.net_log_socket_accepted, socket.RemoteEndPoint, socket.LocalEndPoint));
5679 Logging.Exit(Logging.Sockets, this, "EndAccept", socket);
5684 #endif // !FEATURE_PAL
5692 /// Disables sends and receives on a socket.
5695 public void Shutdown(SocketShutdown how) {
5696 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Shutdown", how);
5698 throw new ObjectDisposedException(this.GetType().FullName);
5701 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Shutdown() how:" + how.ToString());
5703 // This can throw ObjectDisposedException.
5704 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int) how);
5707 // if the native call fails we'll throw a SocketException
5709 errorCode = errorCode!=SocketError.SocketError ? SocketError.Success : (SocketError)Marshal.GetLastWin32Error();
5711 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Shutdown() UnsafeNclNativeMethods.OSSOCK.shutdown returns errorCode:" + errorCode);
5714 // skip good cases: success, socket already closed
5716 if (errorCode!=SocketError.Success && errorCode!=SocketError.NotSocket) {
5718 // update our internal state after this socket error and throw
5720 SocketException socketException = new SocketException(errorCode);
5721 UpdateStatusAfterSocketError(socketException);
5722 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Shutdown", socketException );
5723 throw socketException;
5726 SetToDisconnected();
5727 InternalSetBlocking(willBlockInternal);
5728 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Shutdown", "");
5733 //************* internal and private properties *************************
5735 private static object InternalSyncObject {
5737 if (s_InternalSyncObject == null) {
5738 object o = new object();
5739 Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
5741 return s_InternalSyncObject;
5746 private CacheSet Caches
5750 if (m_Caches == null)
5752 // It's not too bad if extra of these are created and lost.
5753 m_Caches = new CacheSet();
5759 private void EnsureDynamicWinsockMethods()
5761 if (m_DynamicWinsockMethods == null)
5763 m_DynamicWinsockMethods = DynamicWinsockMethods.GetMethods(addressFamily, socketType, protocolType);
5767 private bool AcceptEx(SafeCloseSocket listenSocketHandle,
5768 SafeCloseSocket acceptSocketHandle,
5771 int localAddressLength,
5772 int remoteAddressLength,
5773 out int bytesReceived,
5774 SafeHandle overlapped)
5776 EnsureDynamicWinsockMethods();
5777 AcceptExDelegate acceptEx = m_DynamicWinsockMethods.GetDelegate<AcceptExDelegate>(listenSocketHandle);
5779 return acceptEx(listenSocketHandle,
5784 remoteAddressLength,
5789 internal void GetAcceptExSockaddrs(IntPtr buffer,
5790 int receiveDataLength,
5791 int localAddressLength,
5792 int remoteAddressLength,
5793 out IntPtr localSocketAddress,
5794 out int localSocketAddressLength,
5795 out IntPtr remoteSocketAddress,
5796 out int remoteSocketAddressLength)
5798 EnsureDynamicWinsockMethods();
5799 GetAcceptExSockaddrsDelegate getAcceptExSockaddrs = m_DynamicWinsockMethods.GetDelegate<GetAcceptExSockaddrsDelegate>(m_Handle);
5801 getAcceptExSockaddrs(buffer,
5804 remoteAddressLength,
5805 out localSocketAddress,
5806 out localSocketAddressLength,
5807 out remoteSocketAddress,
5808 out remoteSocketAddressLength);
5811 private bool DisconnectEx(SafeCloseSocket socketHandle, SafeHandle overlapped, int flags, int reserved)
5813 EnsureDynamicWinsockMethods();
5814 DisconnectExDelegate disconnectEx = m_DynamicWinsockMethods.GetDelegate<DisconnectExDelegate>(socketHandle);
5816 return disconnectEx(socketHandle, overlapped, flags, reserved);
5819 private bool DisconnectEx_Blocking(IntPtr socketHandle, IntPtr overlapped, int flags, int reserved)
5821 EnsureDynamicWinsockMethods();
5822 DisconnectExDelegate_Blocking disconnectEx_Blocking = m_DynamicWinsockMethods.GetDelegate<DisconnectExDelegate_Blocking>(m_Handle);
5824 return disconnectEx_Blocking(socketHandle, overlapped, flags, reserved);
5827 private bool ConnectEx(SafeCloseSocket socketHandle,
5828 IntPtr socketAddress,
5829 int socketAddressSize,
5833 SafeHandle overlapped)
5835 EnsureDynamicWinsockMethods();
5836 ConnectExDelegate connectEx = m_DynamicWinsockMethods.GetDelegate<ConnectExDelegate>(socketHandle);
5838 return connectEx(socketHandle, socketAddress, socketAddressSize, buffer, dataLength, out bytesSent, overlapped);
5841 private SocketError WSARecvMsg(SafeCloseSocket socketHandle, IntPtr msg, out int bytesTransferred, SafeHandle overlapped, IntPtr completionRoutine)
5843 EnsureDynamicWinsockMethods();
5844 WSARecvMsgDelegate recvMsg = m_DynamicWinsockMethods.GetDelegate<WSARecvMsgDelegate>(socketHandle);
5846 return recvMsg(socketHandle, msg, out bytesTransferred, overlapped, completionRoutine);
5849 private SocketError WSARecvMsg_Blocking(IntPtr socketHandle, IntPtr msg, out int bytesTransferred, IntPtr overlapped, IntPtr completionRoutine)
5851 EnsureDynamicWinsockMethods();
5852 WSARecvMsgDelegate_Blocking recvMsg_Blocking = m_DynamicWinsockMethods.GetDelegate<WSARecvMsgDelegate_Blocking>(m_Handle);
5854 return recvMsg_Blocking(socketHandle, msg, out bytesTransferred, overlapped, completionRoutine);
5857 private bool TransmitPackets(SafeCloseSocket socketHandle, IntPtr packetArray, int elementCount, int sendSize, SafeNativeOverlapped overlapped, TransmitFileOptions flags)
5859 EnsureDynamicWinsockMethods();
5860 TransmitPacketsDelegate transmitPackets = m_DynamicWinsockMethods.GetDelegate<TransmitPacketsDelegate>(socketHandle);
5862 return transmitPackets(socketHandle, packetArray, elementCount, sendSize, overlapped, flags);
5865 private Queue GetAcceptQueue() {
5866 if (m_AcceptQueueOrConnectResult == null)
5867 Interlocked.CompareExchange(ref m_AcceptQueueOrConnectResult, new Queue(16), null);
5868 return (Queue)m_AcceptQueueOrConnectResult;
5872 internal bool CleanedUp {
5874 return (m_IntCleanedUp == 1);
5879 internal TransportType Transport {
5882 protocolType==Sockets.ProtocolType.Tcp ?
5884 protocolType==Sockets.ProtocolType.Udp ?
5891 //************* internal and private methods *************************
5895 private void CheckSetOptionPermissions(SocketOptionLevel optionLevel, SocketOptionName optionName) {
5896 // freely allow only those below
5897 if ( !(optionLevel == SocketOptionLevel.Tcp &&
5898 (optionName == SocketOptionName.NoDelay ||
5899 optionName == SocketOptionName.BsdUrgent ||
5900 optionName == SocketOptionName.Expedited))
5902 !(optionLevel == SocketOptionLevel.Udp &&
5903 (optionName == SocketOptionName.NoChecksum||
5904 optionName == SocketOptionName.ChecksumCoverage))
5906 !(optionLevel == SocketOptionLevel.Socket &&
5907 (optionName == SocketOptionName.KeepAlive ||
5908 optionName == SocketOptionName.Linger ||
5909 optionName == SocketOptionName.DontLinger ||
5910 optionName == SocketOptionName.SendBuffer ||
5911 optionName == SocketOptionName.ReceiveBuffer ||
5912 optionName == SocketOptionName.SendTimeout ||
5913 optionName == SocketOptionName.ExclusiveAddressUse ||
5914 optionName == SocketOptionName.ReceiveTimeout))
5916 //ipv6 protection level
5917 !(optionLevel == SocketOptionLevel.IPv6 &&
5918 optionName == (SocketOptionName)23)){
5920 ExceptionHelper.UnmanagedPermission.Demand();
5924 private SocketAddress SnapshotAndSerialize(ref EndPoint remoteEP)
5926 IPEndPoint ipSnapshot = remoteEP as IPEndPoint;
5928 if (ipSnapshot != null)
5930 ipSnapshot = ipSnapshot.Snapshot();
5931 remoteEP = RemapIPEndPoint(ipSnapshot);
5934 return CallSerializeCheckDnsEndPoint(remoteEP);
5937 // Give a nicer exception for DnsEndPoint in cases where it is not supported
5938 private SocketAddress CallSerializeCheckDnsEndPoint(EndPoint remoteEP)
5940 if (remoteEP is DnsEndPoint)
5942 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_dnsendpoint, "remoteEP"), "remoteEP");
5945 return remoteEP.Serialize();
5948 // DualMode: Automatically re-map IPv4 addresses to IPv6 addresses
5949 private IPEndPoint RemapIPEndPoint(IPEndPoint input)
5951 if (input.AddressFamily == AddressFamily.InterNetwork && IsDualMode)
5953 return new IPEndPoint(input.Address.MapToIPv6(), input.Port);
5959 // socketAddress must always be the result of remoteEP.Serialize()
5961 private SocketAddress CheckCacheRemote(ref EndPoint remoteEP, bool isOverwrite)
5963 IPEndPoint ipSnapshot = remoteEP as IPEndPoint;
5965 if (ipSnapshot != null)
5967 // Snapshot to avoid external tampering and malicious derivations if IPEndPoint
5968 ipSnapshot = ipSnapshot.Snapshot();
5969 // DualMode: Do the security check on the user input address, but return an IPEndPoint
5970 // mapped to an IPv6 address.
5971 remoteEP = RemapIPEndPoint(ipSnapshot);
5974 // This doesn't use SnapshotAndSerialize() because we need the ipSnapshot later.
5975 SocketAddress socketAddress = CallSerializeCheckDnsEndPoint(remoteEP);
5977 // We remember the first peer we have communicated with
5978 SocketAddress permittedRemoteAddress = m_PermittedRemoteAddress;
5979 if (permittedRemoteAddress != null && permittedRemoteAddress.Equals(socketAddress))
5981 return permittedRemoteAddress;
5985 // for now SocketPermission supports only IPEndPoint
5987 if (ipSnapshot != null)
5990 // create the permissions the user would need for the call
5992 SocketPermission socketPermission
5993 = new SocketPermission(
5994 NetworkAccess.Connect,
5996 ipSnapshot.Address.ToString(),
6001 socketPermission.Demand();
6005 // for V1 we will demand permission to run UnmanagedCode for
6006 // an EndPoint that is not an IPEndPoint until we figure out how these fit
6007 // into the whole picture of SocketPermission
6010 ExceptionHelper.UnmanagedPermission.Demand();
6012 //cache only the first peer we communicated with
6013 if (m_PermittedRemoteAddress == null || isOverwrite) {
6014 m_PermittedRemoteAddress = socketAddress;
6017 return socketAddress;
6021 internal static void InitializeSockets() {
6022 if (!s_Initialized) {
6023 lock(InternalSyncObject){
6024 if (!s_Initialized) {
6027 WSAData wsaData = new WSAData();
6029 SocketError errorCode =
6030 UnsafeNclNativeMethods.OSSOCK.WSAStartup(
6031 (short)0x0202, // we need 2.2
6034 if (errorCode!=SocketError.Success) {
6036 // failed to initialize, throw
6038 // WSAStartup does not set LastWin32Error
6039 throw new SocketException(errorCode);
6045 // we're on WinNT4 or greater, we could use CompletionPort if we
6046 // wanted. check if the user has disabled this functionality in
6047 // the registry, otherwise use CompletionPort.
6051 BooleanSwitch disableCompletionPortSwitch = new BooleanSwitch("DisableNetCompletionPort", "System.Net disabling of Completion Port");
6054 // the following will be true if they've disabled the completionPort
6056 UseOverlappedIO = disableCompletionPortSwitch.Enabled;
6063 ipv4 = IsProtocolSupported (System.Net.NetworkInformation.NetworkInterfaceComponent.IPv4);
6064 ipv6 = IsProtocolSupported (System.Net.NetworkInformation.NetworkInterfaceComponent.IPv6);
6066 SafeCloseSocket.InnerSafeCloseSocket socketV4 =
6067 UnsafeNclNativeMethods.OSSOCK.WSASocket(
6068 AddressFamily.InterNetwork,
6073 (SocketConstructorFlags) 0);
6074 if (socketV4.IsInvalid) {
6075 errorCode = (SocketError) Marshal.GetLastWin32Error();
6076 if (errorCode == SocketError.AddressFamilyNotSupported)
6082 SafeCloseSocket.InnerSafeCloseSocket socketV6 =
6083 UnsafeNclNativeMethods.OSSOCK.WSASocket(
6084 AddressFamily.InterNetworkV6,
6089 (SocketConstructorFlags) 0);
6090 if (socketV6.IsInvalid) {
6091 errorCode = (SocketError) Marshal.GetLastWin32Error();
6092 if (errorCode == SocketError.AddressFamilyNotSupported)
6102 #if COMNET_DISABLEIPV6
6104 // Turn off IPv6 support
6109 // Now read the switch as the final check: by checking the current value for IPv6
6110 // support we may be able to avoid a painful configuration file read.
6113 s_OSSupportsIPv6 = true;
6114 ipv6 = SettingsSectionInternal.Section.Ipv6Enabled;
6119 // Update final state
6121 s_SupportsIPv4 = ipv4;
6122 s_SupportsIPv6 = ipv6;
6124 #else //!FEATURE_PAL
6126 s_SupportsIPv4 = true;
6127 s_SupportsIPv6 = false;
6129 #endif //!FEATURE_PAL
6131 // Cache some settings locally.
6134 #if !FEATURE_PAL // perfcounter
6135 s_PerfCountersEnabled = NetworkingPerfCounters.Instance.Enabled;
6139 s_Initialized = true;
6146 internal void InternalConnect(EndPoint remoteEP)
6148 EndPoint endPointSnapshot = remoteEP;
6149 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
6150 DoConnect(endPointSnapshot, socketAddress);
6153 private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
6155 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Connect", endPointSnapshot);
6157 // This can throw ObjectDisposedException.
6158 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAConnect(
6159 m_Handle.DangerousGetHandle(),
6160 socketAddress.m_Buffer,
6161 socketAddress.m_Size,
6170 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalConnect() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.WSAConnect returns errorCode:" + errorCode);
6172 catch (ObjectDisposedException) { }
6176 // if the native call fails we'll throw a SocketException
6178 if (errorCode!=SocketError.Success) {
6180 // update our internal state after this socket error and throw
6182 SocketException socketException = new SocketException(endPointSnapshot);
6183 UpdateStatusAfterSocketError(socketException);
6184 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Connect", socketException);
6185 throw socketException;
6188 if (m_RightEndPoint==null) {
6190 // save a copy of the EndPoint so we can use it for Create()
6192 m_RightEndPoint = endPointSnapshot;
6195 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoConnect() connection to:" + endPointSnapshot.ToString());
6198 // update state and performance counter
6201 if (s_LoggingEnabled) {
6202 Logging.PrintInfo(Logging.Sockets, this, SR.GetString(SR.net_log_socket_connected, LocalEndPoint, RemoteEndPoint));
6203 Logging.Exit(Logging.Sockets, this, "Connect", "");
6208 protected virtual void Dispose(bool disposing)
6217 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() disposing:true CleanedUp:" + CleanedUp.ToString());
6218 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Dispose", null);
6220 catch (Exception exception)
6222 if (NclUtilities.IsFatal(exception)) throw;
6225 // make sure we're the first call to Dispose and no SetAsyncEventSelect is in progress
6227 while ((last = Interlocked.CompareExchange(ref m_IntCleanedUp, 1, 0)) == 2)
6234 if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "Dispose", null);
6236 catch (Exception exception)
6238 if (NclUtilities.IsFatal(exception)) throw;
6243 SetToDisconnected();
6245 AsyncEventBits pendingAsync = AsyncEventBits.FdNone;
6246 if (m_BlockEventBits != AsyncEventBits.FdNone)
6248 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Pending nonblocking operations! m_BlockEventBits:" + m_BlockEventBits.ToString());
6249 UnsetAsyncEventSelect();
6250 if (m_BlockEventBits == AsyncEventBits.FdConnect)
6252 LazyAsyncResult connectResult = m_AcceptQueueOrConnectResult as LazyAsyncResult;
6253 if (connectResult != null && !connectResult.InternalPeekCompleted)
6254 pendingAsync = AsyncEventBits.FdConnect;
6256 else if (m_BlockEventBits == AsyncEventBits.FdAccept)
6258 Queue acceptQueue = m_AcceptQueueOrConnectResult as Queue;
6259 if (acceptQueue != null && acceptQueue.Count != 0)
6260 pendingAsync = AsyncEventBits.FdAccept;
6264 #if SOCKETTHREADPOOL
6265 if (m_BoundToThreadPool) SocketThreadPool.UnBindHandle(m_Handle);
6267 // Close the handle in one of several ways depending on the timeout.
6268 // Ignore ObjectDisposedException just in case the handle somehow gets disposed elsewhere.
6271 int timeout = m_CloseTimeout;
6275 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Calling m_Handle.Dispose()");
6280 SocketError errorCode;
6282 // Go to blocking mode. We know no WSAEventSelect is pending because of the lock and UnsetAsyncEventSelect() above.
6283 if (!willBlock || !willBlockInternal)
6285 int nonBlockCmd = 0;
6286 errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
6288 IoctlSocketConstants.FIONBIO,
6290 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") ioctlsocket(FIONBIO):" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
6295 // Close with existing user-specified linger option.
6296 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Calling m_Handle.CloseAsIs()");
6297 m_Handle.CloseAsIs();
6301 // Since our timeout is in ms and linger is in seconds, implement our own sortof linger here.
6302 errorCode = UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int) SocketShutdown.Send);
6303 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") shutdown():" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
6305 // This should give us a timeout in milliseconds.
6306 errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6308 SocketOptionLevel.Socket,
6309 SocketOptionName.ReceiveTimeout,
6312 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") setsockopt():" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
6314 if (errorCode != SocketError.Success)
6322 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), null, 0, SocketFlags.None);
6324 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") recv():" + errorCode.ToString());
6326 if (errorCode != (SocketError) 0)
6328 // We got a timeout - abort.
6333 // We got a FIN or data. Use ioctlsocket to find out which.
6334 int dataAvailable = 0;
6335 errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
6337 IoctlSocketConstants.FIONREAD,
6339 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") ioctlsocket(FIONREAD):" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
6341 if (errorCode != SocketError.Success || dataAvailable != 0)
6343 // If we have data or don't know, safest thing is to reset.
6348 // We got a FIN. It'd be nice to block for the remainder of the timeout for the handshake to finsh.
6349 // Since there's no real way to do that, close the socket with the user's preferences. This lets
6350 // the user decide how best to handle this case via the linger options.
6351 m_Handle.CloseAsIs();
6358 catch (ObjectDisposedException)
6360 GlobalLog.Assert("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ")", "Closing the handle threw ObjectDisposedException.");
6364 // Clear out the Overlapped caches.
6365 if (m_Caches != null)
6367 OverlappedCache.InterlockedFree(ref m_Caches.SendOverlappedCache);
6368 OverlappedCache.InterlockedFree(ref m_Caches.ReceiveOverlappedCache);
6372 if (pendingAsync == AsyncEventBits.FdConnect)
6374 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() QueueUserWorkItem for ConnectCallback");
6375 // This will try to complete connectResult on a different thread
6376 ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(((LazyAsyncResult)m_AcceptQueueOrConnectResult).InvokeCallback), new SocketException(SocketError.OperationAborted));
6378 else if (pendingAsync == AsyncEventBits.FdAccept)
6380 // This will try to complete all acceptResults on a different thread
6381 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() QueueUserWorkItem for AcceptCallback");
6382 ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(CompleteAcceptResults), null);
6385 if (m_AsyncEvent != null)
6387 m_AsyncEvent.Close();
6392 public void Dispose() {
6394 GC.SuppressFinalize(this);
6402 // this version does not throw.
6403 internal void InternalShutdown(SocketShutdown how) {
6404 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalShutdown() how:" + how.ToString());
6406 if (CleanedUp || m_Handle.IsInvalid) {
6412 UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int)how);
6414 catch (ObjectDisposedException) { }
6417 // Set the socket option to begin receiving packet information if it has not been
6418 // set for this socket previously
6419 internal void SetReceivingPacketInformation()
6421 if (!m_ReceivingPacketInformation)
6423 // DualMode: When bound to IPv6Any you must enable both socket options.
6424 // When bound to an IPv4 mapped IPv6 address you must enable the IPv4 socket option.
6425 IPEndPoint ipEndPoint = m_RightEndPoint as IPEndPoint;
6426 IPAddress boundAddress = (ipEndPoint != null ? ipEndPoint.Address : null);
6427 Debug.Assert(boundAddress != null, "Not Bound");
6428 if (this.addressFamily == AddressFamily.InterNetwork
6429 || (boundAddress != null && IsDualMode
6430 && (boundAddress.IsIPv4MappedToIPv6 || boundAddress.Equals(IPAddress.IPv6Any))))
6432 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
6435 if (this.addressFamily == AddressFamily.InterNetworkV6
6436 && (boundAddress == null || !boundAddress.IsIPv4MappedToIPv6))
6438 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true);
6441 m_ReceivingPacketInformation = true;
6445 internal unsafe void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue, bool silent) {
6446 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() optionLevel:" + optionLevel + " optionName:" + optionName + " optionValue:" + optionValue + " silent:" + silent);
6447 if (silent && (CleanedUp || m_Handle.IsInvalid)) {
6448 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() skipping the call");
6451 SocketError errorCode = SocketError.Success;
6453 // This can throw ObjectDisposedException.
6454 errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6461 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
6464 if (silent && m_Handle.IsInvalid) {
6470 // Keep the internal state in [....] if the user manually resets this
6471 if (optionName == SocketOptionName.PacketInformation && optionValue == 0 &&
6472 errorCode == SocketError.Success)
6474 m_ReceivingPacketInformation = false;
6482 // if the native call fails we'll throw a SocketException
6484 if (errorCode==SocketError.SocketError) {
6486 // update our internal state after this socket error and throw
6488 SocketException socketException = new SocketException();
6489 UpdateStatusAfterSocketError(socketException);
6490 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SetSocketOption", socketException);
6491 throw socketException;
6495 private void setMulticastOption(SocketOptionName optionName, MulticastOption MR) {
6496 IPMulticastRequest ipmr = new IPMulticastRequest();
6498 ipmr.MulticastAddress = unchecked((int)MR.Group.m_Address);
6501 if(MR.LocalAddress != null){
6502 ipmr.InterfaceAddress = unchecked((int)MR.LocalAddress.m_Address);
6504 else { //this structure works w/ interfaces as well
6505 int ifIndex =IPAddress.HostToNetworkOrder(MR.InterfaceIndex);
6506 ipmr.InterfaceAddress = unchecked((int)ifIndex);
6510 ipmr.MulticastAddress = (int) (((uint) ipmr.MulticastAddress << 24) |
6511 (((uint) ipmr.MulticastAddress & 0x0000FF00) << 8) |
6512 (((uint) ipmr.MulticastAddress >> 8) & 0x0000FF00) |
6513 ((uint) ipmr.MulticastAddress >> 24));
6515 if(MR.LocalAddress != null){
6516 ipmr.InterfaceAddress = (int) (((uint) ipmr.InterfaceAddress << 24) |
6517 (((uint) ipmr.InterfaceAddress & 0x0000FF00) << 8) |
6518 (((uint) ipmr.InterfaceAddress >> 8) & 0x0000FF00) |
6519 ((uint) ipmr.InterfaceAddress >> 24));
6523 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setMulticastOption(): optionName:" + optionName.ToString() + " MR:" + MR.ToString() + " ipmr:" + ipmr.ToString() + " IPMulticastRequest.Size:" + IPMulticastRequest.Size.ToString());
6525 // This can throw ObjectDisposedException.
6526 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6528 SocketOptionLevel.IP,
6531 IPMulticastRequest.Size);
6533 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setMulticastOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
6536 // if the native call fails we'll throw a SocketException
6538 if (errorCode==SocketError.SocketError) {
6540 // update our internal state after this socket error and throw
6542 SocketException socketException = new SocketException();
6543 UpdateStatusAfterSocketError(socketException);
6544 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setMulticastOption", socketException);
6545 throw socketException;
6552 /// IPv6 setsockopt for JOIN / LEAVE multicast group
6555 private void setIPv6MulticastOption(SocketOptionName optionName, IPv6MulticastOption MR) {
6556 IPv6MulticastRequest ipmr = new IPv6MulticastRequest();
6558 ipmr.MulticastAddress = MR.Group.GetAddressBytes();
6559 ipmr.InterfaceIndex = unchecked((int)MR.InterfaceIndex);
6561 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setIPv6MulticastOption(): optionName:" + optionName.ToString() + " MR:" + MR.ToString() + " ipmr:" + ipmr.ToString() + " IPv6MulticastRequest.Size:" + IPv6MulticastRequest.Size.ToString());
6563 // This can throw ObjectDisposedException.
6564 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6566 SocketOptionLevel.IPv6,
6569 IPv6MulticastRequest.Size);
6571 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setIPv6MulticastOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
6574 // if the native call fails we'll throw a SocketException
6576 if (errorCode==SocketError.SocketError) {
6578 // update our internal state after this socket error and throw
6580 SocketException socketException = new SocketException();
6581 UpdateStatusAfterSocketError(socketException);
6582 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setIPv6MulticastOption", socketException);
6583 throw socketException;
6587 private void setLingerOption(LingerOption lref) {
6588 Linger lngopt = new Linger();
6589 lngopt.OnOff = lref.Enabled ? (ushort)1 : (ushort)0;
6590 lngopt.Time = (ushort)lref.LingerTime;
6592 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setLingerOption(): lref:" + lref.ToString());
6594 // This can throw ObjectDisposedException.
6595 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6597 SocketOptionLevel.Socket,
6598 SocketOptionName.Linger,
6602 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setLingerOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
6605 // if the native call fails we'll throw a SocketException
6607 if (errorCode==SocketError.SocketError) {
6609 // update our internal state after this socket error and throw
6611 SocketException socketException = new SocketException();
6612 UpdateStatusAfterSocketError(socketException);
6613 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setLingerOption", socketException);
6614 throw socketException;
6618 private LingerOption getLingerOpt() {
6619 Linger lngopt = new Linger();
6622 // This can throw ObjectDisposedException.
6623 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
6625 SocketOptionLevel.Socket,
6626 SocketOptionName.Linger,
6630 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getLingerOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
6633 // if the native call fails we'll throw a SocketException
6635 if (errorCode==SocketError.SocketError) {
6637 // update our internal state after this socket error and throw
6639 SocketException socketException = new SocketException();
6640 UpdateStatusAfterSocketError(socketException);
6641 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getLingerOpt", socketException);
6642 throw socketException;
6645 LingerOption lingerOption = new LingerOption(lngopt.OnOff!=0, (int)lngopt.Time);
6646 return lingerOption;
6649 private MulticastOption getMulticastOpt(SocketOptionName optionName) {
6650 IPMulticastRequest ipmr = new IPMulticastRequest();
6651 int optlen = IPMulticastRequest.Size;
6653 // This can throw ObjectDisposedException.
6654 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
6656 SocketOptionLevel.IP,
6661 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getMulticastOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
6664 // if the native call fails we'll throw a SocketException
6666 if (errorCode==SocketError.SocketError) {
6668 // update our internal state after this socket error and throw
6670 SocketException socketException = new SocketException();
6671 UpdateStatusAfterSocketError(socketException);
6672 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getMulticastOpt", socketException);
6673 throw socketException;
6677 ipmr.MulticastAddress = (int) (((uint) ipmr.MulticastAddress << 24) |
6678 (((uint) ipmr.MulticastAddress & 0x0000FF00) << 8) |
6679 (((uint) ipmr.MulticastAddress >> 8) & 0x0000FF00) |
6680 ((uint) ipmr.MulticastAddress >> 24));
6681 ipmr.InterfaceAddress = (int) (((uint) ipmr.InterfaceAddress << 24) |
6682 (((uint) ipmr.InterfaceAddress & 0x0000FF00) << 8) |
6683 (((uint) ipmr.InterfaceAddress >> 8) & 0x0000FF00) |
6684 ((uint) ipmr.InterfaceAddress >> 24));
6687 IPAddress multicastAddr = new IPAddress(ipmr.MulticastAddress);
6688 IPAddress multicastIntr = new IPAddress(ipmr.InterfaceAddress);
6690 MulticastOption multicastOption = new MulticastOption(multicastAddr, multicastIntr);
6692 return multicastOption;
6698 /// IPv6 getsockopt for JOIN / LEAVE multicast group
6701 private IPv6MulticastOption getIPv6MulticastOpt(SocketOptionName optionName) {
6702 IPv6MulticastRequest ipmr = new IPv6MulticastRequest();
6704 int optlen = IPv6MulticastRequest.Size;
6706 // This can throw ObjectDisposedException.
6707 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
6709 SocketOptionLevel.IP,
6714 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getIPv6MulticastOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
6717 // if the native call fails we'll throw a SocketException
6719 if (errorCode==SocketError.SocketError) {
6721 // update our internal state after this socket error and throw
6723 SocketException socketException = new SocketException();
6724 UpdateStatusAfterSocketError(socketException);
6725 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getIPv6MulticastOpt", socketException);
6726 throw socketException;
6729 IPv6MulticastOption multicastOption = new IPv6MulticastOption(new IPAddress(ipmr.MulticastAddress),ipmr.InterfaceIndex);
6731 return multicastOption;
6735 // this version will ignore failures but it returns the win32
6736 // error code, and it will update internal state on success.
6738 private SocketError InternalSetBlocking(bool desired, out bool current) {
6739 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "desired:" + desired.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
6742 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "ObjectDisposed");
6743 current = willBlock;
6744 return SocketError.Success;
6747 int intBlocking = desired ? 0 : -1;
6750 SocketError errorCode;
6753 errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
6755 IoctlSocketConstants.FIONBIO,
6758 if (errorCode == SocketError.SocketError)
6760 errorCode = (SocketError) Marshal.GetLastWin32Error();
6763 catch (ObjectDisposedException)
6765 errorCode = SocketError.NotSocket;
6768 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking() UnsafeNclNativeMethods.OSSOCK.ioctlsocket returns errorCode:" + errorCode);
6771 // we will update only internal state but only on successfull win32 call
6772 // so if the native call fails, the state will remain the same.
6774 if (errorCode==SocketError.Success) {
6776 // success, update internal state
6778 willBlockInternal = intBlocking==0;
6781 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "errorCode:" + errorCode.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
6782 current = willBlockInternal;
6786 // this version will ignore all failures.
6788 internal void InternalSetBlocking(bool desired) {
6790 InternalSetBlocking(desired, out current);
6793 private static IntPtr[] SocketListToFileDescriptorSet(IList socketList) {
6794 if (socketList==null || socketList.Count==0) {
6797 IntPtr[] fileDescriptorSet = new IntPtr[socketList.Count + 1];
6798 fileDescriptorSet[0] = (IntPtr)socketList.Count;
6799 for (int current=0; current<socketList.Count; current++) {
6800 if (!(socketList[current] is Socket)) {
6801 throw new ArgumentException(SR.GetString(SR.net_sockets_select, socketList[current].GetType().FullName, typeof(System.Net.Sockets.Socket).FullName), "socketList");
6803 fileDescriptorSet[current + 1] = ((Socket)socketList[current]).m_Handle.DangerousGetHandle();
6805 return fileDescriptorSet;
6809 // Transform the list socketList such that the only sockets left are those
6810 // with a file descriptor contained in the array "fileDescriptorArray"
6812 private static void SelectFileDescriptor(IList socketList, IntPtr[] fileDescriptorSet) {
6813 // Walk the list in order
6814 // Note that the counter is not necessarily incremented at each step;
6815 // when the socket is removed, advancing occurs automatically as the
6816 // other elements are shifted down.
6817 if (socketList==null || socketList.Count==0) {
6820 if ((int)fileDescriptorSet[0]==0) {
6821 // no socket present, will never find any socket, remove them all
6826 for (int currentSocket=0; currentSocket<socketList.Count; currentSocket++) {
6827 Socket socket = socketList[currentSocket] as Socket;
6828 // Look for the file descriptor in the array
6829 int currentFileDescriptor;
6830 for (currentFileDescriptor=0; currentFileDescriptor<(int)fileDescriptorSet[0]; currentFileDescriptor++) {
6831 if (fileDescriptorSet[currentFileDescriptor + 1]==socket.m_Handle.DangerousGetHandle()) {
6835 if (currentFileDescriptor==(int)fileDescriptorSet[0]) {
6836 // descriptor not found: remove the current socket and start again
6837 socketList.RemoveAt(currentSocket--);
6844 private static void MicrosecondsToTimeValue(long microSeconds, ref TimeValue socketTime) {
6845 socketTime.Seconds = (int) (microSeconds / microcnv);
6846 socketTime.Microseconds = (int) (microSeconds % microcnv);
6848 //Implements ConnectEx - this provides completion port IO and support for
6849 //disconnect and reconnects
6851 // Since this is private, the unsafe mode is specified with a flag instead of an overload.
6852 private IAsyncResult BeginConnectEx(EndPoint remoteEP, bool flowContext, AsyncCallback callback, object state)
6854 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnectEx", "");
6856 // This will check the permissions for connect.
6857 EndPoint endPointSnapshot = remoteEP;
6858 SocketAddress socketAddress = flowContext ? CheckCacheRemote(ref endPointSnapshot, true) : SnapshotAndSerialize(ref endPointSnapshot);
6860 //socket must be bound first
6861 //the calling method BeginConnect will ensure that this method is only
6862 //called if m_RightEndPoint is not null, of that the endpoint is an ipendpoint
6863 if (m_RightEndPoint==null){
6864 GlobalLog.Assert(endPointSnapshot.GetType() == typeof(IPEndPoint), "Socket#{0}::BeginConnectEx()|Socket not bound and endpoint not IPEndPoint.", ValidationHelper.HashString(this));
6865 if (endPointSnapshot.AddressFamily == AddressFamily.InterNetwork)
6866 InternalBind(new IPEndPoint(IPAddress.Any, 0));
6868 InternalBind(new IPEndPoint(IPAddress.IPv6Any, 0));
6872 // Allocate the async result and the event we'll pass to the
6875 ConnectOverlappedAsyncResult asyncResult = new ConnectOverlappedAsyncResult(this, endPointSnapshot, state, callback);
6877 // If context flowing is enabled, set it up here. No need to lock since the context isn't used until the callback.
6880 asyncResult.StartPostingAsyncOp(false);
6883 // This will pin socketAddress buffer
6884 asyncResult.SetUnmanagedStructures(socketAddress.m_Buffer);
6886 //we should fix this in Whidbey.
6887 EndPoint oldEndPoint = m_RightEndPoint;
6888 if (m_RightEndPoint == null) {
6889 m_RightEndPoint = endPointSnapshot;
6892 SocketError errorCode=SocketError.Success;
6894 int ignoreBytesSent;
6900 Marshal.UnsafeAddrOfPinnedArrayElement(socketAddress.m_Buffer, 0),
6901 socketAddress.m_Size,
6904 out ignoreBytesSent,
6905 asyncResult.OverlappedHandle))
6907 errorCode = (SocketError)Marshal.GetLastWin32Error();
6913 // Bug 152350: If ConnectEx throws we need to unpin the socketAddress buffer.
6914 // m_RightEndPoint will always equal oldEndPoint anyways...
6916 asyncResult.InternalCleanup();
6917 m_RightEndPoint = oldEndPoint;
6922 if (errorCode == SocketError.Success) {
6926 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginConnectEx() UnsafeNclNativeMethods.OSSOCK.connect returns:" + errorCode.ToString());
6928 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
6931 // if the asynchronous native call fails synchronously
6932 // we'll throw a SocketException
6934 if (errorCode != SocketError.Success) {
6936 // update our internal state after this socket error and throw
6938 m_RightEndPoint = oldEndPoint;
6939 SocketException socketException = new SocketException(errorCode);
6940 UpdateStatusAfterSocketError(socketException);
6941 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginConnectEx", socketException);
6942 throw socketException;
6945 // We didn't throw, so indicate that we're returning this result to the user. This may call the callback.
6946 // This is a nop if the context isn't being flowed.
6947 asyncResult.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
6949 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginConnectEx() to:" + endPointSnapshot.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
6950 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnectEx", asyncResult);
6955 internal void MultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags) {
6956 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "MultipleSend", "");
6958 throw new ObjectDisposedException(this.GetType().FullName);
6961 // parameter validation
6963 GlobalLog.Assert(buffers != null, "Socket#{0}::MultipleSend()|buffers == null", ValidationHelper.HashString(this));
6964 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::MultipleSend() buffers.Length:" + buffers.Length.ToString());
6966 WSABuffer[] WSABuffers = new WSABuffer[buffers.Length];
6967 GCHandle[] objectsToPin = null;
6968 int bytesTransferred;
6969 SocketError errorCode;
6972 objectsToPin = new GCHandle[buffers.Length];
6973 for (int i = 0; i < buffers.Length; ++i)
6975 objectsToPin[i] = GCHandle.Alloc(buffers[i].Buffer, GCHandleType.Pinned);
6976 WSABuffers[i].Length = buffers[i].Size;
6977 WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffers[i].Buffer, buffers[i].Offset);
6980 // This can throw ObjectDisposedException.
6981 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend_Blocking(
6982 m_Handle.DangerousGetHandle(),
6985 out bytesTransferred,
6987 SafeNativeOverlapped.Zero,
6990 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::MultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString());
6994 if (objectsToPin != null)
6995 for (int i = 0; i < objectsToPin.Length; ++i)
6996 if (objectsToPin[i].IsAllocated)
6997 objectsToPin[i].Free();
7000 if (errorCode!=SocketError.Success) {
7001 SocketException socketException = new SocketException();
7002 UpdateStatusAfterSocketError(socketException);
7003 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "MultipleSend", socketException);
7004 throw socketException;
7007 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "MultipleSend", "");
7011 private static void DnsCallback(IAsyncResult result){
7012 if (result.CompletedSynchronously)
7015 bool invokeCallback = false;
7017 MultipleAddressConnectAsyncResult context = (MultipleAddressConnectAsyncResult) result.AsyncState;
7020 invokeCallback = DoDnsCallback(result, context);
7022 catch (Exception exception)
7024 context.InvokeCallback(exception);
7027 // Invoke the callback outside of the try block so we don't catch user Exceptions
7030 context.InvokeCallback();
7034 private static bool DoDnsCallback(IAsyncResult result, MultipleAddressConnectAsyncResult context)
7036 IPAddress[] addresses = Dns.EndGetHostAddresses(result);
7037 context.addresses = addresses;
7038 return DoMultipleAddressConnectCallback(PostOneBeginConnect(context), context);
7041 private class MultipleAddressConnectAsyncResult : ContextAwareResult
7043 internal MultipleAddressConnectAsyncResult(IPAddress[] addresses, int port, Socket socket, object myState, AsyncCallback myCallBack) :
7044 base(socket, myState, myCallBack)
7046 this.addresses = addresses;
7048 this.socket = socket;
7051 internal Socket socket; // Keep this member just to avoid all the casting.
7052 internal IPAddress[] addresses;
7055 internal Exception lastException;
7057 internal EndPoint RemoteEndPoint {
7059 if (addresses != null && index > 0 && index < addresses.Length) {
7060 return new IPEndPoint(addresses[index], port);
7068 private static object PostOneBeginConnect(MultipleAddressConnectAsyncResult context)
7070 IPAddress currentAddressSnapshot = context.addresses[context.index];
7072 if (!context.socket.CanTryAddressFamily(currentAddressSnapshot.AddressFamily))
7074 return context.lastException != null ? context.lastException : new ArgumentException(SR.GetString(SR.net_invalidAddressList), "context");
7079 EndPoint endPoint = new IPEndPoint(currentAddressSnapshot, context.port);
7080 // MSRC 11081 - Do the necessary security demand
7081 context.socket.CheckCacheRemote(ref endPoint, true);
7083 IAsyncResult connectResult = context.socket.UnsafeBeginConnect(endPoint,
7084 new AsyncCallback(MultipleAddressConnectCallback), context);
7086 if (connectResult.CompletedSynchronously)
7088 return connectResult;
7091 catch (Exception exception)
7093 if (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException)
7102 private static void MultipleAddressConnectCallback(IAsyncResult result)
7104 if (result.CompletedSynchronously)
7107 bool invokeCallback = false;
7109 MultipleAddressConnectAsyncResult context = (MultipleAddressConnectAsyncResult) result.AsyncState;
7112 invokeCallback = DoMultipleAddressConnectCallback(result, context);
7114 catch (Exception exception)
7116 context.InvokeCallback(exception);
7119 // Invoke the callback outside of the try block so we don't catch user Exceptions
7122 context.InvokeCallback();
7126 // This is like a regular async callback worker, except the result can be an exception. This is a useful pattern when
7127 // processing should continue whether or not an async step failed.
7128 private static bool DoMultipleAddressConnectCallback(object result, MultipleAddressConnectAsyncResult context)
7130 while (result != null)
7132 Exception ex = result as Exception;
7137 context.socket.EndConnect((IAsyncResult) result);
7139 catch (Exception exception)
7147 // Don't invoke the callback from here, because we're probably inside
7148 // a catch-all block that would eat exceptions from the callback.
7149 // Instead tell our caller to invoke the callback outside of its catchall.
7154 if (++context.index >= context.addresses.Length)
7157 context.lastException = ex;
7158 result = PostOneBeginConnect(context);
7162 // Don't invoke the callback at all, because we've posted another async connection attempt
7167 internal IAsyncResult BeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state) {
7168 // Set up the async result and start the flow.
7169 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
7170 asyncResult.StartPostingAsyncOp(false);
7173 DoBeginMultipleSend(buffers, socketFlags, asyncResult);
7175 // Finish it up (capture, complete).
7176 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
7180 internal IAsyncResult UnsafeBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
7182 // Unsafe - don't flow.
7183 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
7184 DoBeginMultipleSend(buffers, socketFlags, asyncResult);
7188 private void DoBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
7190 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginMultipleSend", "");
7192 throw new ObjectDisposedException(this.GetType().FullName);
7195 // parameter validation
7197 GlobalLog.Assert(buffers != null, "Socket#{0}::DoBeginMultipleSend()|buffers == null", ValidationHelper.HashString(this));
7198 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginMultipleSend() buffers.Length:" + buffers.Length.ToString());
7200 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
7201 // avoid a Socket leak in case of error.
7202 SocketError errorCode = SocketError.SocketError;
7205 // Set up asyncResult for overlapped WSASend.
7206 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
7207 asyncResult.SetUnmanagedStructures(buffers, ref Caches.SendOverlappedCache);
7209 // This can throw ObjectDisposedException.
7210 int bytesTransferred;
7211 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
7213 asyncResult.m_WSABuffers,
7214 asyncResult.m_WSABuffers.Length,
7215 out bytesTransferred,
7217 asyncResult.OverlappedHandle,
7220 if (errorCode!=SocketError.Success) {
7221 errorCode = (SocketError)Marshal.GetLastWin32Error();
7223 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginMultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
7227 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
7231 // if the asynchronous native call fails synchronously
7232 // we'll throw a SocketException
7234 if (errorCode!=SocketError.Success) {
7236 // update our internal state after this socket error and throw
7238 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
7239 SocketException socketException = new SocketException(errorCode);
7240 UpdateStatusAfterSocketError(socketException);
7241 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginMultipleSend", socketException);
7242 throw socketException;
7244 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginMultipleSend", asyncResult);
7247 internal int EndMultipleSend(IAsyncResult asyncResult) {
7248 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndMultipleSend", asyncResult);
7250 // parameter validation
7252 GlobalLog.Assert(asyncResult != null, "Socket#{0}::EndMultipleSend()|asyncResult == null", ValidationHelper.HashString(this));
7254 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
7256 GlobalLog.Assert(castedAsyncResult != null, "Socket#{0}::EndMultipleSend()|castedAsyncResult == null", ValidationHelper.HashString(this));
7257 GlobalLog.Assert(castedAsyncResult.AsyncObject == this, "Socket#{0}::EndMultipleSend()|castedAsyncResult.AsyncObject != this", ValidationHelper.HashString(this));
7258 GlobalLog.Assert(!castedAsyncResult.EndCalled, "Socket#{0}::EndMultipleSend()|castedAsyncResult.EndCalled", ValidationHelper.HashString(this));
7260 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
7261 castedAsyncResult.EndCalled = true;
7262 castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
7264 #if !FEATURE_PAL // perfcounter
7265 if (s_PerfCountersEnabled)
7267 if (bytesTransferred>0) {
7268 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
7269 if (Transport==TransportType.Udp) {
7270 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
7274 #endif //!FEATURE_PAL
7276 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndMultipleSend() bytesTransferred:" + bytesTransferred.ToString());
7279 // if the asynchronous native call failed asynchronously
7280 // we'll throw a SocketException
7282 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
7284 // update our internal state after this socket error and throw
7286 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
7287 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndMultipleSend", socketException);
7288 throw socketException;
7290 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndMultipleSend", bytesTransferred);
7291 return bytesTransferred;
7295 // CreateAcceptSocket - pulls unmanaged results and assembles them
7296 // into a new Socket object
7298 private Socket CreateAcceptSocket(SafeCloseSocket fd, EndPoint remoteEP, bool needCancelSelect) {
7300 // Internal state of the socket is inherited from listener
7302 Socket socket = new Socket(fd);
7303 return UpdateAcceptSocket(socket,remoteEP, needCancelSelect);
7306 internal Socket UpdateAcceptSocket(Socket socket, EndPoint remoteEP, bool needCancelSelect) {
7308 // Internal state of the socket is inherited from listener
7310 socket.addressFamily = addressFamily;
7311 socket.socketType = socketType;
7312 socket.protocolType = protocolType;
7313 socket.m_RightEndPoint = m_RightEndPoint;
7314 socket.m_RemoteEndPoint = remoteEP;
7316 // the socket is connected
7318 socket.SetToConnected();
7320 // if the socket is returned by an Endb), the socket might have
7321 // inherited the WSAEventSelect() call from the accepting socket.
7322 // we need to cancel this otherwise the socket will be in non-blocking
7323 // mode and we cannot force blocking mode using the ioctlsocket() in
7324 // Socket.set_Blocking(), since it fails returing 10022 as documented in MSDN.
7325 // (note that the m_AsyncEvent event will not be created in this case.
7328 socket.willBlock = willBlock;
7329 if (needCancelSelect) {
7330 socket.UnsetAsyncEventSelect();
7333 // We need to make sure the Socket is in the right blocking state
7334 // even if we don't have to call UnsetAsyncEventSelect
7335 socket.InternalSetBlocking(willBlock);
7344 // SetToConnected - updates the status of the socket to connected
7346 internal void SetToConnected() {
7347 if (m_IsConnected) {
7349 // socket was already connected
7354 // update the status: this socket was indeed connected at
7355 // some point in time update the perf counter as well.
7357 m_IsConnected = true;
7358 m_IsDisconnected = false;
7359 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToConnected() now connected SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
7360 #if !FEATURE_PAL // perfcounter
7361 if (s_PerfCountersEnabled)
7363 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketConnectionsEstablished);
7365 #endif //!FEATURE_PAL
7369 // SetToDisconnected - updates the status of the socket to disconnected
7371 internal void SetToDisconnected() {
7372 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToDisconnected()");
7373 if (!m_IsConnected) {
7375 // socket was already disconnected
7380 // update the status: this socket was indeed disconnected at
7381 // some point in time, clear any async select bits.
7383 m_IsConnected = false;
7384 m_IsDisconnected = true;
7388 // if socket is still alive cancel WSAEventSelect()
7390 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToDisconnected()");
7392 UnsetAsyncEventSelect();
7397 // UpdateStatusAfterSocketError(socketException) - updates the status of a connected socket
7398 // on which a failure occured. it'll go to winsock and check if the connection
7399 // is still open and if it needs to update our internal state.
7401 internal void UpdateStatusAfterSocketError(SocketException socketException){
7402 UpdateStatusAfterSocketError((SocketError) socketException.NativeErrorCode);
7405 internal void UpdateStatusAfterSocketError(SocketError errorCode)
7408 // if we already know the socket is disconnected
7409 // we don't need to do anything else.
7411 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UpdateStatusAfterSocketError(socketException)");
7412 if (s_LoggingEnabled) Logging.PrintError(Logging.Sockets, this, "UpdateStatusAfterSocketError", errorCode.ToString());
7414 if (m_IsConnected && (m_Handle.IsInvalid || (errorCode != SocketError.WouldBlock &&
7415 errorCode != SocketError.IOPending && errorCode != SocketError.NoBufferSpaceAvailable &&
7416 errorCode != SocketError.TimedOut)))
7420 // the socket is no longer a valid socket
7422 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UpdateStatusAfterSocketError(socketException) Invalidating socket.");
7423 SetToDisconnected();
7429 // Does internal initalization before async winsock
7430 // call to BeginConnect() or BeginAccept().
7432 private void UnsetAsyncEventSelect()
7434 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
7436 RegisteredWaitHandle registeredWait = m_RegisteredWait;
7437 if (registeredWait != null)
7439 m_RegisteredWait = null;
7440 registeredWait.Unregister(null);
7443 SocketError errorCode = SocketError.NotSocket;
7445 errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_Handle, IntPtr.Zero, AsyncEventBits.FdNone);
7449 if (NclUtilities.IsFatal(e))
7451 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect() !!! (ignoring) Exception: " + e.ToString());
7452 GlobalLog.Assert(CleanedUp, "Socket#{0}::UnsetAsyncEventSelect|Got exception and CleanedUp not set.", ValidationHelper.HashString(this));
7456 // May be re-used in future, reset if the event got signalled after registeredWait.Unregister call
7458 if (m_AsyncEvent != null)
7462 m_AsyncEvent.Reset();
7464 catch (ObjectDisposedException) { }
7467 if (errorCode == SocketError.SocketError)
7470 // update our internal state after this socket error
7471 // we won't throw since this is an internal method
7473 UpdateStatusAfterSocketError(errorCode);
7476 // The call to WSAEventSelect will always put us into non-blocking mode.
7477 // Revert back to what the user has requested.
7478 InternalSetBlocking(willBlock);
7480 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
7483 private bool SetAsyncEventSelect(AsyncEventBits blockEventBits)
7485 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "blockEventBits:" + blockEventBits.ToString() + " m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
7486 GlobalLog.Assert(blockEventBits != AsyncEventBits.FdNone, "Socket#{0}::SetAsyncEventSelect|Use UnsetAsyncEventSelect for FdNone.", ValidationHelper.HashString(this));
7487 GlobalLog.Assert(m_BlockEventBits == AsyncEventBits.FdNone || m_BlockEventBits == blockEventBits, "Socket#{0}::SetAsyncEventSelect|Can't change from one active wait to another.", ValidationHelper.HashString(this));
7488 GlobalLog.Assert(m_RegisteredWait == null, "Socket#{0}::SetAsyncEventSelect|Already actively waiting on an op.", ValidationHelper.HashString(this));
7490 // This check is bogus, too late diggin into a historical reason for it.
7491 // Make sure the upper level will fail with ObjectDisposedException
7492 if (m_RegisteredWait != null)
7496 // This will put us into non-blocking mode. Create the event if it isn't, and register a wait.
7498 if (m_AsyncEvent == null)
7500 Interlocked.CompareExchange<ManualResetEvent>(ref m_AsyncEvent, new ManualResetEvent(false), null);
7501 if (s_RegisteredWaitCallback == null)
7502 s_RegisteredWaitCallback = new WaitOrTimerCallback(RegisteredWaitCallback);
7506 // Try to win over Dispose is there is a ----
7508 if (Interlocked.CompareExchange(ref m_IntCleanedUp, 2, 0) != 0)
7510 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect() Already Cleaned up, returning ... ", string.Empty);
7516 m_BlockEventBits = blockEventBits;
7517 m_RegisteredWait = ThreadPool.UnsafeRegisterWaitForSingleObject(m_AsyncEvent, s_RegisteredWaitCallback, this, Timeout.Infinite, true);
7522 // Release dispose if any is waiting
7524 Interlocked.Exchange(ref m_IntCleanedUp, 0);
7527 SocketError errorCode = SocketError.NotSocket;
7529 // issue the native call
7532 errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_Handle, m_AsyncEvent.SafeWaitHandle, blockEventBits);
7536 if (NclUtilities.IsFatal(e))
7538 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect() !!! (converting to ObjectDisposed) Exception :" + e.ToString());
7539 GlobalLog.Assert(CleanedUp, "Socket#{0}::SetAsyncEventSelect|WSAEventSelect got exception and CleanedUp not set.", ValidationHelper.HashString(this));
7542 if (errorCode==SocketError.SocketError) {
7544 // update our internal state after this socket error
7545 // we won't throw since this is an internal method
7547 UpdateStatusAfterSocketError(errorCode);
7551 // the call to WSAEventSelect will put us in non-blocking mode,
7552 // hence we need update internal status
7554 willBlockInternal = false;
7556 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
7557 return errorCode == SocketError.Success;
7560 private static void RegisteredWaitCallback(object state, bool timedOut)
7562 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(state) + "::RegisteredWaitCallback", "m_BlockEventBits:" + ((Socket)state).m_BlockEventBits.ToString());
7564 // GlobalLog.SetThreadSource(ThreadKinds.Worker); Because of change 1077887, need logic to determine thread type here.
7565 using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
7567 Socket me = (Socket)state;
7569 // Interlocked to avoid a race condition with DoBeginConnect
7570 if (Interlocked.Exchange(ref me.m_RegisteredWait, null) != null)
7572 switch (me.m_BlockEventBits)
7574 case AsyncEventBits.FdConnect:
7575 me.ConnectCallback();
7578 case AsyncEventBits.FdAccept:
7579 me.AcceptCallback(null);
7586 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(state) + "::RegisteredWaitCallback", "m_BlockEventBits:" + ((Socket)state).m_BlockEventBits.ToString());
7590 // ValidateBlockingMode - called before synchronous calls to validate
7591 // the fact that we are in blocking mode (not in non-blocking mode) so the
7592 // call will actually be synchronous
7594 private void ValidateBlockingMode() {
7595 if (willBlock && !willBlockInternal) {
7596 throw new InvalidOperationException(SR.GetString(SR.net_invasync));
7602 // This Method binds the Socket Win32 Handle to the ThreadPool's CompletionPort
7603 // (make sure we only bind once per socket)
7605 [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
7606 internal void BindToCompletionPort()
7609 // Check to see if the socket native m_Handle is already
7610 // bound to the ThreadPool's completion port.
7612 if (!m_BoundToThreadPool && !UseOverlappedIO) {
7614 if (!m_BoundToThreadPool) {
7615 #if SOCKETTHREADPOOL
7616 // bind the socket native m_Handle to prototype SocketThreadPool
7617 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BindToCompletionPort() calling SocketThreadPool.BindHandle()");
7618 SocketThreadPool.BindHandle(m_Handle);
7619 m_BoundToThreadPool = true;
7622 // bind the socket native m_Handle to the ThreadPool
7624 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BindToCompletionPort() calling ThreadPool.BindHandle()");
7628 ThreadPool.BindHandle(m_Handle);
7629 m_BoundToThreadPool = true;
7631 catch (Exception exception)
7633 if (NclUtilities.IsFatal(exception)) throw;
7644 [System.Diagnostics.Conditional("TRAVE")]
7645 internal void DebugMembers() {
7646 GlobalLog.Print("m_Handle:" + m_Handle.DangerousGetHandle().ToString("x") );
7647 GlobalLog.Print("m_IsConnected: " + m_IsConnected);
7654 public bool AcceptAsync(SocketAsyncEventArgs e) {
7658 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "AcceptAsync", "");
7660 // Throw if socket disposed
7662 throw new ObjectDisposedException(GetType().FullName);
7665 // Throw if multiple buffers specified.
7666 if(e.m_BufferList != null) {
7667 throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
7670 // Throw if not bound.
7671 if(m_RightEndPoint == null) {
7672 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
7675 // Throw if not listening.
7677 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
7680 // Handle AcceptSocket property.
7681 if(e.AcceptSocket == null) {
7682 // Accept socket not specified - create it.
7683 e.AcceptSocket = new Socket(addressFamily, socketType, protocolType);
7685 // Validate accept socket for use here.
7686 if(e.AcceptSocket.m_RightEndPoint != null && !e.AcceptSocket.m_IsDisconnected) {
7687 throw new InvalidOperationException(SR.GetString(SR.net_sockets_namedmustnotbebound, "AcceptSocket"));
7691 // Prepare for the native call.
7692 e.StartOperationCommon(this);
7693 e.StartOperationAccept();
7694 BindToCompletionPort();
7696 // Local variables for [....] completion.
7697 int bytesTransferred;
7698 SocketError socketError = SocketError.Success;
7700 // Make the native call.
7704 e.AcceptSocket.m_Handle,
7705 (e.m_PtrSingleBuffer != IntPtr.Zero) ? e.m_PtrSingleBuffer : e.m_PtrAcceptBuffer,
7706 (e.m_PtrSingleBuffer != IntPtr.Zero) ? e.Count - e.m_AcceptAddressBufferCount : 0,
7707 e.m_AcceptAddressBufferCount / 2,
7708 e.m_AcceptAddressBufferCount / 2,
7709 out bytesTransferred,
7710 e.m_PtrNativeOverlapped)) {
7711 socketError = (SocketError)Marshal.GetLastWin32Error();
7714 catch (Exception ex) {
7715 // clear in-use on event arg object
7720 // Handle completion when completion port is not posted.
7721 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
7722 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
7728 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "AcceptAsync", retval);
7735 public bool ConnectAsync(SocketAsyncEventArgs e) {
7739 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ConnectAsync", "");
7741 // Throw if socket disposed
7743 throw new ObjectDisposedException(GetType().FullName);
7746 // Throw if multiple buffers specified.
7747 if(e.m_BufferList != null) {
7748 throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
7751 // Throw if RemoteEndPoint is null.
7752 if(e.RemoteEndPoint == null) {
7753 throw new ArgumentNullException("remoteEP");
7755 // Throw if listening.
7757 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
7761 // Check permissions for connect and prepare SocketAddress.
7762 EndPoint endPointSnapshot = e.RemoteEndPoint;
7763 DnsEndPoint dnsEP = endPointSnapshot as DnsEndPoint;
7765 if (dnsEP != null) {
7766 if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, "Socket#" + ValidationHelper.HashString(this)
7767 + "::ConnectAsync " + SR.GetString(SR.net_log_socket_connect_dnsendpoint));
7769 if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily)) {
7770 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
7773 MultipleConnectAsync multipleConnectAsync = new SingleSocketMultipleConnectAsync(this, true);
7775 e.StartOperationCommon(this);
7776 e.StartOperationWrapperConnect(multipleConnectAsync);
7778 retval = multipleConnectAsync.StartConnectAsync(e, dnsEP);
7781 // Throw if remote address family doesn't match socket.
7782 if (!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
7783 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
7786 e.m_SocketAddress = CheckCacheRemote(ref endPointSnapshot, false);
7788 // Do wildcard bind if socket not bound.
7789 if(m_RightEndPoint == null) {
7790 if(endPointSnapshot.AddressFamily == AddressFamily.InterNetwork)
7791 InternalBind(new IPEndPoint(IPAddress.Any, 0));
7793 InternalBind(new IPEndPoint(IPAddress.IPv6Any, 0));
7796 // Save the old RightEndPoint and prep new RightEndPoint.
7797 EndPoint oldEndPoint = m_RightEndPoint;
7798 if(m_RightEndPoint == null) {
7799 m_RightEndPoint = endPointSnapshot;
7802 // Prepare for the native call.
7803 e.StartOperationCommon(this);
7804 e.StartOperationConnect();
7805 BindToCompletionPort();
7808 // Make the native call.
7809 int bytesTransferred;
7810 SocketError socketError = SocketError.Success;
7814 e.m_PtrSocketAddressBuffer,
7815 e.m_SocketAddress.m_Size,
7816 e.m_PtrSingleBuffer,
7818 out bytesTransferred,
7819 e.m_PtrNativeOverlapped)) {
7820 socketError = (SocketError)Marshal.GetLastWin32Error();
7823 catch (Exception ex) {
7824 m_RightEndPoint = oldEndPoint;
7825 // clear in-use on event arg object
7830 // Handle failure where completion port is not posted.
7831 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
7832 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
7839 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ConnectAsync", retval);
7843 public static bool ConnectAsync(SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e) {
7847 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, null, "ConnectAsync", "");
7849 // Throw if multiple buffers specified.
7850 if (e.m_BufferList != null) {
7851 throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
7854 // Throw if RemoteEndPoint is null.
7855 if (e.RemoteEndPoint == null) {
7856 throw new ArgumentNullException("remoteEP");
7859 EndPoint endPointSnapshot = e.RemoteEndPoint;
7860 DnsEndPoint dnsEP = endPointSnapshot as DnsEndPoint;
7862 if (dnsEP != null) {
7863 Socket attemptSocket = null;
7864 MultipleConnectAsync multipleConnectAsync = null;
7865 if (dnsEP.AddressFamily == AddressFamily.Unspecified) {
7866 multipleConnectAsync = new MultipleSocketMultipleConnectAsync(socketType, protocolType);
7868 attemptSocket = new Socket(dnsEP.AddressFamily, socketType, protocolType);
7869 multipleConnectAsync = new SingleSocketMultipleConnectAsync(attemptSocket, false);
7872 e.StartOperationCommon(attemptSocket);
7873 e.StartOperationWrapperConnect(multipleConnectAsync);
7875 retval = multipleConnectAsync.StartConnectAsync(e, dnsEP);
7877 Socket attemptSocket = new Socket(endPointSnapshot.AddressFamily, socketType, protocolType);
7878 retval = attemptSocket.ConnectAsync(e);
7881 if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, null, "ConnectAsync", retval);
7885 public static void CancelConnectAsync(SocketAsyncEventArgs e) {
7888 throw new ArgumentNullException("e");
7890 e.CancelConnectAsync();
7896 public bool DisconnectAsync(SocketAsyncEventArgs e) {
7900 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "DisconnectAsync", "");
7902 // Throw if socket disposed
7904 throw new ObjectDisposedException(GetType().FullName);
7907 // Prepare for the native call.
7908 e.StartOperationCommon(this);
7909 e.StartOperationDisconnect();
7910 BindToCompletionPort();
7912 // Make the native call.
7913 SocketError socketError = SocketError.Success;
7917 e.m_PtrNativeOverlapped,
7918 (int)(e.DisconnectReuseSocket ? TransmitFileOptions.ReuseSocket : 0),
7920 socketError = (SocketError)Marshal.GetLastWin32Error();
7923 catch(Exception ex) {
7924 // clear in-use on event arg object
7929 // Handle completion when completion port is not posted.
7930 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
7931 e.FinishOperationSyncFailure(socketError, 0, SocketFlags.None);
7937 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "DisconnectAsync", retval);
7945 public bool ReceiveAsync(SocketAsyncEventArgs e) {
7949 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveAsync", "");
7951 // Throw if socket disposed
7953 throw new ObjectDisposedException(GetType().FullName);
7956 // Prepare for the native call.
7957 e.StartOperationCommon(this);
7958 e.StartOperationReceive();
7959 BindToCompletionPort();
7961 // Local vars for [....] completion of native call.
7962 SocketFlags flags = e.m_SocketFlags;
7963 int bytesTransferred;
7964 SocketError socketError;
7966 // Wrap native methods with try/catch so event args object can be cleaned up
7968 if(e.m_Buffer != null) {
7969 // Single buffer case
7970 socketError = UnsafeNclNativeMethods.OSSOCK.WSARecv(
7974 out bytesTransferred,
7976 e.m_PtrNativeOverlapped,
7979 // Multi buffer case
7980 socketError = UnsafeNclNativeMethods.OSSOCK.WSARecv(
7983 e.m_WSABufferArray.Length,
7984 out bytesTransferred,
7986 e.m_PtrNativeOverlapped,
7990 catch(Exception ex) {
7991 // clear in-use on event arg object
7996 // Native method emits single catch-all error code when error occurs.
7997 // Must get Win32 error for specific error code.
7998 if(socketError != SocketError.Success) {
7999 socketError = (SocketError)Marshal.GetLastWin32Error();
8002 // Handle completion when completion port is not posted.
8003 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8004 e.FinishOperationSyncFailure(socketError, bytesTransferred, flags);
8010 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveAsync", retval);
8017 public bool ReceiveFromAsync(SocketAsyncEventArgs e) {
8021 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveFromAsync", "");
8023 // Throw if socket disposed
8025 throw new ObjectDisposedException(GetType().FullName);
8028 // Throw if remote endpoint property is null.
8029 if(e.RemoteEndPoint == null) {
8030 throw new ArgumentNullException("RemoteEndPoint");
8033 if(!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
8034 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
8035 e.RemoteEndPoint.AddressFamily, addressFamily), "RemoteEndPoint");
8038 // We don't do a CAS demand here because the contents of remoteEP aren't used by
8039 // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
8040 // with the right address family
8041 EndPoint endPointSnapshot = e.RemoteEndPoint;
8042 e.m_SocketAddress = SnapshotAndSerialize(ref endPointSnapshot);
8043 // DualMode may have updated the endPointSnapshot, and it has to have the same AddressFamily as
8044 // e.m_SocketAddres for Create to work later.
8045 e.RemoteEndPoint = endPointSnapshot;
8047 // Prepare for the native call.
8048 e.StartOperationCommon(this);
8049 e.StartOperationReceiveFrom();
8050 BindToCompletionPort();
8052 // Make the native call.
8053 SocketFlags flags = e.m_SocketFlags;
8054 int bytesTransferred;
8055 SocketError socketError;
8058 if(e.m_Buffer != null) {
8059 socketError = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
8063 out bytesTransferred,
8065 e.m_PtrSocketAddressBuffer,
8066 e.m_PtrSocketAddressBufferSize,
8067 e.m_PtrNativeOverlapped,
8070 socketError = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
8073 e.m_WSABufferArray.Length,
8074 out bytesTransferred,
8076 e.m_PtrSocketAddressBuffer,
8077 e.m_PtrSocketAddressBufferSize,
8078 e.m_PtrNativeOverlapped,
8082 catch(Exception ex) {
8083 // clear in-use on event arg object
8088 // Native method emits single catch-all error code when error occurs.
8089 // Must get Win32 error for specific error code.
8090 if(socketError != SocketError.Success) {
8091 socketError = (SocketError)Marshal.GetLastWin32Error();
8094 // Handle completion when completion port is not posted.
8095 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8096 e.FinishOperationSyncFailure(socketError, bytesTransferred, flags);
8102 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveFromAsync", retval);
8107 // ReceiveMessageFromAsync
8109 public bool ReceiveMessageFromAsync(SocketAsyncEventArgs e) {
8113 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveMessageFromAsync", "");
8115 // Throw if socket disposed
8117 throw new ObjectDisposedException(GetType().FullName);
8120 // Throw if remote endpoint property is null.
8121 if(e.RemoteEndPoint == null) {
8122 throw new ArgumentNullException("RemoteEndPoint");
8125 if(!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
8126 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
8127 e.RemoteEndPoint.AddressFamily, addressFamily), "RemoteEndPoint");
8130 // We don't do a CAS demand here because the contents of remoteEP aren't used by
8131 // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
8132 // with the right address family
8133 EndPoint endPointSnapshot = e.RemoteEndPoint;
8134 e.m_SocketAddress = SnapshotAndSerialize(ref endPointSnapshot);
8135 // DualMode may have updated the endPointSnapshot, and it has to have the same AddressFamily as
8136 // e.m_SocketAddres for Create to work later.
8137 e.RemoteEndPoint = endPointSnapshot;
8139 SetReceivingPacketInformation();
8141 // Prepare for the native call.
8142 e.StartOperationCommon(this);
8143 e.StartOperationReceiveMessageFrom();
8144 BindToCompletionPort();
8147 // Make the native call.
8148 int bytesTransferred;
8149 SocketError socketError;
8152 socketError = WSARecvMsg(
8154 e.m_PtrWSAMessageBuffer,
8155 out bytesTransferred,
8156 e.m_PtrNativeOverlapped,
8159 catch(Exception ex) {
8160 // clear in-use on event arg object
8165 // Native method emits single catch-all error code when error occurs.
8166 // Must get Win32 error for specific error code.
8167 if(socketError != SocketError.Success) {
8168 socketError = (SocketError)Marshal.GetLastWin32Error();
8171 // Handle completion when completion port is not posted.
8172 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8173 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
8179 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveMessageFromAsync", retval);
8187 public bool SendAsync(SocketAsyncEventArgs e) {
8191 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendAsync", "");
8193 // Throw if socket disposed
8195 throw new ObjectDisposedException(GetType().FullName);
8198 // Prepare for the native call.
8199 e.StartOperationCommon(this);
8200 e.StartOperationSend();
8201 BindToCompletionPort();
8204 // Local vars for [....] completion of native call.
8205 int bytesTransferred;
8206 SocketError socketError;
8208 // Wrap native methods with try/catch so event args object can be cleaned up
8210 if(e.m_Buffer != null) {
8211 // Single buffer case
8212 socketError = UnsafeNclNativeMethods.OSSOCK.WSASend(
8216 out bytesTransferred,
8218 e.m_PtrNativeOverlapped,
8221 // Multi buffer case
8222 socketError = UnsafeNclNativeMethods.OSSOCK.WSASend(
8225 e.m_WSABufferArray.Length,
8226 out bytesTransferred,
8228 e.m_PtrNativeOverlapped,
8232 catch(Exception ex) {
8233 // clear in-use on event arg object
8238 // Native method emits single catch-all error code when error occurs.
8239 // Must get Win32 error for specific error code.
8240 if(socketError != SocketError.Success) {
8241 socketError = (SocketError)Marshal.GetLastWin32Error();
8244 // Handle completion when completion port is not posted.
8245 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8246 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
8252 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendAsync", retval);
8260 public bool SendPacketsAsync(SocketAsyncEventArgs e) {
8264 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendPacketsAsync", "");
8266 // Throw if socket disposed
8268 throw new ObjectDisposedException(GetType().FullName);
8271 // Throw if not connected.
8273 throw new NotSupportedException(SR.GetString(SR.net_notconnected));
8276 // Prepare for the native call.
8277 e.StartOperationCommon(this);
8278 e.StartOperationSendPackets();
8279 BindToCompletionPort();
8281 // Make the native call.
8282 SocketError socketError;
8285 if (e.m_SendPacketsDescriptor.Length > 0) {
8287 result = TransmitPackets(
8289 e.m_PtrSendPacketsDescriptor,
8290 e.m_SendPacketsDescriptor.Length,
8291 e.m_SendPacketsSendSize,
8292 e.m_PtrNativeOverlapped,
8293 e.m_SendPacketsFlags);
8296 // clear in-use on event arg object
8302 socketError = (SocketError)Marshal.GetLastWin32Error();
8304 socketError = SocketError.Success;
8307 // Handle completion when completion port is not posted.
8308 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8309 e.FinishOperationSyncFailure(socketError, 0, SocketFlags.None);
8316 // No buffers or files to send.
8317 e.FinishOperationSuccess(SocketError.Success, 0, SocketFlags.None);
8322 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "SendPacketsAsync", retval);
8330 public bool SendToAsync(SocketAsyncEventArgs e) {
8334 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendToAsync", "");
8336 // Throw if socket disposed
8338 throw new ObjectDisposedException(GetType().FullName);
8341 // Throw if remote endpoint property is null.
8342 if(e.RemoteEndPoint == null) {
8343 throw new ArgumentNullException("RemoteEndPoint");
8346 // Check permissions for connect and prepare SocketAddress
8347 EndPoint endPointSnapshot = e.RemoteEndPoint;
8348 e.m_SocketAddress = CheckCacheRemote(ref endPointSnapshot, false);
8350 // Prepare for the native call.
8351 e.StartOperationCommon(this);
8352 e.StartOperationSendTo();
8353 BindToCompletionPort();
8355 // Make the native call.
8356 int bytesTransferred;
8357 SocketError socketError;
8359 // Wrap native methods with try/catch so event args object can be cleaned up
8361 if(e.m_Buffer != null) {
8362 // Single buffer case
8363 socketError = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
8367 out bytesTransferred,
8369 e.m_PtrSocketAddressBuffer,
8370 e.m_SocketAddress.m_Size,
8371 e.m_PtrNativeOverlapped,
8374 socketError = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
8377 e.m_WSABufferArray.Length,
8378 out bytesTransferred,
8380 e.m_PtrSocketAddressBuffer,
8381 e.m_SocketAddress.m_Size,
8382 e.m_PtrNativeOverlapped,
8388 catch(Exception ex) {
8389 // clear in-use on event arg object
8394 // Native method emits single catch-all error code when error occurs.
8395 // Must get Win32 error for specific error code.
8396 if(socketError != SocketError.Success) {
8397 socketError = (SocketError)Marshal.GetLastWin32Error();
8400 // Handle completion when completion port is not posted.
8401 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8402 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
8408 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "SendToAsync", retval);
8413 } // end of class Socket
8416 internal class ConnectAsyncResult:ContextAwareResult{
8417 private EndPoint m_EndPoint;
8418 internal ConnectAsyncResult(object myObject, EndPoint endPoint, object myState, AsyncCallback myCallBack):base(myObject, myState, myCallBack) {
8419 m_EndPoint = endPoint;
8421 internal EndPoint RemoteEndPoint {
8422 get { return m_EndPoint; }
8426 internal class AcceptAsyncResult:ContextAwareResult{
8427 internal AcceptAsyncResult(object myObject, object myState, AsyncCallback myCallBack):base(myObject, myState, myCallBack) {
8432 public enum SocketAsyncOperation {
8445 // class that wraps the semantics of a winsock TRANSMIT_PACKETS_ELEMENTS struct
8446 public class SendPacketsElement {
8447 internal string m_FilePath;
8448 internal byte [] m_Buffer;
8449 internal int m_Offset;
8450 internal int m_Count;
8454 internal UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags m_Flags;
8457 // hide default constructor
8458 private SendPacketsElement() {}
8460 // constructors for file elements
8461 public SendPacketsElement(string filepath) :
8462 this(filepath, 0, 0, false) { }
8464 public SendPacketsElement(string filepath, int offset, int count) :
8465 this(filepath, offset, count, false) { }
8467 public SendPacketsElement(string filepath, int offset, int count, bool endOfPacket) {
8468 // We will validate if the file exists on send
8469 if (filepath == null) {
8470 throw new ArgumentNullException("filepath");
8472 // The native API will validate the file length on send
8474 throw new ArgumentOutOfRangeException("offset");
8477 throw new ArgumentOutOfRangeException("count");
8479 Contract.EndContractBlock();
8482 Initialize(filepath, null, offset, count, /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.File,*/
8485 Initialize(filepath, null, offset, count, UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.File,
8490 // constructors for buffer elements
8491 public SendPacketsElement(byte[] buffer) :
8492 this(buffer, 0, (buffer != null ? buffer.Length : 0), false) { }
8494 public SendPacketsElement(byte[] buffer, int offset, int count) :
8495 this(buffer, offset, count, false) { }
8497 public SendPacketsElement(byte[] buffer, int offset, int count, bool endOfPacket) {
8498 if (buffer == null) {
8499 throw new ArgumentNullException("buffer");
8501 if (offset < 0 || offset > buffer.Length) {
8502 throw new ArgumentOutOfRangeException("offset");
8504 if (count < 0 || count > (buffer.Length - offset)) {
8505 throw new ArgumentOutOfRangeException("count");
8507 Contract.EndContractBlock();
8510 Initialize(null, buffer, offset, count, /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.Memory,*/
8513 Initialize(null, buffer, offset, count, UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.Memory,
8518 private void Initialize(string filePath, byte[] buffer, int offset, int count,
8519 /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags flags,*/ bool endOfPacket) {
8521 m_FilePath = filePath;
8526 m_endOfPacket = endOfPacket;
8530 m_Flags |= UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.EndOfPacket;
8535 // Filename property
8536 public string FilePath {
8537 get { return m_FilePath; }
8541 public byte[] Buffer {
8542 get { return m_Buffer; }
8547 get { return m_Count; }
8552 get { return m_Offset; }
8555 // EndOfPacket property
8556 public bool EndOfPacket {
8559 return m_endOfPacket;
8561 return (m_Flags & UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.EndOfPacket) != 0;
8567 #region designer support for System.Windows.dll
8568 //introduced for supporting design-time loading of System.Windows.dll
8569 [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
8570 [EditorBrowsable(EditorBrowsableState.Never)]
8571 public enum SocketClientAccessPolicyProtocol
8579 public class SocketAsyncEventArgs : EventArgs, IDisposable {
8581 // Struct sizes needed for some custom marshalling.
8582 internal static readonly int s_ControlDataSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.ControlData));
8583 internal static readonly int s_ControlDataIPv6Size = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6));
8584 internal static readonly int s_WSAMsgSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.WSAMsg));
8586 // AcceptSocket property variables.
8587 internal Socket m_AcceptSocket;
8588 private Socket m_ConnectSocket;
8590 // Buffer,Offset,Count property variables.
8591 internal byte[] m_Buffer;
8592 internal WSABuffer m_WSABuffer;
8593 internal IntPtr m_PtrSingleBuffer;
8594 internal int m_Count;
8595 internal int m_Offset;
8597 // BufferList property variables.
8598 internal IList<ArraySegment<byte> > m_BufferList;
8599 private bool m_BufferListChanged;
8600 internal WSABuffer[] m_WSABufferArray;
8602 // BytesTransferred property variables.
8603 private int m_BytesTransferred;
8605 // Completed event property variables.
8606 private event EventHandler<SocketAsyncEventArgs> m_Completed;
8607 private bool m_CompletedChanged;
8609 // DisconnectReuseSocket propery variables.
8610 private bool m_DisconnectReuseSocket;
8612 // LastOperation property variables.
8613 private SocketAsyncOperation m_CompletedOperation;
8615 // ReceiveMessageFromPacketInfo property variables.
8616 private IPPacketInformation m_ReceiveMessageFromPacketInfo;
8618 // RemoteEndPoint property variables.
8619 private EndPoint m_RemoteEndPoint;
8621 // SendPacketsFlags property variable.
8622 internal TransmitFileOptions m_SendPacketsFlags;
8624 // SendPacketsSendSize property variable.
8625 internal int m_SendPacketsSendSize;
8627 // SendPacketsElements property variables.
8628 internal SendPacketsElement[] m_SendPacketsElements;
8629 private SendPacketsElement[] m_SendPacketsElementsInternal;
8630 internal int m_SendPacketsElementsFileCount;
8631 internal int m_SendPacketsElementsBufferCount;
8633 // SocketError property variables.
8634 private SocketError m_SocketError;
8635 private Exception m_ConnectByNameError;
8637 // SocketFlags property variables.
8638 internal SocketFlags m_SocketFlags;
8640 // UserToken property variables.
8641 private object m_UserToken;
8643 // Internal buffer for AcceptEx when Buffer not supplied.
8644 internal byte[] m_AcceptBuffer;
8645 internal int m_AcceptAddressBufferCount;
8646 internal IntPtr m_PtrAcceptBuffer;
8648 // Internal SocketAddress buffer
8649 internal SocketAddress m_SocketAddress;
8650 private GCHandle m_SocketAddressGCHandle;
8651 private SocketAddress m_PinnedSocketAddress;
8652 internal IntPtr m_PtrSocketAddressBuffer;
8653 internal IntPtr m_PtrSocketAddressBufferSize;
8655 // Internal buffers for WSARecvMsg
8656 private byte[] m_WSAMessageBuffer;
8657 private GCHandle m_WSAMessageBufferGCHandle;
8658 internal IntPtr m_PtrWSAMessageBuffer;
8659 private byte[] m_ControlBuffer;
8660 private GCHandle m_ControlBufferGCHandle;
8661 internal IntPtr m_PtrControlBuffer;
8662 private WSABuffer[] m_WSARecvMsgWSABufferArray;
8663 private GCHandle m_WSARecvMsgWSABufferArrayGCHandle;
8664 private IntPtr m_PtrWSARecvMsgWSABufferArray;
8666 // Internal variables for SendPackets
8667 internal FileStream[] m_SendPacketsFileStreams;
8668 internal SafeHandle[] m_SendPacketsFileHandles;
8669 internal UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElement[] m_SendPacketsDescriptor;
8670 internal IntPtr m_PtrSendPacketsDescriptor;
8672 // Misc state variables.
8673 private ExecutionContext m_Context;
8674 private ExecutionContext m_ContextCopy;
8675 private ContextCallback m_ExecutionCallback;
8676 private Socket m_CurrentSocket;
8677 private bool m_DisposeCalled;
8679 // Controls thread safety via Interlocked
8680 private const int Configuring = -1;
8681 private const int Free = 0;
8682 private const int InProgress = 1;
8683 private const int Disposed = 2;
8684 private int m_Operating;
8686 // Overlapped object related variables.
8687 internal SafeNativeOverlapped m_PtrNativeOverlapped;
8688 private Overlapped m_Overlapped;
8689 private object[] m_ObjectsToPin;
8690 private enum PinState {
8698 private PinState m_PinState;
8699 private byte[] m_PinnedAcceptBuffer;
8700 private byte[] m_PinnedSingleBuffer;
8701 private int m_PinnedSingleBufferOffset;
8702 private int m_PinnedSingleBufferCount;
8704 private MultipleConnectAsync m_MultipleConnect;
8706 private static bool s_LoggingEnabled = Logging.On;
8708 #region designer support for System.Windows.dll
8709 //introduced for supporting design-time loading of System.Windows.dll
8710 [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
8711 [EditorBrowsable(EditorBrowsableState.Never)]
8712 public SocketClientAccessPolicyProtocol SocketClientAccessPolicyProtocol { get; set; }
8716 // Public constructor.
8717 public SocketAsyncEventArgs() {
8719 // Create callback delegate
8720 m_ExecutionCallback = new ContextCallback(ExecutionCallback);
8722 // Zero tells TransmitPackets to select a default send size.
8723 m_SendPacketsSendSize = 0;
8726 // AcceptSocket property.
8727 public Socket AcceptSocket {
8728 get { return m_AcceptSocket; }
8729 set { m_AcceptSocket = value; }
8732 public Socket ConnectSocket {
8733 get { return m_ConnectSocket; }
8737 public byte[] Buffer {
8738 get { return m_Buffer; }
8743 get { return m_Offset; }
8748 get { return m_Count; }
8751 // BufferList property.
8752 // Mutually exclusive with Buffer.
8753 // Setting this property with an existing non-null Buffer will throw.
8754 public IList<ArraySegment<byte> > BufferList {
8755 get { return m_BufferList; }
8759 if(value != null && m_Buffer != null) {
8760 throw new ArgumentException(SR.GetString(SR.net_ambiguousbuffers, "Buffer"));
8762 m_BufferList = value;
8763 m_BufferListChanged = true;
8764 CheckPinMultipleBuffers();
8771 // BytesTransferred property.
8772 public int BytesTransferred {
8773 get { return m_BytesTransferred; }
8776 // Completed property.
8777 public event EventHandler<SocketAsyncEventArgs> Completed {
8779 m_Completed += value;
8780 m_CompletedChanged = true;
8783 m_Completed -= value;
8784 m_CompletedChanged = true;
8788 // Method to raise Completed event.
8789 protected virtual void OnCompleted(SocketAsyncEventArgs e) {
8790 EventHandler<SocketAsyncEventArgs> handler = m_Completed;
8791 if(handler != null) {
8792 handler(e.m_CurrentSocket, e);
8796 // DisconnectResuseSocket property.
8797 public bool DisconnectReuseSocket {
8798 get { return m_DisconnectReuseSocket; }
8799 set { m_DisconnectReuseSocket = value; }
8802 // LastOperation property.
8803 public SocketAsyncOperation LastOperation {
8804 get { return m_CompletedOperation; }
8807 // ReceiveMessageFromPacketInfo property.
8808 public IPPacketInformation ReceiveMessageFromPacketInfo {
8809 get { return m_ReceiveMessageFromPacketInfo; }
8812 // RemoteEndPoint property.
8813 public EndPoint RemoteEndPoint {
8814 get { return m_RemoteEndPoint; }
8815 set { m_RemoteEndPoint = value; }
8818 // SendPacketsElements property.
8819 public SendPacketsElement[] SendPacketsElements {
8820 get { return m_SendPacketsElements; }
8824 m_SendPacketsElements = value;
8825 m_SendPacketsElementsInternal = null;
8832 // SendPacketsFlags property.
8833 public TransmitFileOptions SendPacketsFlags {
8834 get { return m_SendPacketsFlags; }
8835 set { m_SendPacketsFlags = value; }
8838 // SendPacketsSendSize property.
8839 public int SendPacketsSendSize {
8840 get { return m_SendPacketsSendSize; }
8841 set { m_SendPacketsSendSize = value; }
8844 // SocketError property.
8845 public SocketError SocketError {
8846 get { return m_SocketError; }
8847 set { m_SocketError = value; }
8850 public Exception ConnectByNameError {
8851 get { return m_ConnectByNameError; }
8854 // SocketFlags property.
8855 public SocketFlags SocketFlags {
8856 get { return m_SocketFlags; }
8857 set { m_SocketFlags = value; }
8860 // UserToken property.
8861 public object UserToken {
8862 get { return m_UserToken; }
8863 set { m_UserToken = value; }
8866 // SetBuffer(byte[], int, int) method.
8867 public void SetBuffer(byte [] buffer, int offset, int count) {
8868 SetBufferInternal(buffer, offset, count);
8871 // SetBuffer(int, int) method.
8872 public void SetBuffer(int offset, int count) {
8873 SetBufferInternal(m_Buffer, offset, count);
8876 private void SetBufferInternal(byte [] buffer, int offset, int count) {
8879 if (buffer == null) {
8881 // Clear out existing buffer.
8887 // Can't have both Buffer and BufferList
8888 if(m_BufferList != null) {
8889 throw new ArgumentException(SR.GetString(SR.net_ambiguousbuffers, "BufferList"));
8891 // Offset and count can't be negative and the
8892 // combination must be in bounds of the array.
8893 if (offset < 0 || offset > buffer.Length) {
8894 throw new ArgumentOutOfRangeException("offset");
8896 if (count < 0 || count > (buffer.Length - offset)) {
8897 throw new ArgumentOutOfRangeException("count");
8904 // Pin new or unpin old buffer.
8905 CheckPinSingleBuffer(true);
8913 // Method to update internal state after [....] or async completion.
8914 internal void SetResults(SocketError socketError, int bytesTransferred, SocketFlags flags) {
8915 m_SocketError = socketError;
8916 m_ConnectByNameError = null;
8917 m_BytesTransferred = bytesTransferred;
8918 m_SocketFlags = flags;
8921 internal void SetResults(Exception exception, int bytesTransferred, SocketFlags flags) {
8922 m_ConnectByNameError = exception;
8923 m_BytesTransferred = bytesTransferred;
8924 m_SocketFlags = flags;
8926 if (exception == null) {
8927 m_SocketError = SocketError.Success;
8930 SocketException socketException = exception as SocketException;
8931 if (socketException != null) {
8932 m_SocketError = socketException.SocketErrorCode;
8935 m_SocketError = SocketError.SocketError;
8940 // Context callback delegate.
8941 private void ExecutionCallback(object ignored) {
8945 // Method to mark this object as no longer "in-use".
8946 // Will also execute a Dispose deferred because I/O was in progress.
8947 internal void Complete() {
8949 // Mark as not in-use
8952 // Check for deferred Dispose().
8953 // The deferred Dispose is not guaranteed if Dispose is called while an operation is in progress.
8954 // The m_DisposeCalled variable is not managed in a thread-safe manner on purpose for performance.
8955 if (m_DisposeCalled) {
8960 // Dispose call to implement IDisposable.
8961 public void Dispose() {
8963 // Remember that Dispose was called.
8964 m_DisposeCalled = true;
8966 // Check if this object is in-use for an async socket operation.
8967 if(Interlocked.CompareExchange(ref m_Operating, Disposed, Free) != Free) {
8968 // Either already disposed or will be disposed when current operation completes.
8972 // OK to dispose now.
8973 // Free native overlapped data.
8974 FreeOverlapped(false);
8976 // Don't bother finalizing later.
8977 GC.SuppressFinalize(this);
8981 ~SocketAsyncEventArgs() {
8982 FreeOverlapped(true);
8985 // Us a try/Finally to make sure Complete is called when you're done
8986 private void StartConfiguring() {
8987 int status = Interlocked.CompareExchange(ref m_Operating, Configuring, Free);
8988 if (status == InProgress || status == Configuring) {
8989 throw new InvalidOperationException(SR.GetString(SR.net_socketopinprogress));
8991 else if (status == Disposed)
8993 throw new ObjectDisposedException(GetType().FullName);
8997 // Method called to prepare for a native async socket call.
8998 // This method performs the tasks common to all socket operations.
8999 internal void StartOperationCommon(Socket socket) {
9001 // Change status to "in-use".
9002 if(Interlocked.CompareExchange(ref m_Operating, InProgress, Free) != Free) {
9004 // If it was already "in-use" check if Dispose was called.
9005 if(m_DisposeCalled) {
9007 // Dispose was called - throw ObjectDisposed.
9008 throw new ObjectDisposedException(GetType().FullName);
9011 // Only one at a time.
9012 throw new InvalidOperationException(SR.GetString(SR.net_socketopinprogress));
9015 // Prepare execution context for callback.
9017 if (ExecutionContext.IsFlowSuppressed()) {
9019 // Fast path for when flow is suppressed.
9022 m_ContextCopy = null;
9026 // Flow is not suppressed.
9028 // If event delegates have changed or socket has changed
9029 // then discard any existing context.
9031 if (m_CompletedChanged || socket != m_CurrentSocket) {
9033 m_CompletedChanged = false;
9035 m_ContextCopy = null;
9038 // Capture execution context if none already.
9040 if (m_Context == null) {
9041 m_Context = ExecutionContext.Capture();
9044 // If there is an execution context we need a fresh copy for each completion.
9046 if(m_Context != null) {
9047 m_ContextCopy = m_Context.CreateCopy();
9051 // Remember current socket.
9052 m_CurrentSocket = socket;
9055 internal void StartOperationAccept() {
9056 // Remember the operation type.
9057 m_CompletedOperation = SocketAsyncOperation.Accept;
9059 // AcceptEx needs a single buffer with room for two special sockaddr data structures.
9060 // It can also take additional buffer space in front of those special sockaddr
9061 // structures that can be filled in with initial data coming in on a connection.
9063 // First calculate the special AcceptEx address buffer size.
9064 // It is the size of two native sockaddr buffers with 16 extra bytes each.
9065 // The native sockaddr buffers vary by address family so must reference the current socket.
9066 m_AcceptAddressBufferCount = 2 * (m_CurrentSocket.m_RightEndPoint.Serialize().Size + 16);
9068 // If our caller specified a buffer (willing to get received data with the Accept) then
9069 // it needs to be large enough for the two special sockaddr buffers that AcceptEx requires.
9070 // Throw if that buffer is not large enough.
9071 if(m_Buffer != null) {
9073 // Caller specified a buffer - see if it is large enough
9074 if(m_Count < m_AcceptAddressBufferCount) {
9075 throw new ArgumentException(SR.GetString(SR.net_buffercounttoosmall, "Count"));
9077 // Buffer is already pinned.
9081 // Caller didn't specify a buffer so use an internal one.
9082 // See if current internal one is big enough, otherwise create a new one.
9083 if(m_AcceptBuffer == null || m_AcceptBuffer.Length < m_AcceptAddressBufferCount) {
9084 m_AcceptBuffer = new byte[m_AcceptAddressBufferCount];
9086 CheckPinSingleBuffer(false);
9090 internal void StartOperationConnect() {
9091 // Remember the operation type.
9092 m_CompletedOperation = SocketAsyncOperation.Connect;
9093 m_MultipleConnect = null;
9094 m_ConnectSocket = null;
9096 // ConnectEx uses a sockaddr buffer containing he remote address to which to connect.
9097 // It can also optionally take a single buffer of data to send after the connection is complete.
9099 // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
9100 // The optional buffer is pinned using the Overlapped.UnsafePack method that takes a single object to pin.
9102 PinSocketAddressBuffer();
9106 internal void StartOperationWrapperConnect(MultipleConnectAsync args) {
9107 m_CompletedOperation = SocketAsyncOperation.Connect;
9108 m_MultipleConnect = args;
9109 m_ConnectSocket = null;
9112 internal void CancelConnectAsync() {
9113 if (m_Operating == InProgress && m_CompletedOperation == SocketAsyncOperation.Connect) {
9115 if (m_MultipleConnect != null) {
9116 // if a multiple connect is in progress, abort it
9117 m_MultipleConnect.Cancel();
9120 // otherwise we're doing a normal ConnectAsync - cancel it by closing the socket
9121 // m_CurrentSocket will only be null if m_MultipleConnect was set, so we don't have to check
9122 GlobalLog.Assert(m_CurrentSocket != null, "SocketAsyncEventArgs::CancelConnectAsync - CurrentSocket and MultipleConnect both null!");
9123 m_CurrentSocket.Close();
9128 internal void StartOperationDisconnect() {
9129 // Remember the operation type.
9130 m_CompletedOperation = SocketAsyncOperation.Disconnect;
9134 internal void StartOperationReceive() {
9135 // Remember the operation type.
9136 m_CompletedOperation = SocketAsyncOperation.Receive;
9138 // WWSARecv uses a WSABuffer array describing buffers of data to send.
9139 // Single and multiple buffers are handled differently so as to optimize
9140 // performance for the more common single buffer case.
9141 // For a single buffer:
9142 // The Overlapped.UnsafePack method is used that takes a single object to pin.
9143 // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
9144 // For multiple buffers:
9145 // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
9146 // An array to reference the multiple buffer is allocated.
9147 // An array of WSABuffer descriptors is allocated.
9150 internal void StartOperationReceiveFrom() {
9151 // Remember the operation type.
9152 m_CompletedOperation = SocketAsyncOperation.ReceiveFrom;
9154 // WSARecvFrom uses e a WSABuffer array describing buffers in which to
9155 // receive data and from which to send data respectively. Single and multiple buffers
9156 // are handled differently so as to optimize performance for the more common single buffer case.
9157 // For a single buffer:
9158 // The Overlapped.UnsafePack method is used that takes a single object to pin.
9159 // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
9160 // For multiple buffers:
9161 // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
9162 // An array to reference the multiple buffer is allocated.
9163 // An array of WSABuffer descriptors is allocated.
9164 // WSARecvFrom and WSASendTo also uses a sockaddr buffer in which to store the address from which the data was received.
9165 // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
9166 PinSocketAddressBuffer();
9169 internal void StartOperationReceiveMessageFrom() {
9170 // Remember the operation type.
9171 m_CompletedOperation = SocketAsyncOperation.ReceiveMessageFrom;
9173 // WSARecvMsg uses a WSAMsg descriptor.
9174 // The WSAMsg buffer is pinned with a GCHandle to avoid complicating the use of Overlapped.
9175 // WSAMsg contains a pointer to a sockaddr.
9176 // The sockaddr is pinned with a GCHandle to avoid complicating the use of Overlapped.
9177 // WSAMsg contains a pointer to a WSABuffer array describing data buffers.
9178 // WSAMsg also contains a single WSABuffer describing a control buffer.
9180 PinSocketAddressBuffer();
9182 // Create and pin a WSAMessageBuffer if none already.
9183 if(m_WSAMessageBuffer == null) {
9184 m_WSAMessageBuffer = new byte[s_WSAMsgSize];
9185 m_WSAMessageBufferGCHandle = GCHandle.Alloc(m_WSAMessageBuffer, GCHandleType.Pinned);
9186 m_PtrWSAMessageBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSAMessageBuffer, 0);
9189 // Create and pin an appropriately sized control buffer if none already
9190 IPAddress ipAddress = (m_SocketAddress.Family == AddressFamily.InterNetworkV6
9191 ? m_SocketAddress.GetIPAddress() : null);
9192 bool ipv4 = (m_CurrentSocket.AddressFamily == AddressFamily.InterNetwork
9193 || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode
9194 bool ipv6 = m_CurrentSocket.AddressFamily == AddressFamily.InterNetworkV6;
9196 if(ipv4 && (m_ControlBuffer == null || m_ControlBuffer.Length != s_ControlDataSize)) {
9197 if(m_ControlBufferGCHandle.IsAllocated) {
9198 m_ControlBufferGCHandle.Free();
9200 m_ControlBuffer = new byte[s_ControlDataSize];
9201 } else if(ipv6 && (m_ControlBuffer == null || m_ControlBuffer.Length != s_ControlDataIPv6Size)) {
9202 if(m_ControlBufferGCHandle.IsAllocated) {
9203 m_ControlBufferGCHandle.Free();
9205 m_ControlBuffer = new byte[s_ControlDataIPv6Size];
9207 if(!m_ControlBufferGCHandle.IsAllocated) {
9208 m_ControlBufferGCHandle = GCHandle.Alloc(m_ControlBuffer, GCHandleType.Pinned);
9209 m_PtrControlBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_ControlBuffer, 0);
9212 // If single buffer we need a pinned 1 element WSABuffer.
9213 if(m_Buffer != null) {
9214 if(m_WSARecvMsgWSABufferArray == null) {
9215 m_WSARecvMsgWSABufferArray = new WSABuffer[1];
9217 m_WSARecvMsgWSABufferArray[0].Pointer = m_PtrSingleBuffer;
9218 m_WSARecvMsgWSABufferArray[0].Length = m_Count;
9219 m_WSARecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(m_WSARecvMsgWSABufferArray, GCHandleType.Pinned);
9220 m_PtrWSARecvMsgWSABufferArray = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSARecvMsgWSABufferArray, 0);
9222 // just pin the multi-buffer WSABuffer
9223 m_WSARecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(m_WSABufferArray, GCHandleType.Pinned);
9224 m_PtrWSARecvMsgWSABufferArray = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSABufferArray, 0);
9227 // Fill in WSAMessageBuffer
9229 UnsafeNclNativeMethods.OSSOCK.WSAMsg* pMessage = (UnsafeNclNativeMethods.OSSOCK.WSAMsg*)m_PtrWSAMessageBuffer;;
9230 pMessage->socketAddress = m_PtrSocketAddressBuffer;
9231 pMessage->addressLength = (uint)m_SocketAddress.Size;
9232 pMessage->buffers = m_PtrWSARecvMsgWSABufferArray;
9233 if(m_Buffer != null) {
9234 pMessage->count = (uint)1;
9236 pMessage->count = (uint)m_WSABufferArray.Length;
9238 if(m_ControlBuffer != null) {
9239 pMessage->controlBuffer.Pointer = m_PtrControlBuffer;
9240 pMessage->controlBuffer.Length = m_ControlBuffer.Length;
9242 pMessage->flags = m_SocketFlags;
9246 internal void StartOperationSend() {
9247 // Remember the operation type.
9248 m_CompletedOperation = SocketAsyncOperation.Send;
9250 // WSASend uses a WSABuffer array describing buffers of data to send.
9251 // Single and multiple buffers are handled differently so as to optimize
9252 // performance for the more common single buffer case.
9253 // For a single buffer:
9254 // The Overlapped.UnsafePack method is used that takes a single object to pin.
9255 // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
9256 // For multiple buffers:
9257 // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
9258 // An array to reference the multiple buffer is allocated.
9259 // An array of WSABuffer descriptors is allocated.
9262 internal void StartOperationSendPackets() {
9263 // Remember the operation type.
9264 m_CompletedOperation = SocketAsyncOperation.SendPackets;
9266 // Prevent mutithreaded manipulation of the list.
9267 if (m_SendPacketsElements != null) {
9268 m_SendPacketsElementsInternal = (SendPacketsElement[])m_SendPacketsElements.Clone();
9271 // TransmitPackets uses an array of TRANSMIT_PACKET_ELEMENT structs as
9272 // descriptors for buffers and files to be sent. It also takes a send size
9273 // and some flags. The TRANSMIT_PACKET_ELEMENT for a file contains a native file handle.
9274 // This function basically opens the files to get the file handles, pins down any buffers
9275 // specified and builds the native TRANSMIT_PACKET_ELEMENT array that will be passed
9276 // to TransmitPackets.
9278 // Scan the elements to count files and buffers
9279 m_SendPacketsElementsFileCount = 0;
9280 m_SendPacketsElementsBufferCount = 0;
9281 foreach (SendPacketsElement spe in m_SendPacketsElementsInternal) {
9283 if(spe.m_FilePath != null) {
9284 m_SendPacketsElementsFileCount++;
9286 if(spe.m_Buffer != null && spe.m_Count > 0) {
9287 m_SendPacketsElementsBufferCount++;
9292 // Attempt to open the files if any
9293 if(m_SendPacketsElementsFileCount > 0) {
9295 // Create arrays for streams and handles
9296 m_SendPacketsFileStreams = new FileStream[m_SendPacketsElementsFileCount];
9297 m_SendPacketsFileHandles = new SafeHandle[m_SendPacketsElementsFileCount];
9299 // Loop through the elements attempting to open each files and get its handle
9301 foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
9302 if(spe != null && spe.m_FilePath != null) {
9303 Exception fileStreamException = null;
9305 // Create a FileStream to open the file
9306 m_SendPacketsFileStreams[index] =
9307 new FileStream(spe.m_FilePath,FileMode.Open,FileAccess.Read,FileShare.Read);
9309 catch (Exception ex) {
9310 // Save the exception to throw after closing any previous successful file opens
9311 fileStreamException = ex;
9313 if (fileStreamException != null) {
9314 // Got exception opening a file - do some cleanup then throw
9315 for(int i = 0; i < m_SendPacketsElementsFileCount; i++) {
9316 // Dereference handles
9317 m_SendPacketsFileHandles[i] = null;
9318 // Close any open streams
9319 if(m_SendPacketsFileStreams[i] != null) {
9320 m_SendPacketsFileStreams[i].Close();
9321 m_SendPacketsFileStreams[i] = null;
9324 throw fileStreamException;
9326 // Get the file handle from the stream
9327 ExceptionHelper.UnmanagedPermission.Assert();
9329 m_SendPacketsFileHandles[index] = m_SendPacketsFileStreams[index].SafeFileHandle;
9332 SecurityPermission.RevertAssert();
9339 CheckPinSendPackets();
9342 internal void StartOperationSendTo() {
9343 // Remember the operation type.
9344 m_CompletedOperation = SocketAsyncOperation.SendTo;
9346 // WSASendTo uses a WSABuffer array describing buffers in which to
9347 // receive data and from which to send data respectively. Single and multiple buffers
9348 // are handled differently so as to optimize performance for the more common single buffer case.
9349 // For a single buffer:
9350 // The Overlapped.UnsafePack method is used that takes a single object to pin.
9351 // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
9352 // For multiple buffers:
9353 // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
9354 // An array to reference the multiple buffer is allocated.
9355 // An array of WSABuffer descriptors is allocated.
9356 // WSARecvFrom and WSASendTo also uses a sockaddr buffer in which to store the address from which the data was received.
9357 // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
9358 PinSocketAddressBuffer();
9361 // Method to ensure Overlapped object exists for operations that need no data buffer.
9362 private void CheckPinNoBuffer() {
9364 if (m_PinState == PinState.None) {
9365 SetupOverlappedSingle(true);
9369 // Method to maintain pinned state of single buffer
9370 private void CheckPinSingleBuffer(bool pinUsersBuffer) {
9372 if (pinUsersBuffer) {
9374 // Using app supplied buffer.
9376 if (m_Buffer == null) {
9378 // No user buffer is set so unpin any existing single buffer pinning.
9379 if(m_PinState == PinState.SingleBuffer) {
9380 FreeOverlapped(false);
9385 if(m_PinState == PinState.SingleBuffer && m_PinnedSingleBuffer == m_Buffer) {
9386 // This buffer is already pinned - update if offset or count has changed.
9387 if (m_Offset != m_PinnedSingleBufferOffset) {
9388 m_PinnedSingleBufferOffset = m_Offset;
9389 m_PtrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, m_Offset);
9390 m_WSABuffer.Pointer = m_PtrSingleBuffer;
9392 if (m_Count != m_PinnedSingleBufferCount) {
9393 m_PinnedSingleBufferCount = m_Count;
9394 m_WSABuffer.Length = m_Count;
9397 FreeOverlapped(false);
9398 SetupOverlappedSingle(true);
9403 // Using internal accept buffer.
9405 if(!(m_PinState == PinState.SingleAcceptBuffer) || !(m_PinnedSingleBuffer == m_AcceptBuffer)) {
9407 // Not already pinned - so pin it.
9408 FreeOverlapped(false);
9409 SetupOverlappedSingle(false);
9414 // Method to ensure Overlapped object exists with appropriate multiple buffers pinned.
9415 private void CheckPinMultipleBuffers() {
9417 if (m_BufferList == null) {
9419 // No buffer list is set so unpin any existing multiple buffer pinning.
9421 if(m_PinState == PinState.MultipleBuffer) {
9422 FreeOverlapped(false);
9426 if(!(m_PinState == PinState.MultipleBuffer) || m_BufferListChanged) {
9427 // Need to setup new Overlapped
9428 m_BufferListChanged = false;
9429 FreeOverlapped(false);
9432 SetupOverlappedMultiple();
9436 FreeOverlapped(false);
9443 // Method to ensure Overlapped object exists with appropriate buffers pinned.
9444 private void CheckPinSendPackets() {
9445 if(m_PinState != PinState.None) {
9446 FreeOverlapped(false);
9448 SetupOverlappedSendPackets();
9451 // Method to ensure appropriate SocketAddress buffer is pinned.
9452 private void PinSocketAddressBuffer() {
9453 // Check if already pinned.
9454 if(m_PinnedSocketAddress == m_SocketAddress) {
9458 // Unpin any existing.
9459 if(m_SocketAddressGCHandle.IsAllocated) {
9460 m_SocketAddressGCHandle.Free();
9463 // Pin down the new one.
9464 m_SocketAddressGCHandle = GCHandle.Alloc(m_SocketAddress.m_Buffer, GCHandleType.Pinned);
9465 m_SocketAddress.CopyAddressSizeIntoBuffer();
9466 m_PtrSocketAddressBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_SocketAddress.m_Buffer, 0);
9467 m_PtrSocketAddressBufferSize = Marshal.UnsafeAddrOfPinnedArrayElement(m_SocketAddress.m_Buffer, m_SocketAddress.GetAddressSizeOffset());
9468 m_PinnedSocketAddress = m_SocketAddress;
9471 // Method to clean up any existing Overlapped object and related state variables.
9472 private void FreeOverlapped(bool checkForShutdown) {
9473 if (!checkForShutdown || !NclUtilities.HasShutdownStarted) {
9475 // Free the overlapped object
9477 if(m_PtrNativeOverlapped != null && !m_PtrNativeOverlapped.IsInvalid) {
9478 m_PtrNativeOverlapped.Dispose();
9479 m_PtrNativeOverlapped = null;
9480 m_Overlapped = null;
9481 m_PinState = PinState.None;
9482 m_PinnedAcceptBuffer = null;
9483 m_PinnedSingleBuffer = null;
9484 m_PinnedSingleBufferOffset = 0;
9485 m_PinnedSingleBufferCount = 0;
9488 // Free any alloc'd GCHandles
9490 if(m_SocketAddressGCHandle.IsAllocated) {
9491 m_SocketAddressGCHandle.Free();
9493 if(m_WSAMessageBufferGCHandle.IsAllocated) {
9494 m_WSAMessageBufferGCHandle.Free();
9496 if(m_WSARecvMsgWSABufferArrayGCHandle.IsAllocated) {
9497 m_WSARecvMsgWSABufferArrayGCHandle.Free();
9499 if(m_ControlBufferGCHandle.IsAllocated) {
9500 m_ControlBufferGCHandle.Free();
9506 // Method to setup an Overlapped object with either m_Buffer or m_AcceptBuffer pinned.
9507 unsafe private void SetupOverlappedSingle(bool pinSingleBuffer) {
9509 // Alloc new Overlapped.
9510 m_Overlapped = new Overlapped();
9512 // Pin buffer, get native pointers, and fill in WSABuffer descriptor.
9513 if(pinSingleBuffer) {
9514 if(m_Buffer != null) {
9515 #if SOCKETTHREADPOOL
9516 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9517 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_Buffer));
9519 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_Buffer));
9521 m_PinnedSingleBuffer = m_Buffer;
9522 m_PinnedSingleBufferOffset = m_Offset;
9523 m_PinnedSingleBufferCount = m_Count;
9524 m_PtrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, m_Offset);
9525 m_PtrAcceptBuffer = IntPtr.Zero;
9526 m_WSABuffer.Pointer = m_PtrSingleBuffer;
9527 m_WSABuffer.Length = m_Count;
9528 m_PinState = PinState.SingleBuffer;
9530 #if SOCKETTHREADPOOL
9531 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9532 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, null));
9534 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, null));
9536 m_PinnedSingleBuffer = null;
9537 m_PinnedSingleBufferOffset = 0;
9538 m_PinnedSingleBufferCount = 0;
9539 m_PtrSingleBuffer = IntPtr.Zero;
9540 m_PtrAcceptBuffer = IntPtr.Zero;
9541 m_WSABuffer.Pointer = m_PtrSingleBuffer;
9542 m_WSABuffer.Length = m_Count;
9543 m_PinState = PinState.NoBuffer;
9546 #if SOCKETTHREADPOOL
9547 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9548 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_AcceptBuffer));
9550 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_AcceptBuffer));
9552 m_PinnedAcceptBuffer = m_AcceptBuffer;
9553 m_PtrAcceptBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_AcceptBuffer, 0);
9554 m_PtrSingleBuffer = IntPtr.Zero;
9555 m_PinState = PinState.SingleAcceptBuffer;
9559 // Method to setup an Overlapped object with with multiple buffers pinned.
9560 unsafe private void SetupOverlappedMultiple() {
9562 ArraySegment<byte>[] tempList = new ArraySegment<byte>[m_BufferList.Count];
9563 m_BufferList.CopyTo(tempList, 0);
9565 // Alloc new Overlapped.
9566 m_Overlapped = new Overlapped();
9568 // Number of things to pin is number of buffers.
9569 // Ensure we have properly sized object array.
9570 if(m_ObjectsToPin == null || (m_ObjectsToPin.Length != tempList.Length)) {
9571 m_ObjectsToPin = new object[tempList.Length];
9574 // Fill in object array.
9575 for(int i = 0; i < (tempList.Length); i++) {
9576 m_ObjectsToPin[i] = tempList[i].Array;
9579 if(m_WSABufferArray == null || m_WSABufferArray.Length != tempList.Length) {
9580 m_WSABufferArray = new WSABuffer[tempList.Length];
9583 // Pin buffers and fill in WSABuffer descriptor pointers and lengths
9584 #if SOCKETTHREADPOOL
9585 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9586 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_ObjectsToPin));
9588 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_ObjectsToPin));
9590 for(int i = 0; i < tempList.Length; i++) {
9591 ArraySegment<byte> localCopy = tempList[i];
9592 ValidationHelper.ValidateSegment(localCopy);
9593 m_WSABufferArray[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(localCopy.Array, localCopy.Offset);
9594 m_WSABufferArray[i].Length = localCopy.Count;
9596 m_PinState = PinState.MultipleBuffer;
9599 // Method to setup an Overlapped object for SendPacketsAsync.
9600 unsafe private void SetupOverlappedSendPackets() {
9604 // Alloc new Overlapped.
9605 m_Overlapped = new Overlapped();
9607 // Alloc native descriptor.
9608 m_SendPacketsDescriptor =
9609 new UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElement[m_SendPacketsElementsFileCount + m_SendPacketsElementsBufferCount];
9611 // Number of things to pin is number of buffers + 1 (native descriptor).
9612 // Ensure we have properly sized object array.
9613 if(m_ObjectsToPin == null || (m_ObjectsToPin.Length != m_SendPacketsElementsBufferCount + 1)) {
9614 m_ObjectsToPin = new object[m_SendPacketsElementsBufferCount + 1];
9617 // Fill in objects to pin array. Native descriptor buffer first and then user specified buffers.
9618 m_ObjectsToPin[0] = m_SendPacketsDescriptor;
9620 foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
9621 if(spe != null && spe.m_Buffer != null && spe.m_Count > 0) {
9622 m_ObjectsToPin[index] = spe.m_Buffer;
9628 #if SOCKETTHREADPOOL
9629 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9630 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_ObjectsToPin));
9632 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_ObjectsToPin));
9635 // Get pointer to native descriptor.
9636 m_PtrSendPacketsDescriptor = Marshal.UnsafeAddrOfPinnedArrayElement(m_SendPacketsDescriptor, 0);
9638 // Fill in native descriptor.
9639 int descriptorIndex = 0;
9641 foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
9643 if(spe.m_Buffer != null && spe.m_Count > 0) {
9645 m_SendPacketsDescriptor[descriptorIndex].buffer = Marshal.UnsafeAddrOfPinnedArrayElement(spe.m_Buffer, spe.m_Offset);
9646 m_SendPacketsDescriptor[descriptorIndex].length = (uint)spe.m_Count;
9647 m_SendPacketsDescriptor[descriptorIndex].flags = spe.m_Flags;
9649 } else if (spe.m_FilePath != null) {
9651 m_SendPacketsDescriptor[descriptorIndex].fileHandle = m_SendPacketsFileHandles[fileIndex].DangerousGetHandle();
9652 m_SendPacketsDescriptor[descriptorIndex].fileOffset = spe.m_Offset;
9653 m_SendPacketsDescriptor[descriptorIndex].length = (uint)spe.m_Count;
9654 m_SendPacketsDescriptor[descriptorIndex].flags = spe.m_Flags;
9661 m_PinState = PinState.SendPackets;
9664 internal void LogBuffer(int size) {
9665 switch(m_PinState) {
9666 case PinState.SingleAcceptBuffer:
9667 Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", m_AcceptBuffer, 0, size);
9669 case PinState.SingleBuffer:
9670 Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", m_Buffer, m_Offset, size);
9672 case PinState.MultipleBuffer:
9673 foreach(WSABuffer wsaBuffer in m_WSABufferArray) {
9674 Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", wsaBuffer.Pointer, Math.Min(wsaBuffer.Length, size));
9675 if((size -= wsaBuffer.Length) <= 0)
9684 internal void LogSendPacketsBuffers(int size) {
9685 foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
9687 if(spe.m_Buffer != null && spe.m_Count > 0) {
9689 Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)Buffer", spe.m_Buffer, spe.m_Offset, Math.Min(spe.m_Count, size));
9690 } else if(spe.m_FilePath != null) {
9692 Logging.PrintInfo(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", SR.GetString(SR.net_log_socket_not_logged_file, spe.m_FilePath));
9698 internal void UpdatePerfCounters(int size, bool sendOp) {
9699 #if !FEATURE_PAL // perfcounter
9701 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, size);
9702 if(m_CurrentSocket.Transport == TransportType.Udp) {
9703 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
9706 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, size);
9707 if(m_CurrentSocket.Transport == TransportType.Udp) {
9708 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
9714 internal void FinishOperationSyncFailure(SocketError socketError, int bytesTransferred, SocketFlags flags) {
9715 SetResults(socketError, bytesTransferred, flags);
9717 // this will be null if we're doing a static ConnectAsync to a DnsEndPoint with AddressFamily.Unspecified;
9718 // the attempt socket will be closed anyways, so not updating the state is OK
9719 if (m_CurrentSocket != null) {
9720 m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
9726 internal void FinishConnectByNameSyncFailure(Exception exception, int bytesTransferred, SocketFlags flags) {
9727 SetResults(exception, bytesTransferred, flags);
9729 if (m_CurrentSocket != null) {
9730 m_CurrentSocket.UpdateStatusAfterSocketError(m_SocketError);
9736 internal void FinishOperationAsyncFailure(SocketError socketError, int bytesTransferred, SocketFlags flags) {
9737 SetResults(socketError, bytesTransferred, flags);
9739 // this will be null if we're doing a static ConnectAsync to a DnsEndPoint with AddressFamily.Unspecified;
9740 // the attempt socket will be closed anyways, so not updating the state is OK
9741 if (m_CurrentSocket != null) {
9742 m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
9746 if(m_Context == null) {
9749 ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
9753 internal void FinishOperationAsyncFailure(Exception exception, int bytesTransferred, SocketFlags flags) {
9754 SetResults(exception, bytesTransferred, flags);
9756 if (m_CurrentSocket != null) {
9757 m_CurrentSocket.UpdateStatusAfterSocketError(m_SocketError);
9760 if (m_Context == null) {
9763 ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
9767 internal void FinishWrapperConnectSuccess(Socket connectSocket, int bytesTransferred, SocketFlags flags) {
9769 SetResults(SocketError.Success, bytesTransferred, flags);
9770 m_CurrentSocket = connectSocket;
9771 m_ConnectSocket = connectSocket;
9773 // Complete the operation and raise the event
9775 if (m_ContextCopy == null) {
9778 ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
9782 internal void FinishOperationSuccess(SocketError socketError, int bytesTransferred, SocketFlags flags) {
9784 SetResults(socketError, bytesTransferred, flags);
9786 switch(m_CompletedOperation) {
9788 case SocketAsyncOperation.Accept:
9791 if (bytesTransferred > 0) {
9792 // Log and Perf counters.
9793 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9794 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
9797 // Get the endpoint.
9798 SocketAddress remoteSocketAddress = m_CurrentSocket.m_RightEndPoint.Serialize();
9801 int localAddrLength;
9805 m_CurrentSocket.GetAcceptExSockaddrs(
9806 m_PtrSingleBuffer != IntPtr.Zero ? m_PtrSingleBuffer : m_PtrAcceptBuffer,
9807 m_Count != 0 ? m_Count - m_AcceptAddressBufferCount : 0,
9808 m_AcceptAddressBufferCount / 2,
9809 m_AcceptAddressBufferCount / 2,
9811 out localAddrLength,
9813 out remoteSocketAddress.m_Size
9815 Marshal.Copy(remoteAddr, remoteSocketAddress.m_Buffer, 0, remoteSocketAddress.m_Size);
9817 // Set the socket context.
9818 IntPtr handle = m_CurrentSocket.SafeHandle.DangerousGetHandle();
9820 socketError = UnsafeNclNativeMethods.OSSOCK.setsockopt(
9821 m_AcceptSocket.SafeHandle,
9822 SocketOptionLevel.Socket,
9823 SocketOptionName.UpdateAcceptContext,
9825 Marshal.SizeOf(handle));
9827 if(socketError == SocketError.SocketError) {
9828 socketError = (SocketError)Marshal.GetLastWin32Error();
9831 catch(ObjectDisposedException) {
9832 socketError = SocketError.OperationAborted;
9835 if(socketError == SocketError.Success) {
9836 m_AcceptSocket = m_CurrentSocket.UpdateAcceptSocket(m_AcceptSocket, m_CurrentSocket.m_RightEndPoint.Create(remoteSocketAddress), false);
9838 if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, m_AcceptSocket,
9839 SR.GetString(SR.net_log_socket_accepted, m_AcceptSocket.RemoteEndPoint, m_AcceptSocket.LocalEndPoint));
9841 SetResults(socketError, bytesTransferred, SocketFlags.None);
9842 m_AcceptSocket = null;
9846 case SocketAsyncOperation.Connect:
9848 if (bytesTransferred > 0) {
9849 // Log and Perf counters.
9850 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9851 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
9854 // Update the socket context.
9856 socketError = UnsafeNclNativeMethods.OSSOCK.setsockopt(
9857 m_CurrentSocket.SafeHandle,
9858 SocketOptionLevel.Socket,
9859 SocketOptionName.UpdateConnectContext,
9862 if(socketError == SocketError.SocketError) {
9863 socketError = (SocketError)Marshal.GetLastWin32Error();
9866 catch(ObjectDisposedException) {
9867 socketError = SocketError.OperationAborted;
9870 // Mark socket connected.
9871 if(socketError == SocketError.Success) {
9872 if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, m_CurrentSocket,
9873 SR.GetString(SR.net_log_socket_connected, m_CurrentSocket.LocalEndPoint, m_CurrentSocket.RemoteEndPoint));
9875 m_CurrentSocket.SetToConnected();
9876 m_ConnectSocket = m_CurrentSocket;
9880 case SocketAsyncOperation.Disconnect:
9882 m_CurrentSocket.SetToDisconnected();
9883 m_CurrentSocket.m_RemoteEndPoint = null;
9887 case SocketAsyncOperation.Receive:
9889 if (bytesTransferred > 0) {
9890 // Log and Perf counters.
9891 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9892 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
9896 case SocketAsyncOperation.ReceiveFrom:
9898 if (bytesTransferred > 0) {
9899 // Log and Perf counters.
9900 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9901 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
9904 // Deal with incoming address.
9905 m_SocketAddress.SetSize(m_PtrSocketAddressBufferSize);
9906 SocketAddress socketAddressOriginal = m_RemoteEndPoint.Serialize();
9907 if(!socketAddressOriginal.Equals(m_SocketAddress)) {
9909 m_RemoteEndPoint = m_RemoteEndPoint.Create(m_SocketAddress);
9916 case SocketAsyncOperation.ReceiveMessageFrom:
9918 if (bytesTransferred > 0) {
9919 // Log and Perf counters.
9920 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9921 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
9924 // Deal with incoming address.
9925 m_SocketAddress.SetSize(m_PtrSocketAddressBufferSize);
9926 socketAddressOriginal = m_RemoteEndPoint.Serialize();
9927 if(!socketAddressOriginal.Equals(m_SocketAddress)) {
9929 m_RemoteEndPoint = m_RemoteEndPoint.Create(m_SocketAddress);
9935 // Extract the packet information.
9937 IPAddress address = null;
9938 UnsafeNclNativeMethods.OSSOCK.WSAMsg* PtrMessage = (UnsafeNclNativeMethods.OSSOCK.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(m_WSAMessageBuffer, 0);
9941 if(m_ControlBuffer.Length == s_ControlDataSize) {
9942 UnsafeNclNativeMethods.OSSOCK.ControlData controlData = (UnsafeNclNativeMethods.OSSOCK.ControlData)Marshal.PtrToStructure(PtrMessage->controlBuffer.Pointer, typeof(UnsafeNclNativeMethods.OSSOCK.ControlData));
9943 if(controlData.length != UIntPtr.Zero) {
9944 address = new IPAddress((long)controlData.address);
9946 m_ReceiveMessageFromPacketInfo = new IPPacketInformation(((address != null) ? address : IPAddress.None), (int)controlData.index);
9949 else if(m_ControlBuffer.Length == s_ControlDataIPv6Size) {
9950 UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6 controlData = (UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6)Marshal.PtrToStructure(PtrMessage->controlBuffer.Pointer, typeof(UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6));
9951 if(controlData.length != UIntPtr.Zero) {
9952 address = new IPAddress(controlData.address);
9954 m_ReceiveMessageFromPacketInfo = new IPPacketInformation(((address != null) ? address : IPAddress.IPv6None), (int)controlData.index);
9958 m_ReceiveMessageFromPacketInfo = new IPPacketInformation();
9963 case SocketAsyncOperation.Send:
9965 if (bytesTransferred > 0) {
9966 // Log and Perf counters.
9967 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9968 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
9972 case SocketAsyncOperation.SendPackets:
9974 if(bytesTransferred > 0) {
9975 // Log and Perf counters.
9976 if(s_LoggingEnabled) LogSendPacketsBuffers(bytesTransferred);
9977 if(Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
9980 // Close the files if open
9981 if (m_SendPacketsFileStreams != null) {
9982 for(int i = 0; i < m_SendPacketsElementsFileCount; i++) {
9983 // Dereference handles
9984 m_SendPacketsFileHandles[i] = null;
9985 // Close any open streams
9986 if(m_SendPacketsFileStreams[i] != null) {
9987 m_SendPacketsFileStreams[i].Close();
9988 m_SendPacketsFileStreams[i] = null;
9992 m_SendPacketsFileStreams = null;
9993 m_SendPacketsFileHandles = null;
9997 case SocketAsyncOperation.SendTo:
9999 if (bytesTransferred > 0) {
10000 // Log and Perf counters.
10001 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
10002 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
10008 if(socketError != SocketError.Success) {
10009 // Asynchronous failure or something went wrong after async success.
10010 SetResults(socketError, bytesTransferred, flags);
10011 m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
10014 // Complete the operation and raise completion event.
10016 if(m_ContextCopy == null) {
10019 ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
10023 private unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) {
10025 GlobalLog.SetThreadSource(ThreadKinds.CompletionPort);
10026 using(GlobalLog.SetThreadKind(ThreadKinds.System)) {
10028 SocketFlags socketFlags = SocketFlags.None;
10029 SocketError socketError = (SocketError)errorCode;
10031 if(socketError == SocketError.Success) {
10032 FinishOperationSuccess(socketError, (int)numBytes, socketFlags);
10034 if(socketError != SocketError.OperationAborted) {
10035 if(m_CurrentSocket.CleanedUp) {
10036 socketError = SocketError.OperationAborted;
10039 // This is the same NativeOverlapped* as we already have a SafeHandle for, re-use the orriginal.
10040 Debug.Assert((IntPtr)nativeOverlapped == m_PtrNativeOverlapped.DangerousGetHandle(), "Handle mismatch");
10042 // The Async IO completed with a failure.
10043 // here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error.
10044 bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult(
10045 m_CurrentSocket.SafeHandle,
10046 m_PtrNativeOverlapped,
10050 socketError = (SocketError)Marshal.GetLastWin32Error();
10053 // m_CurrentSocket.CleanedUp check above does not always work since this code is subject to race conditions
10054 socketError = SocketError.OperationAborted;
10058 FinishOperationAsyncFailure(socketError, (int)numBytes, socketFlags);
10064 } // class SocketAsyncContext
10066 #if SOCKETTHREADPOOL
10067 internal static class SocketThreadPool
10069 private static readonly int c_threadIOCPTimeout = 15000; // milliseconds
10070 private static readonly IntPtr c_InvalidHandleValue = new IntPtr(-1);
10071 private static readonly int m_maxThreadsAllowed = System.Int32.MaxValue; //Maybe (Environment.ProcessorCount * some_factor) ?
10072 private static int m_numThreadsInPool = 0;
10073 private static int m_maxThreadsEverInPool = 0;
10074 private static int m_numBusyThreads = 0;
10075 private static int m_numCallbacks = 0;
10076 private static int m_numBoundHandles = 0;
10077 private static object s_InternalSyncObject;
10078 private static bool initialized = false;
10079 private static IntPtr m_hIOCP = c_InvalidHandleValue;
10081 public static bool BindHandle(SafeHandle osHandle)
10083 // ensure initialized
10087 // bind to completion port
10089 IntPtr handle = UnsafeNclNativeMethods.OSSOCK.CreateIoCompletionPort(osHandle, m_hIOCP, 1111, 0);
10090 if (handle == IntPtr.Zero)
10092 throw new Exception(string.Format("CreateIoCompletionPort failed with Win32 error {0}.", Marshal.GetLastWin32Error()));
10097 Interlocked.Increment(ref m_numBoundHandles);
10099 if (m_numThreadsInPool == 0)
10101 // add thread to pool if none
10108 public static void UnBindHandle(SafeHandle osHandle)
10110 // take count to zero
10112 Interlocked.Decrement(ref m_numBoundHandles);
10115 private static void Init()
10119 lock (InternalSyncObject)
10123 // Create completion port
10125 m_hIOCP = UnsafeNclNativeMethods.OSSOCK.CreateIoCompletionPort(c_InvalidHandleValue, IntPtr.Zero, 1111, 0);
10126 if (m_hIOCP == c_InvalidHandleValue)
10128 throw new Exception(string.Format("CreateIoCompletionPort failed with Win32 error {0}.", Marshal.GetLastWin32Error()));
10130 initialized = true;
10136 private static object InternalSyncObject
10140 if (s_InternalSyncObject == null)
10142 object o = new object();
10143 Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
10145 return s_InternalSyncObject;
10149 private unsafe static void ThreadPoolFunc()
10153 for (Boolean fStayInPool = true; fStayInPool; /*empty*/ )
10157 uint bytesTransferred;
10159 NativeOverlapped* nativeOverlappedPtr;
10161 // Thread no longer busy.
10163 Interlocked.Decrement(ref m_numBusyThreads);
10165 // Read the completion port queue.
10167 result = UnsafeNclNativeMethods.OSSOCK.GetQueuedCompletionStatus(
10169 out bytesTransferred,
10171 out nativeOverlappedPtr,
10172 c_threadIOCPTimeout);
10174 // Thread woke up and might have something to do.
10176 Int32 busyThreads = Interlocked.Increment(ref m_numBusyThreads);
10178 // Get win32 status only if GQCS returned false.
10183 status = (uint)Marshal.GetLastWin32Error();
10186 // Handle the case where GQCS itself fails without dequeueing a completion packet.
10188 if (nativeOverlappedPtr == null)
10190 // Could be a timeout.
10192 if (status == (uint)258) // WAIT_TIMEOUT
10194 // On timeout let thread go away
10196 fStayInPool = false;
10197 break; // Leave the loop
10200 // Some other win32 failure - try GQCS again.
10205 // Heuristic to add another thread to pool.
10207 if ((busyThreads == m_numThreadsInPool) && (busyThreads < m_maxThreadsAllowed))
10212 // Unpack the native overlapped structure into managed Overlapped object
10214 Overlapped overlapped = Overlapped.Unpack(nativeOverlappedPtr);
10216 // See if we have a SocketOperationAsyncResult.
10217 // Otherwise we have something derived from BaseOverlappedAsyncResult.
10219 DummyAsyncResult ar = overlapped.AsyncResult as DummyAsyncResult;
10222 // Is child of BaseOverlappedAsyncResult. Callback is static function in BaseOverlappedAsyncResult.
10224 // call the callback
10225 BaseOverlappedAsyncResult.s_IOCallback(status, bytesTransferred, nativeOverlappedPtr);
10229 // Must be SocAsyncResult. Callback is in the AsyncResult.
10231 // call the callback
10232 ar.IOCompletionCallBack(status, bytesTransferred, nativeOverlappedPtr);
10235 // count the completion
10237 Interlocked.Increment(ref m_numCallbacks);
10245 // Thread is leaving pool.
10247 Interlocked.Decrement(ref m_numBusyThreads);
10248 if (Interlocked.Decrement(ref m_numThreadsInPool) == 0)
10250 // No more threads in the pool.
10255 private static void AddThreadToPool()
10257 // suppress flow if not already
10259 if (!ExecutionContext.IsFlowSuppressed()) ExecutionContext.SuppressFlow();
10261 // Adding a thread to the thread pool
10263 Interlocked.Increment(ref m_numThreadsInPool);
10265 // Track max threads in pool
10267 InterlockedMax(ref m_maxThreadsEverInPool, m_numThreadsInPool);
10269 // Thread is busy until it blocks on GQCS
10271 Interlocked.Increment(ref m_numBusyThreads);
10275 Thread t = new Thread(new ThreadStart(ThreadPoolFunc));
10276 t.IsBackground = true;
10280 private static Int32 InterlockedMax(ref Int32 target, Int32 val)
10282 Int32 i, j = target;
10286 j = Interlocked.CompareExchange(ref target, Math.Max(i, val), i);
10292 // internal minimal IAsyncResult class to pass completion routine across native overlapped calls via Overlapped magic internals
10293 internal class DummyAsyncResult : IAsyncResult {
10294 IOCompletionCallback m_iocb;
10296 public DummyAsyncResult() : this(null) {
10298 public DummyAsyncResult(IOCompletionCallback iocb) {
10301 public IOCompletionCallback IOCompletionCallBack {
10302 get { return m_iocb; }
10304 public object AsyncObject {
10305 get { return null; }
10307 public object AsyncState {
10308 get { return null; }
10310 public bool IsCompleted {
10311 get { return false; }
10313 public WaitHandle AsyncWaitHandle {
10314 get { return null; }
10316 public bool CompletedSynchronously {
10317 get { return false; }
10320 #endif // SOCKETTHREADPOOL