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;
126 private static volatile WaitOrTimerCallback s_RegisteredWaitCallback;
128 private static volatile bool s_LoggingEnabled;
129 #if !FEATURE_PAL // perfcounter
130 internal static volatile bool s_PerfCountersEnabled;
133 //************* constructors *************************
135 //------------------------------------
137 // Creates a Dual Mode socket for working with both IPv4 and IPv6
138 public Socket(SocketType socketType, ProtocolType protocolType)
139 : this(AddressFamily.InterNetworkV6, socketType, protocolType) {
145 /// Initializes a new instance of the <see cref='Sockets.Socket'/> class.
148 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) {
149 s_LoggingEnabled = Logging.On;
150 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
155 m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
157 m_Handle = SafeCloseSocket.CreateWSASocket(
163 if (m_Handle.IsInvalid) {
165 // failed to create the win32 socket, throw
167 throw new SocketException();
170 this.addressFamily = addressFamily;
171 this.socketType = socketType;
172 this.protocolType = protocolType;
174 IPProtectionLevel defaultProtectionLevel = SettingsSectionInternal.Section.IPProtectionLevel;
175 if (defaultProtectionLevel != IPProtectionLevel.Unspecified) {
176 SetIPProtectionLevel(defaultProtectionLevel);
183 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
187 public Socket(SocketInformation socketInformation) {
188 s_LoggingEnabled = Logging.On;
189 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
191 ExceptionHelper.UnrestrictedSocketPermission.Demand();
194 if(socketInformation.ProtocolInformation == null || socketInformation.ProtocolInformation.Length < protocolInformationSize){
195 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation.ProtocolInformation");
199 fixed(byte * pinnedBuffer = socketInformation.ProtocolInformation){
200 m_Handle = SafeCloseSocket.CreateWSASocket(pinnedBuffer);
202 UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO protocolInfo = (UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO)Marshal.PtrToStructure((IntPtr)pinnedBuffer, typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
203 addressFamily = protocolInfo.iAddressFamily;
204 socketType = (SocketType)protocolInfo.iSocketType;
205 protocolType = (ProtocolType)protocolInfo.iProtocol;
209 if (m_Handle.IsInvalid) {
210 SocketException e = new SocketException();
211 if(e.ErrorCode == (int)SocketError.InvalidArgument){
212 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation");
219 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
220 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
223 m_IsConnected = socketInformation.IsConnected;
224 willBlock = !socketInformation.IsNonBlocking;
225 InternalSetBlocking(willBlock);
226 isListening = socketInformation.IsListening;
227 UseOnlyOverlappedIO = socketInformation.UseOnlyOverlappedIO;
230 //are we bound? if so, what's the local endpoint?
232 if (socketInformation.RemoteEndPoint != null) {
233 m_RightEndPoint = socketInformation.RemoteEndPoint;
234 m_RemoteEndPoint = socketInformation.RemoteEndPoint;
238 if (addressFamily == AddressFamily.InterNetwork ) {
241 else if(addressFamily == AddressFamily.InterNetworkV6) {
242 ep = IPEndPoint.IPv6Any;
245 SocketAddress socketAddress = ep.Serialize();
246 SocketError errorCode;
249 errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
251 socketAddress.m_Buffer,
252 ref socketAddress.m_Size);
254 catch (ObjectDisposedException)
256 errorCode = SocketError.NotSocket;
259 if (errorCode == SocketError.Success) {
262 m_RightEndPoint = ep.Create(socketAddress);
269 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
275 /// Called by the class to create a socket to accept an
276 /// incoming request.
279 private Socket(SafeCloseSocket fd) {
280 s_LoggingEnabled = Logging.On;
281 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", null);
283 // ExceptionHelper.UnmanagedPermission.Demand();
291 // this should never happen, let's check anyway
293 if (fd == null || fd.IsInvalid) {
294 throw new ArgumentException(SR.GetString(SR.net_InvalidSocketHandle));
299 addressFamily = Sockets.AddressFamily.Unknown;
300 socketType = Sockets.SocketType.Unknown;
301 protocolType = Sockets.ProtocolType.Unknown;
302 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
307 //************* properties *************************
311 /// <para>Indicates whether IPv4 support is available and enabled on this machine.</para>
313 [Obsolete("SupportsIPv4 is obsoleted for this type, please use OSSupportsIPv4 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
314 public static bool SupportsIPv4 {
317 return s_SupportsIPv4;
321 // Renamed to be consistent with OSSupportsIPv6
322 public static bool OSSupportsIPv4 {
325 return s_SupportsIPv4;
330 /// <para>Indicates whether IPv6 support is available and enabled on this machine.</para>
333 [Obsolete("SupportsIPv6 is obsoleted for this type, please use OSSupportsIPv6 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
334 public static bool SupportsIPv6 {
337 return s_SupportsIPv6;
341 internal static bool LegacySupportsIPv6 {
344 return s_SupportsIPv6;
348 public static bool OSSupportsIPv6 {
351 return s_OSSupportsIPv6;
358 /// Gets the amount of data pending in the network's input buffer that can be
359 /// read from the socket.
362 public int Available {
365 throw new ObjectDisposedException(this.GetType().FullName);
370 // This may throw ObjectDisposedException.
371 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
373 IoctlSocketConstants.FIONREAD,
376 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Available_get() UnsafeNclNativeMethods.OSSOCK.ioctlsocket returns errorCode:" + errorCode);
379 // if the native call fails we'll throw a SocketException
381 if (errorCode==SocketError.SocketError) {
383 // update our internal state after this socket error and throw
385 SocketException socketException = new SocketException();
386 UpdateStatusAfterSocketError(socketException);
387 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Available", socketException);
388 throw socketException;
401 /// Gets the local end point.
404 public EndPoint LocalEndPoint {
407 throw new ObjectDisposedException(this.GetType().FullName);
410 if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
412 // update the state if we've become connected after a non-blocking connect
413 m_IsConnected = true;
414 m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
415 m_NonBlockingConnectInProgress = false;
418 if (m_RightEndPoint == null) {
422 SocketAddress socketAddress = m_RightEndPoint.Serialize();
424 // This may throw ObjectDisposedException.
425 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
427 socketAddress.m_Buffer,
428 ref socketAddress.m_Size);
430 if (errorCode!=SocketError.Success) {
432 // update our internal state after this socket error and throw
434 SocketException socketException = new SocketException();
435 UpdateStatusAfterSocketError(socketException);
436 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "LocalEndPoint", socketException);
437 throw socketException;
440 return m_RightEndPoint.Create(socketAddress);
446 /// Gets the remote end point
449 public EndPoint RemoteEndPoint {
452 throw new ObjectDisposedException(this.GetType().FullName);
455 if (m_RemoteEndPoint==null) {
457 if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
459 // update the state if we've become connected after a non-blocking connect
460 m_IsConnected = true;
461 m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
462 m_NonBlockingConnectInProgress = false;
465 if (m_RightEndPoint==null) {
469 SocketAddress socketAddress = m_RightEndPoint.Serialize();
471 // This may throw ObjectDisposedException.
472 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getpeername(
474 socketAddress.m_Buffer,
475 ref socketAddress.m_Size);
477 if (errorCode!=SocketError.Success) {
479 // update our internal state after this socket error and throw
481 SocketException socketException = new SocketException();
482 UpdateStatusAfterSocketError(socketException);
483 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "RemoteEndPoint", socketException);
484 throw socketException;
488 m_RemoteEndPoint = m_RightEndPoint.Create(socketAddress);
494 return m_RemoteEndPoint;
501 /// Gets the operating system m_Handle for the socket.
502 ///YUKON: should we cut this method off, who are the users?
505 public IntPtr Handle {
508 ExceptionHelper.UnmanagedPermission.Demand();
510 return m_Handle.DangerousGetHandle();
514 internal SafeCloseSocket SafeHandle {
521 // Non-blocking I/O control
524 /// Gets and sets the blocking mode of a socket.
527 public bool Blocking {
530 // return the user's desired blocking behaviour (not the actual win32 state)
536 throw new ObjectDisposedException(this.GetType().FullName);
539 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::set_Blocking() value:" + value.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
543 SocketError errorCode = InternalSetBlocking(value, out current);
545 if (errorCode!=SocketError.Success) {
547 // update our internal state after this socket error and throw
548 SocketException socketException = new SocketException(errorCode);
549 UpdateStatusAfterSocketError(socketException);
550 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Blocking", socketException);
551 throw socketException;
555 // win32 call succeeded, update desired state
562 public bool UseOnlyOverlappedIO{
565 // return the user's desired blocking behaviour (not the actual win32 state)
567 return useOverlappedIO;
572 if (m_BoundToThreadPool) {
573 throw new InvalidOperationException(SR.GetString(SR.net_io_completionportwasbound));
577 useOverlappedIO = value;
584 /// Gets the connection state of the Socket. This property will return the latest
585 /// known state of the Socket. When it returns false, the Socket was either never connected
586 /// or it is not connected anymore. When it returns true, though, there's no guarantee that the Socket
587 /// is still connected, but only that it was connected at the time of the last IO operation.
590 public bool Connected {
592 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connected() m_IsConnected:"+m_IsConnected);
594 if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
596 // update the state if we've become connected after a non-blocking connect
597 m_IsConnected = true;
598 m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
599 m_NonBlockingConnectInProgress = false;
602 return m_IsConnected;
609 /// Gets the socket's address family.
612 public AddressFamily AddressFamily {
614 return addressFamily;
620 /// Gets the socket's socketType.
623 public SocketType SocketType {
631 /// Gets the socket's protocol socketType.
634 public ProtocolType ProtocolType {
643 return (m_RightEndPoint != null);
648 public bool ExclusiveAddressUse{
650 return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse) != 0 ? true : false;
654 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotbebound));
656 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
661 public int ReceiveBufferSize {
663 return (int)GetSocketOption(SocketOptionLevel.Socket,
664 SocketOptionName.ReceiveBuffer);
668 throw new ArgumentOutOfRangeException("value");
671 SetSocketOption(SocketOptionLevel.Socket,
672 SocketOptionName.ReceiveBuffer, value);
676 public int SendBufferSize {
678 return (int)GetSocketOption(SocketOptionLevel.Socket,
679 SocketOptionName.SendBuffer);
684 throw new ArgumentOutOfRangeException("value");
687 SetSocketOption(SocketOptionLevel.Socket,
688 SocketOptionName.SendBuffer, value);
692 public int ReceiveTimeout {
694 return (int)GetSocketOption(SocketOptionLevel.Socket,
695 SocketOptionName.ReceiveTimeout);
699 throw new ArgumentOutOfRangeException("value");
705 SetSocketOption(SocketOptionLevel.Socket,
706 SocketOptionName.ReceiveTimeout, value);
710 public int SendTimeout {
712 return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
717 throw new ArgumentOutOfRangeException("value");
723 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
727 public LingerOption LingerState {
729 return (LingerOption)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
732 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value);
737 public bool NoDelay {
739 return (int)GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) != 0 ? true : false;
742 SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
749 if (addressFamily == AddressFamily.InterNetwork) {
750 return (short)(int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
752 else if (addressFamily == AddressFamily.InterNetworkV6) {
753 return (short)(int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive);
756 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
762 // valid values are from 0 to 255 since Ttl is really just a byte value on the wire
763 if (value < 0 || value > 255) {
764 throw new ArgumentOutOfRangeException("value");
767 if (addressFamily == AddressFamily.InterNetwork) {
768 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
771 else if (addressFamily == AddressFamily.InterNetworkV6) {
772 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive, value);
775 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
780 public bool DontFragment{
782 if (addressFamily == AddressFamily.InterNetwork) {
783 return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment) != 0 ? true : false;
786 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
791 if (addressFamily == AddressFamily.InterNetwork) {
792 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
795 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
801 public bool MulticastLoopback{
803 if (addressFamily == AddressFamily.InterNetwork) {
804 return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback) != 0 ? true : false;
806 else if (addressFamily == AddressFamily.InterNetworkV6) {
807 return (int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback) != 0 ? true : false;
810 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
815 if (addressFamily == AddressFamily.InterNetwork) {
816 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
819 else if (addressFamily == AddressFamily.InterNetworkV6) {
820 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
823 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
828 public bool EnableBroadcast{
830 return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast) != 0 ? true : false;
833 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
838 public bool DualMode {
840 if (AddressFamily != AddressFamily.InterNetworkV6) {
841 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
843 return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
846 if (AddressFamily != AddressFamily.InterNetworkV6) {
847 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
849 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
853 private bool IsDualMode {
855 return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
859 internal bool CanTryAddressFamily(AddressFamily family) {
860 return (family == addressFamily) || (family == AddressFamily.InterNetwork && IsDualMode);
864 //************* public methods *************************
871 /// <para>Associates a socket with an end point.</para>
873 public void Bind(EndPoint localEP) {
875 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Bind", localEP);
878 throw new ObjectDisposedException(this.GetType().FullName);
881 // parameter validation
884 throw new ArgumentNullException("localEP");
887 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() localEP:" + localEP.ToString());
889 EndPoint endPointSnapshot = localEP;
890 IPEndPoint ipSnapshot = localEP as IPEndPoint;
893 // for now security is implemented only on IPEndPoint
894 // If EndPoint is of other type - unmanaged code permisison is demanded
896 if (ipSnapshot != null)
898 // Take a snapshot that will make it immutable and not derived.
899 ipSnapshot = ipSnapshot.Snapshot();
900 // DualMode: Do the security check on the users IPv4 address, but map to IPv6 before binding.
901 endPointSnapshot = RemapIPEndPoint(ipSnapshot);
904 // create the permissions the user would need for the call
906 SocketPermission socketPermission
907 = new SocketPermission(
908 NetworkAccess.Accept,
910 ipSnapshot.Address.ToString(),
915 socketPermission.Demand();
917 // Here the permission check has succeded.
918 // NB: if local port is 0, then winsock will assign some>1024,
919 // so assuming that this is safe. We will not check the
920 // NetworkAccess.Accept permissions in Receive.
929 ExceptionHelper.UnmanagedPermission.Demand();
933 // ask the EndPoint to generate a SocketAddress that we
934 // can pass down to winsock
936 SocketAddress socketAddress = CallSerializeCheckDnsEndPoint(endPointSnapshot);
937 DoBind(endPointSnapshot, socketAddress);
938 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Bind", "");
941 internal void InternalBind(EndPoint localEP)
943 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "InternalBind", localEP);
947 throw new ObjectDisposedException(GetType().FullName);
950 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalBind() localEP:" + localEP.ToString());
951 GlobalLog.Assert(!(localEP is DnsEndPoint), "Calling InternalBind with a DnsEndPoint, about to get NotImplementedException");
954 // ask the EndPoint to generate a SocketAddress that we
955 // can pass down to winsock
957 EndPoint endPointSnapshot = localEP;
958 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
959 DoBind(endPointSnapshot, socketAddress);
961 if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "InternalBind", "");
964 private void DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
966 // Mitigation for Blue Screen of Death (Win7, maybe others)
967 IPEndPoint ipEndPoint = endPointSnapshot as IPEndPoint;
968 if (!OSSupportsIPv4 && ipEndPoint != null && ipEndPoint.Address.IsIPv4MappedToIPv6)
970 SocketException socketException = new SocketException(SocketError.InvalidArgument);
971 UpdateStatusAfterSocketError(socketException);
972 if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
973 throw socketException;
976 // This may throw ObjectDisposedException.
977 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.bind(
979 socketAddress.m_Buffer,
980 socketAddress.m_Size);
985 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.bind returns errorCode:" + errorCode);
987 catch (ObjectDisposedException) { }
991 // if the native call fails we'll throw a SocketException
993 if (errorCode != SocketError.Success)
996 // update our internal state after this socket error and throw
998 SocketException socketException = new SocketException();
999 UpdateStatusAfterSocketError(socketException);
1000 if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
1001 throw socketException;
1004 if (m_RightEndPoint == null)
1007 // save a copy of the EndPoint so we can use it for Create()
1009 m_RightEndPoint = endPointSnapshot;
1015 /// <para>Establishes a connection to a remote system.</para>
1017 public void Connect(EndPoint remoteEP) {
1019 throw new ObjectDisposedException(this.GetType().FullName);
1022 // parameter validation
1024 if (remoteEP==null) {
1025 throw new ArgumentNullException("remoteEP");
1028 if(m_IsDisconnected){
1029 throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedConnect));
1034 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
1037 ValidateBlockingMode();
1038 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connect() DST:" + ValidationHelper.ToString(remoteEP));
1040 DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
1043 if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily))
1045 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
1048 Connect(dnsEP.Host, dnsEP.Port);
1052 //This will check the permissions for connect
1053 EndPoint endPointSnapshot = remoteEP;
1054 SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true);
1058 m_NonBlockingConnectRightEndPoint = endPointSnapshot;
1059 m_NonBlockingConnectInProgress = true;
1062 DoConnect(endPointSnapshot, socketAddress);
1066 public void Connect(IPAddress address, int port){
1068 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", address);
1071 throw new ObjectDisposedException(this.GetType().FullName);
1073 //if address family isn't the socket address family throw
1074 if (address==null) {
1075 throw new ArgumentNullException("address");
1078 if (!ValidationHelper.ValidateTcpPort(port)) {
1079 throw new ArgumentOutOfRangeException("port");
1081 if (!CanTryAddressFamily(address.AddressFamily)) {
1082 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
1085 IPEndPoint remoteEP = new IPEndPoint(address, port);
1087 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
1091 public void Connect(string host, int port){
1092 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", host);
1095 throw new ObjectDisposedException(this.GetType().FullName);
1098 throw new ArgumentNullException("host");
1100 if (!ValidationHelper.ValidateTcpPort(port)){
1101 throw new ArgumentOutOfRangeException("port");
1103 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
1104 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
1107 IPAddress[] addresses = Dns.GetHostAddresses(host);
1108 Connect(addresses,port);
1109 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
1113 public void Connect(IPAddress[] addresses, int port){
1114 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", addresses);
1117 throw new ObjectDisposedException(this.GetType().FullName);
1119 if (addresses==null) {
1120 throw new ArgumentNullException("addresses");
1122 if (addresses.Length == 0) {
1123 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_ipaddress_length), "addresses");
1125 if (!ValidationHelper.ValidateTcpPort(port)) {
1126 throw new ArgumentOutOfRangeException("port");
1128 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
1129 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
1132 Exception lastex = null;
1133 foreach ( IPAddress address in addresses ) {
1134 if (CanTryAddressFamily(address.AddressFamily)) {
1137 Connect(new IPEndPoint(address,port) );
1141 catch ( Exception ex )
1143 if (NclUtilities.IsFatal(ex)) throw;
1149 if ( lastex != null )
1152 //if we're not connected, then we didn't get a valid ipaddress in the list
1154 throw new ArgumentException(SR.GetString(SR.net_invalidAddressList), "addresses");
1157 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
1163 /// Forces a socket connection to close.
1168 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
1169 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Close", null);
1170 ((IDisposable)this).Dispose();
1171 if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "Close", null);
1174 public void Close(int timeout)
1178 throw new ArgumentOutOfRangeException("timeout");
1180 m_CloseTimeout = timeout;
1181 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
1182 ((IDisposable)this).Dispose();
1188 /// Places a socket in a listening state.
1191 public void Listen(int backlog) {
1192 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Listen", backlog);
1194 throw new ObjectDisposedException(this.GetType().FullName);
1197 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() backlog:" + backlog.ToString());
1199 // No access permissions are necessary here because
1200 // the verification is done for Bind
1202 // This may throw ObjectDisposedException.
1203 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.listen(
1210 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.listen returns errorCode:" + errorCode);
1212 catch (ObjectDisposedException) { }
1216 // if the native call fails we'll throw a SocketException
1218 if (errorCode!=SocketError.Success) {
1220 // update our internal state after this socket error and throw
1222 SocketException socketException = new SocketException();
1223 UpdateStatusAfterSocketError(socketException);
1224 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Listen", socketException);
1225 throw socketException;
1228 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Listen", "");
1233 /// Creates a new <see cref='Sockets.Socket'/> instance to handle an incoming
1237 public Socket Accept() {
1238 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Accept", "");
1241 // parameter validation
1245 throw new ObjectDisposedException(this.GetType().FullName);
1248 if (m_RightEndPoint==null) {
1249 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
1253 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
1256 if(m_IsDisconnected){
1257 throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedAccept));
1260 ValidateBlockingMode();
1261 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Accept() SRC:" + ValidationHelper.ToString(LocalEndPoint));
1263 SocketAddress socketAddress = m_RightEndPoint.Serialize();
1265 // This may throw ObjectDisposedException.
1266 SafeCloseSocket acceptedSocketHandle = SafeCloseSocket.Accept(
1268 socketAddress.m_Buffer,
1269 ref socketAddress.m_Size);
1272 // if the native call fails we'll throw a SocketException
1274 if (acceptedSocketHandle.IsInvalid) {
1276 // update our internal state after this socket error and throw
1278 SocketException socketException = new SocketException();
1279 UpdateStatusAfterSocketError(socketException);
1280 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Accept", socketException);
1281 throw socketException;
1284 Socket socket = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress), false);
1285 if (s_LoggingEnabled) {
1286 Logging.PrintInfo(Logging.Sockets, socket, SR.GetString(SR.net_log_socket_accepted, socket.RemoteEndPoint, socket.LocalEndPoint));
1287 Logging.Exit(Logging.Sockets, this, "Accept", socket);
1294 /// <para>Sends a data buffer to a connected socket.</para>
1296 public int Send(byte[] buffer, int size, SocketFlags socketFlags) {
1297 return Send(buffer, 0, size, socketFlags);
1300 /// <para>[To be supplied.]</para>
1302 public int Send(byte[] buffer, SocketFlags socketFlags) {
1303 return Send(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags);
1306 /// <para>[To be supplied.]</para>
1308 public int Send(byte[] buffer) {
1309 return Send(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None);
1315 /// <para>[To be supplied.]</para>
1317 public int Send(IList<ArraySegment<byte>> buffers) {
1318 return Send(buffers,SocketFlags.None);
1322 /// <para>[To be supplied.]</para>
1324 public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) {
1325 SocketError errorCode;
1326 int bytesTransferred = Send(buffers, socketFlags, out errorCode);
1327 if(errorCode != SocketError.Success){
1328 throw new SocketException(errorCode);
1330 return bytesTransferred;
1334 public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode) {
1335 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Send", "");
1337 throw new ObjectDisposedException(this.GetType().FullName);
1339 if (buffers==null) {
1340 throw new ArgumentNullException("buffers");
1343 if(buffers.Count == 0){
1344 throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
1347 ValidateBlockingMode();
1348 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
1350 //make sure we don't let the app mess up the buffer array enough to cause
1353 errorCode = SocketError.Success;
1354 int count = buffers.Count;
1355 WSABuffer[] WSABuffers = new WSABuffer[count];
1356 GCHandle[] objectsToPin = null;
1357 int bytesTransferred;
1360 objectsToPin = new GCHandle[count];
1361 for (int i = 0; i < count; ++i)
1363 ArraySegment<byte> buffer = buffers[i];
1364 ValidationHelper.ValidateSegment(buffer);
1365 objectsToPin[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
1366 WSABuffers[i].Length = buffer.Count;
1367 WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset);
1370 // This may throw ObjectDisposedException.
1371 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend_Blocking(
1372 m_Handle.DangerousGetHandle(),
1375 out bytesTransferred,
1377 SafeNativeOverlapped.Zero,
1380 if ((SocketError)errorCode==SocketError.SocketError) {
1381 errorCode = (SocketError)Marshal.GetLastWin32Error();
1387 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.send returns errorCode:" + errorCode + " bytesTransferred:" + bytesTransferred);
1389 catch (ObjectDisposedException) { }
1393 if (objectsToPin != null)
1394 for (int i = 0; i < objectsToPin.Length; ++i)
1395 if (objectsToPin[i].IsAllocated)
1396 objectsToPin[i].Free();
1399 if (errorCode != SocketError.Success) {
1401 // update our internal state after this socket error and throw
1403 UpdateStatusAfterSocketError(errorCode);
1404 if(s_LoggingEnabled){
1405 Logging.Exception(Logging.Sockets, this, "Send", new SocketException(errorCode));
1406 Logging.Exit(Logging.Sockets, this, "Send", 0);
1411 #if !FEATURE_PAL // perfcounter
1412 if (s_PerfCountersEnabled)
1414 if (bytesTransferred>0) {
1415 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
1416 if (Transport==TransportType.Udp) {
1417 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
1422 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Send", bytesTransferred);
1423 return bytesTransferred;
1428 /// <para>Sends a file to
1429 /// a connected socket.</para>
1431 [ResourceExposure(ResourceScope.Machine)]
1432 [ResourceConsumption(ResourceScope.Machine)]
1433 public void SendFile(string fileName)
1435 SendFile(fileName,null,null,TransmitFileOptions.UseDefaultWorkerThread);
1440 /// <para>Sends a file to
1441 /// a connected socket.</para>
1443 [ResourceExposure(ResourceScope.Machine)]
1444 [ResourceConsumption(ResourceScope.Machine)]
1445 public void SendFile(string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags) {
1446 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "SendFile", "");
1449 throw new ObjectDisposedException(this.GetType().FullName);
1453 throw new NotSupportedException(SR.GetString(SR.net_notconnected));
1456 ValidateBlockingMode();
1457 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " fileName:" + fileName);
1459 TransmitFileOverlappedAsyncResult asyncResult = new TransmitFileOverlappedAsyncResult(this);
1461 FileStream fileStream = null;
1462 if (fileName != null && fileName.Length>0) {
1463 fileStream = new FileStream(fileName,FileMode.Open,FileAccess.Read,FileShare.Read);
1466 SafeHandle fileHandle = null;
1468 if (fileStream != null) {
1469 ExceptionHelper.UnmanagedPermission.Assert();
1471 fileHandle = fileStream.SafeFileHandle;
1474 SecurityPermission.RevertAssert();
1478 SocketError errorCode = SocketError.Success;
1480 asyncResult.SetUnmanagedStructures(preBuffer, postBuffer, fileStream, 0, true);
1482 // This can throw ObjectDisposedException.
1483 if (fileHandle != null ?
1484 !UnsafeNclNativeMethods.OSSOCK.TransmitFile_Blocking(m_Handle.DangerousGetHandle(), fileHandle, 0, 0, SafeNativeOverlapped.Zero, asyncResult.TransmitFileBuffers, flags) :
1485 !UnsafeNclNativeMethods.OSSOCK.TransmitFile_Blocking2(m_Handle.DangerousGetHandle(), IntPtr.Zero, 0, 0, SafeNativeOverlapped.Zero, asyncResult.TransmitFileBuffers, flags))
1487 errorCode = (SocketError) Marshal.GetLastWin32Error();
1491 asyncResult.SyncReleaseUnmanagedStructures();
1497 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.TransmitFile returns errorCode:" + errorCode);
1499 catch (ObjectDisposedException) { }
1503 // if the native call fails we'll throw a SocketException
1505 if (errorCode!=SocketError.Success) {
1507 // update our internal state after this socket error and throw
1509 SocketException socketException = new SocketException(errorCode);
1510 UpdateStatusAfterSocketError(socketException);
1511 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SendFile", socketException);
1512 throw socketException;
1515 if ((asyncResult.Flags & (TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket) )!=0) {
1516 SetToDisconnected();
1517 m_RemoteEndPoint = null;
1520 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "SendFile", errorCode);
1524 #endif // !FEATURE_PAL
1528 /// <para>Sends data to
1529 /// a connected socket, starting at the indicated location in the
1534 public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) {
1535 SocketError errorCode;
1536 int bytesTransferred = Send(buffer, offset, size, socketFlags, out errorCode);
1537 if(errorCode != SocketError.Success){
1538 throw new SocketException(errorCode);
1540 return bytesTransferred;
1544 public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) {
1545 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Send", "");
1548 throw new ObjectDisposedException(this.GetType().FullName);
1551 // parameter validation
1554 throw new ArgumentNullException("buffer");
1556 if (offset<0 || offset>buffer.Length) {
1557 throw new ArgumentOutOfRangeException("offset");
1559 if (size<0 || size>buffer.Length-offset) {
1560 throw new ArgumentOutOfRangeException("size");
1564 errorCode = SocketError.Success;
1565 ValidateBlockingMode();
1566 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size);
1568 // This can throw ObjectDisposedException.
1569 int bytesTransferred;
1571 if (buffer.Length == 0)
1572 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.send(m_Handle.DangerousGetHandle(), null, 0, socketFlags);
1574 fixed (byte* pinnedBuffer = buffer) {
1575 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.send(
1576 m_Handle.DangerousGetHandle(),
1577 pinnedBuffer+offset,
1585 // if the native call fails we'll throw a SocketException
1587 if ((SocketError)bytesTransferred==SocketError.SocketError) {
1589 // update our internal state after this socket error and throw
1591 errorCode = (SocketError)Marshal.GetLastWin32Error();
1592 UpdateStatusAfterSocketError(errorCode);
1593 if(s_LoggingEnabled){
1594 Logging.Exception(Logging.Sockets, this, "Send", new SocketException(errorCode));
1595 Logging.Exit(Logging.Sockets, this, "Send", 0);
1600 #if !FEATURE_PAL // perfcounter
1601 if (s_PerfCountersEnabled)
1603 if (bytesTransferred>0) {
1604 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
1605 if (Transport==TransportType.Udp) {
1606 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
1610 #endif //!FEATURE_PAL
1612 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Send() UnsafeNclNativeMethods.OSSOCK.send returns:" + bytesTransferred.ToString());
1613 GlobalLog.Dump(buffer, offset, bytesTransferred);
1614 if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "Send", buffer, offset, size);
1615 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Send", bytesTransferred);
1616 return bytesTransferred;
1621 /// <para>Sends data to a specific end point, starting at the indicated location in the
1624 public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP) {
1625 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "SendTo", "");
1627 throw new ObjectDisposedException(this.GetType().FullName);
1630 // parameter validation
1633 throw new ArgumentNullException("buffer");
1635 if (remoteEP==null) {
1636 throw new ArgumentNullException("remoteEP");
1638 if (offset<0 || offset>buffer.Length) {
1639 throw new ArgumentOutOfRangeException("offset");
1641 if (size<0 || size>buffer.Length-offset) {
1642 throw new ArgumentOutOfRangeException("size");
1645 ValidateBlockingMode();
1646 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendTo() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " size:" + size + " remoteEP:" + ValidationHelper.ToString(remoteEP));
1648 //That will check ConnectPermission for remoteEP
1649 EndPoint endPointSnapshot = remoteEP;
1650 SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, false);
1652 // This can throw ObjectDisposedException.
1653 int bytesTransferred;
1656 if (buffer.Length == 0)
1658 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.sendto(
1659 m_Handle.DangerousGetHandle(),
1663 socketAddress.m_Buffer,
1664 socketAddress.m_Size);
1668 fixed (byte* pinnedBuffer = buffer)
1670 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.sendto(
1671 m_Handle.DangerousGetHandle(),
1672 pinnedBuffer+offset,
1675 socketAddress.m_Buffer,
1676 socketAddress.m_Size);
1682 // if the native call fails we'll throw a SocketException
1684 if ((SocketError)bytesTransferred==SocketError.SocketError) {
1686 // update our internal state after this socket error and throw
1688 SocketException socketException = new SocketException();
1689 UpdateStatusAfterSocketError(socketException);
1690 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SendTo", socketException);
1691 throw socketException;
1694 if (m_RightEndPoint==null) {
1696 // save a copy of the EndPoint so we can use it for Create()
1698 m_RightEndPoint = endPointSnapshot;
1701 #if !FEATURE_PAL // perfcounter
1702 if (s_PerfCountersEnabled)
1704 if (bytesTransferred>0) {
1705 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
1706 if (Transport==TransportType.Udp) {
1707 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
1711 #endif //!FEATURE_PAL
1713 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SendTo() returning bytesTransferred:" + bytesTransferred.ToString());
1714 GlobalLog.Dump(buffer, offset, bytesTransferred);
1715 if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "SendTo", buffer, offset, size);
1716 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "SendTo", bytesTransferred);
1717 return bytesTransferred;
1722 /// <para>Sends data to a specific end point, starting at the indicated location in the data.</para>
1724 public int SendTo(byte[] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP) {
1725 return SendTo(buffer, 0, size, socketFlags, remoteEP);
1729 /// <para>[To be supplied.]</para>
1731 public int SendTo(byte[] buffer, SocketFlags socketFlags, EndPoint remoteEP) {
1732 return SendTo(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags, remoteEP);
1736 /// <para>[To be supplied.]</para>
1738 public int SendTo(byte[] buffer, EndPoint remoteEP) {
1739 return SendTo(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None, remoteEP);
1744 /// <para>Receives data from a connected socket.</para>
1746 public int Receive(byte[] buffer, int size, SocketFlags socketFlags) {
1747 return Receive(buffer, 0, size, socketFlags);
1750 /// <para>[To be supplied.]</para>
1752 public int Receive(byte[] buffer, SocketFlags socketFlags) {
1753 return Receive(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags);
1756 /// <para>[To be supplied.]</para>
1758 public int Receive(byte[] buffer) {
1759 return Receive(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None);
1763 /// <para>Receives data from a connected socket into a specific location of the receive
1767 public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags) {
1768 SocketError errorCode;
1769 int bytesTransferred = Receive(buffer, offset, size, socketFlags, out errorCode);
1770 if(errorCode != SocketError.Success){
1771 throw new SocketException(errorCode);
1773 return bytesTransferred;
1777 public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) {
1778 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Receive", "");
1780 throw new ObjectDisposedException(this.GetType().FullName);
1783 // parameter validation
1787 throw new ArgumentNullException("buffer");
1789 if (offset<0 || offset>buffer.Length) {
1790 throw new ArgumentOutOfRangeException("offset");
1792 if (size<0 || size>buffer.Length-offset) {
1793 throw new ArgumentOutOfRangeException("size");
1797 ValidateBlockingMode();
1798 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size);
1800 // This can throw ObjectDisposedException.
1801 int bytesTransferred;
1802 errorCode = SocketError.Success;
1804 if (buffer.Length == 0)
1806 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), null, 0, socketFlags);
1808 else fixed (byte* pinnedBuffer = buffer) {
1809 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), pinnedBuffer+offset, size, socketFlags);
1813 if ((SocketError)bytesTransferred==SocketError.SocketError) {
1815 // update our internal state after this socket error and throw
1817 errorCode = (SocketError)Marshal.GetLastWin32Error();
1818 UpdateStatusAfterSocketError(errorCode);
1819 if(s_LoggingEnabled){
1820 Logging.Exception(Logging.Sockets, this, "Receive", new SocketException(errorCode));
1821 Logging.Exit(Logging.Sockets, this, "Receive", 0);
1826 #if !FEATURE_PAL // perfcounter
1827 if (s_PerfCountersEnabled)
1829 bool peek = ((int)socketFlags & (int)SocketFlags.Peek)!=0;
1831 if (bytesTransferred>0 && !peek) {
1832 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
1833 if (Transport==TransportType.Udp) {
1834 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
1838 #endif //!FEATURE_PAL
1843 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred);
1845 catch (ObjectDisposedException) { }
1847 GlobalLog.Dump(buffer, offset, bytesTransferred);
1849 if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "Receive", buffer, offset, bytesTransferred);
1850 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Receive", bytesTransferred);
1852 return bytesTransferred;
1856 public int Receive(IList<ArraySegment<byte>> buffers) {
1857 return Receive(buffers,SocketFlags.None);
1861 public int Receive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) {
1862 SocketError errorCode;
1863 int bytesTransferred = Receive(buffers, socketFlags, out errorCode);
1864 if(errorCode != SocketError.Success){
1865 throw new SocketException(errorCode);
1867 return bytesTransferred;
1871 public int Receive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode) {
1872 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Receive", "");
1874 throw new ObjectDisposedException(this.GetType().FullName);
1877 if (buffers==null) {
1878 throw new ArgumentNullException("buffers");
1881 if(buffers.Count == 0){
1882 throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
1886 ValidateBlockingMode();
1887 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
1889 //make sure we don't let the app mess up the buffer array enough to cause
1891 int count = buffers.Count;
1892 WSABuffer[] WSABuffers = new WSABuffer[count];
1893 GCHandle[] objectsToPin = null;
1894 int bytesTransferred;
1895 errorCode = SocketError.Success;
1898 objectsToPin = new GCHandle[count];
1899 for (int i = 0; i < count; ++i)
1901 ArraySegment<byte> buffer = buffers[i];
1902 ValidationHelper.ValidateSegment(buffer);
1903 objectsToPin[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
1904 WSABuffers[i].Length = buffer.Count;
1905 WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset);
1908 // This can throw ObjectDisposedException.
1909 errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv_Blocking(
1910 m_Handle.DangerousGetHandle(),
1913 out bytesTransferred,
1915 SafeNativeOverlapped.Zero,
1918 if ((SocketError)errorCode==SocketError.SocketError) {
1919 errorCode = (SocketError)Marshal.GetLastWin32Error();
1924 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.send returns errorCode:" + errorCode + " bytesTransferred:" + bytesTransferred);
1926 catch (ObjectDisposedException) { }
1930 if (objectsToPin != null)
1931 for (int i = 0; i < objectsToPin.Length; ++i)
1932 if (objectsToPin[i].IsAllocated)
1933 objectsToPin[i].Free();
1936 if (errorCode != SocketError.Success) {
1938 // update our internal state after this socket error and throw
1940 UpdateStatusAfterSocketError(errorCode);
1941 if(s_LoggingEnabled){
1942 Logging.Exception(Logging.Sockets, this, "Receive", new SocketException(errorCode));
1943 Logging.Exit(Logging.Sockets, this, "Receive", 0);
1950 #if !FEATURE_PAL // perfcounter
1951 if (s_PerfCountersEnabled)
1953 bool peek = ((int)socketFlags & (int)SocketFlags.Peek)!=0;
1955 if (bytesTransferred>0 && !peek) {
1956 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
1957 if (Transport==TransportType.Udp) {
1958 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
1962 #endif //!FEATURE_PAL
1967 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Receive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred);
1969 catch (ObjectDisposedException) { }
1972 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Receive", bytesTransferred);
1974 return bytesTransferred;
1981 /// <para>Receives a datagram into a specific location in the data buffer and stores
1982 /// the end point.</para>
1984 public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation) {
1985 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "ReceiveMessageFrom", "");
1988 throw new ObjectDisposedException(this.GetType().FullName);
1991 throw new ArgumentNullException("buffer");
1993 if (remoteEP==null) {
1994 throw new ArgumentNullException("remoteEP");
1996 if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
1997 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
1998 remoteEP.AddressFamily, addressFamily), "remoteEP");
2000 if (offset<0 || offset>buffer.Length) {
2001 throw new ArgumentOutOfRangeException("offset");
2003 if (size<0 || size>buffer.Length-offset) {
2004 throw new ArgumentOutOfRangeException("size");
2006 if (m_RightEndPoint==null) {
2007 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
2011 ValidateBlockingMode();
2013 // We don't do a CAS demand here because the contents of remoteEP aren't used by
2014 // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
2015 // with the right address family
2016 EndPoint endPointSnapshot = remoteEP;
2017 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
2019 ReceiveMessageOverlappedAsyncResult asyncResult = new ReceiveMessageOverlappedAsyncResult(this,null,null);
2020 asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, socketFlags);
2022 // save a copy of the original EndPoint
2023 SocketAddress socketAddressOriginal = endPointSnapshot.Serialize();
2026 int bytesTransfered = 0;
2027 SocketError errorCode = SocketError.Success;
2029 SetReceivingPacketInformation();
2033 // This can throw ObjectDisposedException (retrieving the delegate AND resolving the handle).
2034 if (WSARecvMsg_Blocking(
2035 m_Handle.DangerousGetHandle(),
2036 Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.m_MessageBuffer,0),
2037 out bytesTransfered,
2039 IntPtr.Zero) == SocketError.SocketError)
2041 errorCode = (SocketError)Marshal.GetLastWin32Error();
2045 asyncResult.SyncReleaseUnmanagedStructures();
2050 // if the native call fails we'll throw a SocketException
2052 if (errorCode!=SocketError.Success && errorCode != SocketError.MessageSize) {
2054 // update our internal state after this socket error and throw
2056 SocketException socketException = new SocketException(errorCode);
2057 UpdateStatusAfterSocketError(socketException);
2058 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "ReceiveMessageFrom", socketException);
2059 throw socketException;
2063 if (!socketAddressOriginal.Equals(asyncResult.m_SocketAddress))
2066 remoteEP = endPointSnapshot.Create(asyncResult.m_SocketAddress);
2070 if (m_RightEndPoint==null) {
2072 // save a copy of the EndPoint so we can use it for Create()
2074 m_RightEndPoint = endPointSnapshot;
2078 socketFlags = asyncResult.m_flags;
2079 ipPacketInformation = asyncResult.m_IPPacketInformation;
2081 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "ReceiveMessageFrom", errorCode);
2082 return bytesTransfered;
2086 /// <para>Receives a datagram into a specific location in the data buffer and stores
2087 /// the end point.</para>
2089 public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP) {
2090 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "ReceiveFrom", "");
2092 throw new ObjectDisposedException(this.GetType().FullName);
2095 // parameter validation
2098 throw new ArgumentNullException("buffer");
2100 if (remoteEP==null) {
2101 throw new ArgumentNullException("remoteEP");
2103 if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
2104 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
2105 remoteEP.AddressFamily, addressFamily), "remoteEP");
2107 if (offset<0 || offset>buffer.Length) {
2108 throw new ArgumentOutOfRangeException("offset");
2110 if (size<0 || size>buffer.Length-offset) {
2111 throw new ArgumentOutOfRangeException("size");
2113 if (m_RightEndPoint==null) {
2114 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
2118 ValidateBlockingMode();
2119 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ReceiveFrom() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " size:" + size + " remoteEP:" + remoteEP.ToString());
2121 // We don't do a CAS demand here because the contents of remoteEP aren't used by
2122 // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
2123 // with the right address family
2124 EndPoint endPointSnapshot = remoteEP;
2125 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
2126 SocketAddress socketAddressOriginal = endPointSnapshot.Serialize();
2128 // This can throw ObjectDisposedException.
2129 int bytesTransferred;
2131 if (buffer.Length == 0)
2132 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recvfrom(m_Handle.DangerousGetHandle(), null, 0, socketFlags, socketAddress.m_Buffer, ref socketAddress.m_Size );
2133 else fixed (byte* pinnedBuffer = buffer) {
2134 bytesTransferred = UnsafeNclNativeMethods.OSSOCK.recvfrom(m_Handle.DangerousGetHandle(), pinnedBuffer+offset, size, socketFlags, socketAddress.m_Buffer, ref socketAddress.m_Size );
2138 // If the native call fails we'll throw a SocketException.
2139 // Must do this immediately after the native call so that the SocketException() constructor can pick up the error code.
2140 SocketException socketException = null;
2141 if ((SocketError) bytesTransferred == SocketError.SocketError)
2143 socketException = new SocketException();
2144 UpdateStatusAfterSocketError(socketException);
2145 if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "ReceiveFrom", socketException);
2147 if(socketException.ErrorCode != (int)SocketError.MessageSize){
2148 throw socketException;
2152 if (!socketAddressOriginal.Equals(socketAddress)) {
2154 remoteEP = endPointSnapshot.Create(socketAddress);
2158 if (m_RightEndPoint==null) {
2160 // save a copy of the EndPoint so we can use it for Create()
2162 m_RightEndPoint = endPointSnapshot;
2166 if(socketException != null){
2167 throw socketException;
2171 #if !FEATURE_PAL // perfcounter
2172 if (s_PerfCountersEnabled)
2174 if (bytesTransferred>0) {
2175 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
2176 if (Transport==TransportType.Udp) {
2177 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
2181 #endif //!FEATURE_PAL
2182 GlobalLog.Dump(buffer, offset, bytesTransferred);
2184 if(s_LoggingEnabled)Logging.Dump(Logging.Sockets, this, "ReceiveFrom", buffer, offset, size);
2185 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "ReceiveFrom", bytesTransferred);
2186 return bytesTransferred;
2191 /// <para>Receives a datagram and stores the source end point.</para>
2193 public int ReceiveFrom(byte[] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP) {
2194 return ReceiveFrom(buffer, 0, size, socketFlags, ref remoteEP);
2197 /// <para>[To be supplied.]</para>
2199 public int ReceiveFrom(byte[] buffer, SocketFlags socketFlags, ref EndPoint remoteEP) {
2200 return ReceiveFrom(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags, ref remoteEP);
2203 /// <para>[To be supplied.]</para>
2205 public int ReceiveFrom(byte[] buffer, ref EndPoint remoteEP) {
2206 return ReceiveFrom(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None, ref remoteEP);
2212 /// <para>[To be supplied.]</para>
2214 public int IOControl(int ioControlCode, byte[] optionInValue, byte[] optionOutValue) {
2216 throw new ObjectDisposedException(this.GetType().FullName);
2218 if (ioControlCode==IoctlSocketConstants.FIONBIO) {
2219 throw new InvalidOperationException(SR.GetString(SR.net_sockets_useblocking));
2222 ExceptionHelper.UnmanagedPermission.Demand();
2224 int realOptionLength = 0;
2226 // This can throw ObjectDisposedException.
2227 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
2228 m_Handle.DangerousGetHandle(),
2231 optionInValue!=null ? optionInValue.Length : 0,
2233 optionOutValue!=null ? optionOutValue.Length : 0,
2234 out realOptionLength,
2235 SafeNativeOverlapped.Zero,
2238 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::IOControl() UnsafeNclNativeMethods.OSSOCK.WSAIoctl returns errorCode:" + errorCode);
2241 // if the native call fails we'll throw a SocketException
2243 if (errorCode==SocketError.SocketError) {
2245 // update our internal state after this socket error and throw
2247 SocketException socketException = new SocketException();
2248 UpdateStatusAfterSocketError(socketException);
2249 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "IOControl", socketException);
2250 throw socketException;
2253 return realOptionLength;
2259 /// <para>[To be supplied.]</para>
2261 public int IOControl(IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue) {
2262 return IOControl(unchecked((int)ioControlCode),optionInValue,optionOutValue);
2266 internal int IOControl( IOControlCode ioControlCode,
2267 IntPtr optionInValue,
2269 IntPtr optionOutValue,
2273 throw new ObjectDisposedException(this.GetType().FullName);
2275 if ( (unchecked((int)ioControlCode)) ==IoctlSocketConstants.FIONBIO) {
2276 throw new InvalidOperationException(SR.GetString(SR.net_sockets_useblocking));
2279 int realOptionLength = 0;
2281 // This can throw ObjectDisposedException.
2282 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking_Internal(
2283 m_Handle.DangerousGetHandle(),
2284 (uint)ioControlCode,
2289 out realOptionLength,
2290 SafeNativeOverlapped.Zero,
2293 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::IOControl() UnsafeNclNativeMethods.OSSOCK.WSAIoctl returns errorCode:" + errorCode);
2296 // if the native call fails we'll throw a SocketException
2298 if (errorCode==SocketError.SocketError) {
2300 // update our internal state after this socket error and throw
2302 SocketException socketException = new SocketException();
2303 UpdateStatusAfterSocketError(socketException);
2304 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "IOControl", socketException);
2305 throw socketException;
2308 return realOptionLength;
2312 public void SetIPProtectionLevel(IPProtectionLevel level) {
2313 if (level == IPProtectionLevel.Unspecified) {
2314 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue_all), "level");
2317 if (addressFamily == AddressFamily.InterNetworkV6) {
2318 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPProtectionLevel, (int)level);
2320 else if (addressFamily == AddressFamily.InterNetwork) {
2321 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IPProtectionLevel, (int)level);
2324 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
2331 /// Sets the specified option to the specified value.
2334 public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue) {
2336 throw new ObjectDisposedException(this.GetType().FullName);
2338 CheckSetOptionPermissions(optionLevel, optionName);
2339 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
2340 SetSocketOption(optionLevel, optionName, optionValue, false);
2345 /// <para>[To be supplied.]</para>
2347 public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue) {
2349 throw new ObjectDisposedException(this.GetType().FullName);
2352 CheckSetOptionPermissions(optionLevel, optionName);
2354 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
2356 // This can throw ObjectDisposedException.
2357 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
2362 optionValue != null ? optionValue.Length : 0);
2364 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
2367 // if the native call fails we'll throw a SocketException
2369 if (errorCode==SocketError.SocketError) {
2371 // update our internal state after this socket error and throw
2373 SocketException socketException = new SocketException();
2374 UpdateStatusAfterSocketError(socketException);
2375 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SetSocketOption", socketException);
2376 throw socketException;
2381 /// <para>Sets the specified option to the specified value.</para>
2384 public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue) {
2385 SetSocketOption(optionLevel,optionName,(optionValue?1:0));
2389 /// <para>Sets the specified option to the specified value.</para>
2391 public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue) {
2393 throw new ObjectDisposedException(this.GetType().FullName);
2396 // parameter validation
2398 if (optionValue==null) {
2399 throw new ArgumentNullException("optionValue");
2402 CheckSetOptionPermissions(optionLevel, optionName);
2404 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption(): optionLevel:" + optionLevel.ToString() + " optionName:" + optionName.ToString() + " optionValue:" + optionValue.ToString());
2406 if (optionLevel==SocketOptionLevel.Socket && optionName==SocketOptionName.Linger) {
2407 LingerOption lingerOption = optionValue as LingerOption;
2408 if (lingerOption==null) {
2409 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "LingerOption"), "optionValue");
2411 if (lingerOption.LingerTime < 0 || lingerOption.LingerTime>(int)UInt16.MaxValue) {
2412 throw new ArgumentException(SR.GetString(SR.ArgumentOutOfRange_Bounds_Lower_Upper, 0, (int)UInt16.MaxValue), "optionValue.LingerTime");
2414 setLingerOption(lingerOption);
2416 else if (optionLevel==SocketOptionLevel.IP && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
2417 MulticastOption multicastOption = optionValue as MulticastOption;
2418 if (multicastOption==null) {
2419 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "MulticastOption"), "optionValue");
2421 setMulticastOption(optionName, multicastOption);
2424 // IPv6 Changes: Handle IPv6 Multicast Add / Drop
2426 else if (optionLevel==SocketOptionLevel.IPv6 && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
2427 IPv6MulticastOption multicastOption = optionValue as IPv6MulticastOption;
2428 if (multicastOption==null) {
2429 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue, "IPv6MulticastOption"), "optionValue");
2431 setIPv6MulticastOption(optionName, multicastOption);
2434 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_optionValue_all), "optionValue");
2441 /// Gets the value of a socket option.
2445 public object GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName) {
2447 throw new ObjectDisposedException(this.GetType().FullName);
2449 if (optionLevel==SocketOptionLevel.Socket && optionName==SocketOptionName.Linger) {
2450 return getLingerOpt();
2452 else if (optionLevel==SocketOptionLevel.IP && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
2453 return getMulticastOpt(optionName);
2458 else if (optionLevel==SocketOptionLevel.IPv6 && (optionName==SocketOptionName.AddMembership || optionName==SocketOptionName.DropMembership)) {
2459 return getIPv6MulticastOpt(optionName);
2462 int optionValue = 0;
2463 int optionLength = 4;
2465 // This can throw ObjectDisposedException.
2466 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
2473 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
2476 // if the native call fails we'll throw a SocketException
2478 if (errorCode==SocketError.SocketError) {
2480 // update our internal state after this socket error and throw
2482 SocketException socketException = new SocketException();
2483 UpdateStatusAfterSocketError(socketException);
2484 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
2485 throw socketException;
2494 /// <para>[To be supplied.]</para>
2496 public void GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue) {
2498 throw new ObjectDisposedException(this.GetType().FullName);
2501 int optionLength = optionValue!=null ? optionValue.Length : 0;
2503 // This can throw ObjectDisposedException.
2504 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
2511 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
2514 // if the native call fails we'll throw a SocketException
2516 if (errorCode==SocketError.SocketError) {
2518 // update our internal state after this socket error and throw
2520 SocketException socketException = new SocketException();
2521 UpdateStatusAfterSocketError(socketException);
2522 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
2523 throw socketException;
2529 /// <para>[To be supplied.]</para>
2531 public byte[] GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength) {
2533 throw new ObjectDisposedException(this.GetType().FullName);
2536 byte[] optionValue = new byte[optionLength];
2537 int realOptionLength = optionLength;
2539 // This can throw ObjectDisposedException.
2540 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
2545 ref realOptionLength);
2547 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::GetSocketOption() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
2550 // if the native call fails we'll throw a SocketException
2552 if (errorCode==SocketError.SocketError) {
2554 // update our internal state after this socket error and throw
2556 SocketException socketException = new SocketException();
2557 UpdateStatusAfterSocketError(socketException);
2558 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "GetSocketOption", socketException);
2559 throw socketException;
2562 if (optionLength!=realOptionLength) {
2563 byte[] newOptionValue = new byte[realOptionLength];
2564 Buffer.BlockCopy(optionValue, 0, newOptionValue, 0, realOptionLength);
2565 optionValue = newOptionValue;
2574 /// Determines the status of the socket.
2577 public bool Poll(int microSeconds, SelectMode mode) {
2579 throw new ObjectDisposedException(this.GetType().FullName);
2582 IntPtr handle = m_Handle.DangerousGetHandle();
2583 IntPtr[] fileDescriptorSet = new IntPtr[2] { (IntPtr) 1, handle };
2584 TimeValue IOwait = new TimeValue();
2587 // negative timeout value implies indefinite wait
2590 if (microSeconds != -1) {
2591 MicrosecondsToTimeValue((long)(uint)microSeconds, ref IOwait);
2593 UnsafeNclNativeMethods.OSSOCK.select(
2595 mode==SelectMode.SelectRead ? fileDescriptorSet : null,
2596 mode==SelectMode.SelectWrite ? fileDescriptorSet : null,
2597 mode==SelectMode.SelectError ? fileDescriptorSet : null,
2602 UnsafeNclNativeMethods.OSSOCK.select(
2604 mode==SelectMode.SelectRead ? fileDescriptorSet : null,
2605 mode==SelectMode.SelectWrite ? fileDescriptorSet : null,
2606 mode==SelectMode.SelectError ? fileDescriptorSet : null,
2609 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Poll() UnsafeNclNativeMethods.OSSOCK.select returns socketCount:" + socketCount);
2612 // if the native call fails we'll throw a SocketException
2614 if ((SocketError)socketCount==SocketError.SocketError) {
2616 // update our internal state after this socket error and throw
2618 SocketException socketException = new SocketException();
2619 UpdateStatusAfterSocketError(socketException);
2620 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Poll", socketException);
2621 throw socketException;
2623 if ((int)fileDescriptorSet[0]==0) {
2626 return fileDescriptorSet[1] == handle;
2630 /// <para>Determines the status of a socket.</para>
2632 public static void Select(IList checkRead, IList checkWrite, IList checkError, int microSeconds) {
2633 // parameter validation
2634 if ((checkRead==null || checkRead.Count==0) && (checkWrite==null || checkWrite.Count==0) && (checkError==null || checkError.Count==0)) {
2635 throw new ArgumentNullException(SR.GetString(SR.net_sockets_empty_select));
2637 const int MaxSelect = 65536;
2638 if (checkRead!=null && checkRead.Count>MaxSelect) {
2639 throw new ArgumentOutOfRangeException("checkRead", SR.GetString(SR.net_sockets_toolarge_select, "checkRead", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
2641 if (checkWrite!=null && checkWrite.Count>MaxSelect) {
2642 throw new ArgumentOutOfRangeException("checkWrite", SR.GetString(SR.net_sockets_toolarge_select, "checkWrite", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
2644 if (checkError!=null && checkError.Count>MaxSelect) {
2645 throw new ArgumentOutOfRangeException("checkError", SR.GetString(SR.net_sockets_toolarge_select, "checkError", MaxSelect.ToString(NumberFormatInfo.CurrentInfo)));
2647 IntPtr[] readfileDescriptorSet = SocketListToFileDescriptorSet(checkRead);
2648 IntPtr[] writefileDescriptorSet = SocketListToFileDescriptorSet(checkWrite);
2649 IntPtr[] errfileDescriptorSet = SocketListToFileDescriptorSet(checkError);
2651 // This code used to erroneously pass a non-null timeval structure containing zeroes
2652 // to select() when the caller specified (-1) for the microseconds parameter. That
2653 // caused select to actually have a *zero* timeout instead of an infinite timeout
2654 // turning the operation into a non-blocking poll.
2656 // Now we pass a null timeval struct when microseconds is (-1).
2658 // Negative microsecond values that weren't exactly (-1) were originally successfully
2659 // converted to a timeval struct containing unsigned non-zero integers. This code
2660 // retains that behavior so that any app working around the original bug with,
2661 // for example, (-2) specified for microseconds, will continue to get the same behavior.
2665 if (microSeconds != -1) {
2666 TimeValue IOwait = new TimeValue();
2667 MicrosecondsToTimeValue((long)(uint)microSeconds, ref IOwait);
2670 UnsafeNclNativeMethods.OSSOCK.select(
2672 readfileDescriptorSet,
2673 writefileDescriptorSet,
2674 errfileDescriptorSet,
2679 UnsafeNclNativeMethods.OSSOCK.select(
2681 readfileDescriptorSet,
2682 writefileDescriptorSet,
2683 errfileDescriptorSet,
2687 GlobalLog.Print("Socket::Select() UnsafeNclNativeMethods.OSSOCK.select returns socketCount:" + socketCount);
2690 // if the native call fails we'll throw a SocketException
2692 if ((SocketError)socketCount==SocketError.SocketError) {
2693 throw new SocketException();
2695 SelectFileDescriptor(checkRead, readfileDescriptorSet);
2696 SelectFileDescriptor(checkWrite, writefileDescriptorSet);
2697 SelectFileDescriptor(checkError, errfileDescriptorSet);
2703 /// <para>[To be supplied.]</para>
2706 [HostProtection(ExternalThreading=true)]
2707 [ResourceExposure(ResourceScope.Machine)]
2708 [ResourceConsumption(ResourceScope.Machine)]
2709 public IAsyncResult BeginSendFile(
2711 AsyncCallback callback,
2714 return BeginSendFile(fileName,null,null,TransmitFileOptions.UseDefaultWorkerThread,callback,state);
2720 // Async Winsock Support, the following functions use either
2721 // the Async Winsock support to do overlapped I/O WSASend/WSARecv
2722 // or a WSAEventSelect call to enable selection and non-blocking mode
2723 // of otherwise normal Winsock calls.
2725 // Currently the following Async Socket calls are supported:
2726 // Send, Recv, SendTo, RecvFrom, Connect, Accept
2731 Routine Description:
2733 BeginConnect - Does a async winsock connect, by calling
2734 WSAEventSelect to enable Connect Events to signal an event and
2735 wake up a callback which involkes a callback.
2737 So note: This routine may go pending at which time,
2738 but any case the callback Delegate will be called upon completion
2742 remoteEP - status line that we wish to parse
2743 Callback - Async Callback Delegate that is called upon Async Completion
2744 State - State used to track callback, set by caller, not required
2748 IAsyncResult - Async result used to retreive result
2754 /// <para>[To be supplied.]</para>
2756 [HostProtection(ExternalThreading=true)]
2757 public IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)
2760 // parameter validation
2762 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", remoteEP);
2765 throw new ObjectDisposedException(this.GetType().FullName);
2768 if (remoteEP==null) {
2769 throw new ArgumentNullException("remoteEP");
2774 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
2777 DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
2780 if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily))
2782 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
2785 return BeginConnect(dnsEP.Host, dnsEP.Port, callback, state);
2788 if (CanUseConnectEx(remoteEP))
2790 return BeginConnectEx(remoteEP, true, callback, state);
2793 // This will check the permissions for connect.
2794 EndPoint endPointSnapshot = remoteEP;
2795 SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true);
2797 // Flow the context. No need to lock it since we don't use it until the callback.
2798 ConnectAsyncResult asyncResult = new ConnectAsyncResult(this, endPointSnapshot, state, callback);
2799 asyncResult.StartPostingAsyncOp(false);
2801 // Post the connect.
2802 DoBeginConnect(endPointSnapshot, socketAddress, asyncResult);
2804 // We didn't throw, so finish the posting op. This will call the callback if the operation already completed.
2805 asyncResult.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
2807 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", asyncResult);
2814 public SocketInformation DuplicateAndClose(int targetProcessId){
2815 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "DuplicateAndClose", null);
2819 throw new ObjectDisposedException(GetType().FullName);
2822 ExceptionHelper.UnrestrictedSocketPermission.Demand();
2824 SocketInformation info = new SocketInformation();
2825 info.ProtocolInformation = new byte[protocolInformationSize];
2827 // This can throw ObjectDisposedException.
2828 SocketError errorCode;
2831 fixed (byte* pinnedBuffer = info.ProtocolInformation) {
2832 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSADuplicateSocket(m_Handle, (uint)targetProcessId, pinnedBuffer);
2836 errorCode = SocketError.SocketError;
2837 #endif // !FEATURE_PAL
2839 if (errorCode!=SocketError.Success) {
2840 SocketException socketException = new SocketException();
2841 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "DuplicateAndClose", socketException);
2842 throw socketException;
2846 info.IsConnected = Connected;
2847 info.IsNonBlocking = !Blocking;
2848 info.IsListening = isListening;
2849 info.UseOnlyOverlappedIO = UseOnlyOverlappedIO;
2850 info.RemoteEndPoint = m_RemoteEndPoint;
2852 //make sure we don't shutdown, etc.
2855 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "DuplicateAndClose", null);
2862 internal IAsyncResult UnsafeBeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)
2864 if (CanUseConnectEx(remoteEP))
2866 return BeginConnectEx(remoteEP, false, callback, state);
2868 EndPoint endPointSnapshot = remoteEP;
2869 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
2871 // No context flow here. Can use Lazy.
2872 ConnectAsyncResult asyncResult = new ConnectAsyncResult(this, endPointSnapshot, state, callback);
2873 DoBeginConnect(endPointSnapshot, socketAddress, asyncResult);
2877 // Leaving the public logging as "BeginConnect" since that makes sense to the people looking at the output.
2878 // Private logging can remain "DoBeginConnect".
2879 private void DoBeginConnect(EndPoint endPointSnapshot, SocketAddress socketAddress, LazyAsyncResult asyncResult)
2881 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() endPointSnapshot:" + endPointSnapshot.ToString());
2883 EndPoint oldEndPoint = m_RightEndPoint;
2886 if (m_AcceptQueueOrConnectResult != null)
2888 throw new InvalidOperationException(SR.GetString(SR.net_sockets_no_duplicate_async));
2891 m_AcceptQueueOrConnectResult = asyncResult;
2893 if (!SetAsyncEventSelect(AsyncEventBits.FdConnect)){
2894 m_AcceptQueueOrConnectResult = null;
2895 throw new ObjectDisposedException(this.GetType().FullName);
2898 // This can throw ObjectDisposedException.
2899 IntPtr handle = m_Handle.DangerousGetHandle();
2901 //we should fix this in Whidbey.
2902 if (m_RightEndPoint == null) {
2903 m_RightEndPoint = endPointSnapshot;
2906 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAConnect(
2908 socketAddress.m_Buffer,
2909 socketAddress.m_Size,
2915 if (errorCode!=SocketError.Success) {
2916 errorCode = (SocketError)Marshal.GetLastWin32Error();
2918 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() UnsafeNclNativeMethods.OSSOCK.WSAConnect returns errorCode:" + errorCode);
2920 if (errorCode != SocketError.WouldBlock)
2922 bool completeSynchronously = true;
2923 if (errorCode == SocketError.Success)
2929 asyncResult.ErrorCode = (int) errorCode;
2932 // Using interlocked to avoid a race condition with RegisteredWaitCallback
2933 // Although UnsetAsyncEventSelect() below should cancel the callback, but
2934 // it may already be in progress and therefore resulting in simultaneous
2935 // registeredWaitCallback calling ConnectCallback() and the synchronous
2937 if (Interlocked.Exchange(ref m_RegisteredWait, null) == null)
2938 completeSynchronously = false;
2940 // Cancel async event and go back to blocking mode.
2942 UnsetAsyncEventSelect();
2944 if (errorCode == SocketError.Success)
2947 // synchronously complete the IO and call the user's callback.
2949 if (completeSynchronously)
2950 asyncResult.InvokeCallback();
2955 // if the asynchronous native call fails synchronously
2956 // we'll throw a SocketException
2958 m_RightEndPoint = oldEndPoint;
2959 SocketException socketException = new SocketException(errorCode);
2960 UpdateStatusAfterSocketError(socketException);
2961 m_AcceptQueueOrConnectResult = null;
2962 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginConnect", socketException);
2963 throw socketException;
2967 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginConnect() to:" + endPointSnapshot.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
2970 // Begin ConnectEx is only supported for connection oriented protocols
2971 // for now this is only supported on win32 platforms. We need to fix this
2972 // when the getdelegatefrom function methods are available on 64bit.
2973 // to use this, the endpoint must either be an IP endpoint, or the
2974 // socket must already be bound.
2975 private bool CanUseConnectEx(EndPoint remoteEP)
2978 return socketType == SocketType.Stream &&
2979 (m_RightEndPoint != null || remoteEP.GetType() == typeof(IPEndPoint)) &&
2980 (Thread.CurrentThread.IsThreadPoolThread || SettingsSectionInternal.Section.AlwaysUseCompletionPortsForConnect || m_IsDisconnected);
2987 // This is the internal callback that will be called when
2988 // the IO we issued for the user to winsock has completed.
2989 // when this function gets called it must:
2990 // 1) update the AsyncResult object with the results of the completed IO
2991 // 2) signal events that the user might be waiting on
2992 // 3) call the callback function that the user might have specified
2994 // This method was copied from a ConnectAsyncResult class that became useless.
2995 private void ConnectCallback()
2997 LazyAsyncResult asyncResult = (LazyAsyncResult) m_AcceptQueueOrConnectResult;
3000 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback");
3002 // If we came here due to a ---- between BeginConnect and Dispose
3004 if (asyncResult.InternalPeekCompleted)
3006 GlobalLog.Assert(CleanedUp, "Socket#{0}::ConnectCallback()|asyncResult is compelted but the socket does not have CleanedUp set.", ValidationHelper.HashString(this));
3007 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback", "Already completed, socket must be closed");
3024 // get async completion
3027 int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
3028 GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString());
3031 NetworkEvents networkEvents = new NetworkEvents();
3032 networkEvents.Events = AsyncEventBits.FdConnect;
3034 SocketError errorCode = SocketError.OperationAborted;
3035 object result = null;
3043 errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents(
3045 m_AsyncEvent.SafeWaitHandle,
3048 if (errorCode != SocketError.Success)
3050 errorCode = (SocketError) Marshal.GetLastWin32Error();
3051 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString());
3055 errorCode = (SocketError) networkEvents.ErrorCodes[(int) AsyncEventBitsPos.FdConnectBit];
3056 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString());
3059 // Cancel async event and go back to blocking mode.
3061 UnsetAsyncEventSelect();
3063 catch (ObjectDisposedException)
3065 errorCode = SocketError.OperationAborted;
3070 // if the native non-blocking call failed we'll throw a SocketException in EndConnect()
3072 if (errorCode == SocketError.Success)
3075 // the Socket is connected, update our state and performance counter
3080 catch (Exception exception)
3082 if (NclUtilities.IsFatal(exception)) throw;
3084 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback() caught exception:" + exception.Message + ", CleanedUp:" + CleanedUp);
3088 if (!asyncResult.InternalPeekCompleted)
3090 // A "ErrorCode" concept is questionable, for ex. below lines are subject to a race condition
3091 asyncResult.ErrorCode = (int) errorCode;
3092 asyncResult.InvokeCallback(result);
3095 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::ConnectCallback", errorCode.ToString());
3098 [HostProtection(ExternalThreading=true)]
3099 public IAsyncResult BeginConnect(string host, int port, AsyncCallback requestCallback, object state){
3100 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", host);
3103 throw new ObjectDisposedException(this.GetType().FullName);
3107 throw new ArgumentNullException("host");
3109 if (!ValidationHelper.ValidateTcpPort(port)){
3110 throw new ArgumentOutOfRangeException("port");
3112 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
3113 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
3118 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
3121 // Here, want to flow the context. No need to lock.
3122 MultipleAddressConnectAsyncResult result = new MultipleAddressConnectAsyncResult(null, port, this, state, requestCallback);
3123 result.StartPostingAsyncOp(false);
3125 IAsyncResult dnsResult = Dns.UnsafeBeginGetHostAddresses(host, new AsyncCallback(DnsCallback), result);
3126 if (dnsResult.CompletedSynchronously)
3128 if (DoDnsCallback(dnsResult, result))
3130 result.InvokeCallback();
3135 result.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
3137 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
3142 [HostProtection(ExternalThreading=true)]
3143 public IAsyncResult BeginConnect(IPAddress address, int port, AsyncCallback requestCallback, object state){
3144 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", address);
3146 throw new ObjectDisposedException(this.GetType().FullName);
3149 if (address==null) {
3150 throw new ArgumentNullException("address");
3152 if (!ValidationHelper.ValidateTcpPort(port)){
3153 throw new ArgumentOutOfRangeException("port");
3155 //if address family isn't the socket address family throw
3156 if (!CanTryAddressFamily(address.AddressFamily)) {
3157 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
3160 IAsyncResult result = BeginConnect(new IPEndPoint(address,port),requestCallback,state);
3161 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
3166 [HostProtection(ExternalThreading=true)]
3167 public IAsyncResult BeginConnect(IPAddress[] addresses, int port, AsyncCallback requestCallback, object state)
3169 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnect", addresses);
3171 throw new ObjectDisposedException(this.GetType().FullName);
3174 if (addresses==null) {
3175 throw new ArgumentNullException("addresses");
3177 if (addresses.Length == 0) {
3178 throw new ArgumentException(SR.GetString(SR.net_invalidAddressList), "addresses");
3180 if (!ValidationHelper.ValidateTcpPort(port)) {
3181 throw new ArgumentOutOfRangeException("port");
3183 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
3184 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
3189 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
3192 // Set up the result to capture the context. No need for a lock.
3193 MultipleAddressConnectAsyncResult result = new MultipleAddressConnectAsyncResult(addresses, port, this, state, requestCallback);
3194 result.StartPostingAsyncOp(false);
3196 if (DoMultipleAddressConnectCallback(PostOneBeginConnect(result), result))
3198 // if it completes synchronously, invoke the callback from here
3199 result.InvokeCallback();
3202 // Finished posting async op. Possibly will call callback.
3203 result.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
3205 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnect", result);
3209 // Supports DisconnectEx - this provides completion port IO and support for
3210 //disconnect and reconnects
3211 [HostProtection(ExternalThreading=true)]
3212 public IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback callback, object state)
3214 // Start context-flowing op. No need to lock - we don't use the context till the callback.
3215 DisconnectOverlappedAsyncResult asyncResult = new DisconnectOverlappedAsyncResult(this, state, callback);
3216 asyncResult.StartPostingAsyncOp(false);
3218 // Post the disconnect.
3219 DoBeginDisconnect(reuseSocket, asyncResult);
3221 // Finish flowing (or call the callback), and return.
3222 asyncResult.FinishPostingAsyncOp();
3226 private void DoBeginDisconnect(bool reuseSocket, DisconnectOverlappedAsyncResult asyncResult)
3228 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginDisconnect",null);
3230 throw new ObjectDisposedException(this.GetType().FullName);
3233 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() ");
3235 #if FEATURE_PAL && !MONO
3236 throw new PlatformNotSupportedException(SR.GetString(SR.WinXPRequired));
3240 asyncResult.SetUnmanagedStructures(null);
3242 SocketError errorCode=SocketError.Success;
3244 // This can throw ObjectDisposedException (handle, and retrieving the delegate).
3245 if (!DisconnectEx(m_Handle,asyncResult.OverlappedHandle, (int)(reuseSocket?TransmitFileOptions.ReuseSocket:0),0)) {
3246 errorCode = (SocketError)Marshal.GetLastWin32Error();
3249 if (errorCode == SocketError.Success) {
3250 SetToDisconnected();
3251 m_RemoteEndPoint = null;
3254 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() UnsafeNclNativeMethods.OSSOCK.DisConnectEx returns:" + errorCode.ToString());
3256 // if the asynchronous native call fails synchronously
3257 // we'll throw a SocketException
3259 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
3261 if (errorCode!= SocketError.Success) {
3263 // update our internal state after this socket error and throw
3265 SocketException socketException = new SocketException(errorCode);
3266 UpdateStatusAfterSocketError(socketException);
3267 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"BeginDisconnect", socketException);
3268 throw socketException;
3271 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginDisconnect() returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
3272 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginDisconnect", asyncResult);
3276 // Supports DisconnectEx - this provides support for disconnect and reconnects
3277 public void Disconnect(bool reuseSocket) {
3279 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Disconnect",null);
3281 throw new ObjectDisposedException(this.GetType().FullName);
3284 #if FEATURE_PAL && !MONO
3285 throw new PlatformNotSupportedException(SR.GetString(SR.WinXPRequired));
3286 #endif // FEATURE_PAL && !MONO
3289 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Disconnect() ");
3291 SocketError errorCode = SocketError.Success;
3293 // This can throw ObjectDisposedException (handle, and retrieving the delegate).
3294 if (!DisconnectEx_Blocking(m_Handle.DangerousGetHandle(), IntPtr.Zero, (int) (reuseSocket ? TransmitFileOptions.ReuseSocket : 0), 0))
3296 errorCode = (SocketError)Marshal.GetLastWin32Error();
3299 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Disconnect() UnsafeNclNativeMethods.OSSOCK.DisConnectEx returns:" + errorCode.ToString());
3302 if (errorCode!= SocketError.Success) {
3304 // update our internal state after this socket error and throw
3306 SocketException socketException = new SocketException(errorCode);
3307 UpdateStatusAfterSocketError(socketException);
3308 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"Disconnect", socketException);
3309 throw socketException;
3312 SetToDisconnected();
3313 m_RemoteEndPoint = null;
3315 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Disconnect", null);
3320 Routine Description:
3322 EndConnect - Called addressFamilyter receiving callback from BeginConnect,
3323 in order to retrive the result of async call
3327 AsyncResult - the AsyncResult Returned fron BeginConnect call
3331 int - Return code from aync Connect, 0 for success, SocketError.NotConnected otherwise
3335 /// <para>[To be supplied.]</para>
3337 public void EndConnect(IAsyncResult asyncResult) {
3338 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndConnect", asyncResult);
3340 throw new ObjectDisposedException(this.GetType().FullName);
3343 // parameter validation
3345 if (asyncResult==null) {
3346 throw new ArgumentNullException("asyncResult");
3349 LazyAsyncResult castedAsyncResult = null;
3350 EndPoint remoteEndPoint = null;
3351 ConnectOverlappedAsyncResult coar;
3352 MultipleAddressConnectAsyncResult macar;
3353 ConnectAsyncResult car;
3355 coar = asyncResult as ConnectOverlappedAsyncResult;
3357 macar = asyncResult as MultipleAddressConnectAsyncResult;
3358 if (macar == null) {
3359 car = asyncResult as ConnectAsyncResult;
3361 remoteEndPoint = car.RemoteEndPoint;
3362 castedAsyncResult = car;
3365 remoteEndPoint = macar.RemoteEndPoint;
3366 castedAsyncResult = macar;
3369 remoteEndPoint = coar.RemoteEndPoint;
3370 castedAsyncResult = coar;
3373 if (castedAsyncResult == null || castedAsyncResult.AsyncObject!=this) {
3374 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
3376 if (castedAsyncResult.EndCalled) {
3377 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndConnect"));
3380 castedAsyncResult.InternalWaitForCompletion();
3381 castedAsyncResult.EndCalled = true;
3382 m_AcceptQueueOrConnectResult = null;
3384 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndConnect() asyncResult:" + ValidationHelper.HashString(asyncResult));
3386 if (castedAsyncResult.Result is Exception) {
3387 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndConnect", (Exception)castedAsyncResult.Result);
3388 throw (Exception)castedAsyncResult.Result;
3390 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
3392 // update our internal state after this socket error and throw
3394 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode, remoteEndPoint);
3395 UpdateStatusAfterSocketError(socketException);
3396 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndConnect", socketException);
3397 throw socketException;
3399 if (s_LoggingEnabled) {
3400 Logging.PrintInfo(Logging.Sockets, this, SR.GetString(SR.net_log_socket_connected, LocalEndPoint, RemoteEndPoint));
3401 Logging.Exit(Logging.Sockets, this, "EndConnect", "");
3405 public void EndDisconnect(IAsyncResult asyncResult) {
3407 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndDisconnect", asyncResult);
3409 throw new ObjectDisposedException(this.GetType().FullName);
3412 #if FEATURE_PAL && !MONO
3413 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
3414 #endif // FEATURE_PAL && !MONO
3416 if (asyncResult==null) {
3417 throw new ArgumentNullException("asyncResult");
3421 //get async result and check for errors
3422 LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
3423 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
3424 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
3426 if (castedAsyncResult.EndCalled) {
3427 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndDisconnect"));
3430 //wait for completion if it hasn't occured
3431 castedAsyncResult.InternalWaitForCompletion();
3432 castedAsyncResult.EndCalled = true;
3435 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndDisconnect()");
3438 // if the asynchronous native call failed asynchronously
3439 // we'll throw a SocketException
3441 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
3443 // update our internal state after this socket error and throw
3445 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
3446 UpdateStatusAfterSocketError(socketException);
3447 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets,this,"EndDisconnect", socketException);
3448 throw socketException;
3451 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndDisconnect", null);
3458 Routine Description:
3460 BeginSend - Async implimentation of Send call, mirrored addressFamilyter BeginReceive
3461 This routine may go pending at which time,
3462 but any case the callback Delegate will be called upon completion
3466 WriteBuffer - status line that we wish to parse
3467 Index - Offset into WriteBuffer to begin sending from
3468 Size - Size of Buffer to transmit
3469 Callback - Delegate function that holds callback, called on completeion of I/O
3470 State - State used to track callback, set by caller, not required
3474 IAsyncResult - Async result used to retreive result
3479 /// <para>[To be supplied.]</para>
3482 [HostProtection(ExternalThreading=true)]
3483 public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
3485 SocketError errorCode;
3486 IAsyncResult result = BeginSend(buffer, offset, size, socketFlags, out errorCode, callback, state);
3487 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3488 throw new SocketException(errorCode);
3494 [HostProtection(ExternalThreading=true)]
3495 public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
3498 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSend", "");
3501 throw new ObjectDisposedException(this.GetType().FullName);
3504 // parameter validation
3508 throw new ArgumentNullException("buffer");
3510 if (offset < 0 || offset > buffer.Length)
3512 throw new ArgumentOutOfRangeException("offset");
3514 if (size < 0 || size > buffer.Length - offset)
3516 throw new ArgumentOutOfRangeException("size");
3519 // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
3520 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
3521 asyncResult.StartPostingAsyncOp(false);
3523 // Run the send with this asyncResult.
3524 errorCode = DoBeginSend(buffer, offset, size, socketFlags, asyncResult);
3526 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3531 // We're not throwing, so finish the async op posting code so we can return to the user.
3532 // If the operation already finished, the callback will be called from here.
3533 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
3536 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSend", asyncResult);
3541 internal IAsyncResult UnsafeBeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
3543 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "UnsafeBeginSend", "");
3546 throw new ObjectDisposedException(this.GetType().FullName);
3549 // No need to flow the context.
3550 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
3552 SocketError errorCode = DoBeginSend(buffer, offset, size, socketFlags, asyncResult);
3553 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3554 throw new SocketException(errorCode);
3557 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "UnsafeBeginSend", asyncResult);
3561 private SocketError DoBeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
3564 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " size:" + size.ToString());
3566 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
3567 // avoid a Socket leak in case of error.
3568 SocketError errorCode = SocketError.SocketError;
3571 // Set up asyncResult for overlapped WSASend.
3572 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
3573 asyncResult.SetUnmanagedStructures(buffer, offset, size, null, false /*don't pin null remoteEP*/, ref Caches.SendOverlappedCache);
3576 // Get the Send going.
3578 GlobalLog.Print("BeginSend: asyncResult:" + ValidationHelper.HashString(asyncResult) + " size:" + size.ToString());
3579 int bytesTransferred;
3581 // This can throw ObjectDisposedException.
3582 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
3584 ref asyncResult.m_SingleBuffer,
3585 1, // only ever 1 buffer being sent
3586 out bytesTransferred,
3588 asyncResult.OverlappedHandle,
3591 if (errorCode!=SocketError.Success) {
3592 errorCode = (SocketError)Marshal.GetLastWin32Error();
3594 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
3598 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
3602 // if the asynchronous native call fails synchronously
3603 // we'll throw a SocketException
3605 if (errorCode != SocketError.Success)
3607 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3608 UpdateStatusAfterSocketError(errorCode);
3609 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSend", new SocketException(errorCode));
3616 /// <para>[To be supplied.]</para>
3620 [HostProtection(ExternalThreading=true)]
3621 [ResourceExposure(ResourceScope.Machine)]
3622 [ResourceConsumption(ResourceScope.Machine)]
3623 public IAsyncResult BeginSendFile(
3627 TransmitFileOptions flags,
3628 AsyncCallback callback,
3632 // Start the context flowing. No lock necessary.
3633 TransmitFileOverlappedAsyncResult asyncResult = new TransmitFileOverlappedAsyncResult(this,state,callback);
3634 asyncResult.StartPostingAsyncOp(false);
3636 // Start the operation.
3637 DoBeginSendFile(fileName, preBuffer, postBuffer, flags, asyncResult);
3639 // Finish the op, collect the context or maybe call the callback.
3640 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
3644 [ResourceExposure(ResourceScope.Machine)]
3645 [ResourceConsumption(ResourceScope.Machine)]
3646 private void DoBeginSendFile(
3650 TransmitFileOptions flags,
3651 TransmitFileOverlappedAsyncResult asyncResult)
3653 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSendFile", "");
3656 throw new ObjectDisposedException(this.GetType().FullName);
3660 throw new ObjectDisposedException(this.GetType().FullName);
3663 #if FEATURE_PAL && !MONO
3664 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
3665 #endif // FEATURE_PAL && !MONO
3669 throw new NotSupportedException(SR.GetString(SR.net_notconnected));
3672 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendFile() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " fileName:" + fileName);
3674 FileStream fileStream = null;
3675 if (fileName != null && fileName.Length>0) {
3676 fileStream = new FileStream(fileName,FileMode.Open,FileAccess.Read,FileShare.Read);
3679 SafeHandle fileHandle = null;
3681 if (fileStream != null) {
3682 ExceptionHelper.UnmanagedPermission.Assert();
3684 fileHandle = fileStream.SafeFileHandle;
3687 SecurityPermission.RevertAssert();
3691 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
3692 // avoid a Socket leak in case of error.
3693 SocketError errorCode = SocketError.SocketError;
3696 asyncResult.SetUnmanagedStructures(preBuffer, postBuffer, fileStream, flags, ref Caches.SendOverlappedCache);
3697 bool result = false;
3699 // This can throw ObjectDisposedException.
3700 if (fileHandle != null){
3701 result = UnsafeNclNativeMethods.OSSOCK.TransmitFile(m_Handle,fileHandle,0,0,asyncResult.OverlappedHandle,asyncResult.TransmitFileBuffers,flags);
3704 result = UnsafeNclNativeMethods.OSSOCK.TransmitFile2(m_Handle,IntPtr.Zero,0,0,asyncResult.OverlappedHandle,asyncResult.TransmitFileBuffers,flags);
3708 errorCode = (SocketError)Marshal.GetLastWin32Error();
3712 errorCode = SocketError.Success;
3717 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
3721 // if the native call fails we'll throw a SocketException
3723 if (errorCode!=SocketError.Success) {
3725 // update our internal state after this socket error and throw
3727 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3728 SocketException socketException = new SocketException(errorCode);
3729 UpdateStatusAfterSocketError(socketException);
3731 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSendFile", socketException);
3732 throw socketException;
3735 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendFile() UnsafeNclNativeMethods.OSSOCK.send returns:" + errorCode.ToString());
3737 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSendFile", errorCode);
3740 #endif // !FEATURE_PAL
3744 /// <para>[To be supplied.]</para>
3746 [HostProtection(ExternalThreading=true)]
3747 public IAsyncResult BeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
3749 SocketError errorCode;
3750 IAsyncResult result = BeginSend(buffers, socketFlags, out errorCode, callback, state);
3751 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3752 throw new SocketException(errorCode);
3758 [HostProtection(ExternalThreading=true)]
3759 public IAsyncResult BeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
3762 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSend", "");
3765 throw new ObjectDisposedException(this.GetType().FullName);
3769 // parameter validation
3771 if (buffers==null) {
3772 throw new ArgumentNullException("buffers");
3775 if(buffers.Count == 0){
3776 throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
3779 // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
3780 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
3781 asyncResult.StartPostingAsyncOp(false);
3783 // Run the send with this asyncResult.
3784 errorCode = DoBeginSend(buffers, socketFlags, asyncResult);
3786 // We're not throwing, so finish the async op posting code so we can return to the user.
3787 // If the operation already finished, the callback will be called from here.
3788 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
3790 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
3794 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSend", asyncResult);
3798 private SocketError DoBeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
3801 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " buffers:" + buffers);
3803 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
3804 // avoid a Socket leak in case of error.
3805 SocketError errorCode = SocketError.SocketError;
3808 // Set up asyncResult for overlapped WSASend.
3809 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
3810 asyncResult.SetUnmanagedStructures(buffers, ref Caches.SendOverlappedCache);
3812 GlobalLog.Print("BeginSend: asyncResult:" + ValidationHelper.HashString(asyncResult));
3814 // This can throw ObjectDisposedException.
3815 int bytesTransferred;
3816 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
3818 asyncResult.m_WSABuffers,
3819 asyncResult.m_WSABuffers.Length,
3820 out bytesTransferred,
3822 asyncResult.OverlappedHandle,
3825 if (errorCode!=SocketError.Success) {
3826 errorCode = (SocketError)Marshal.GetLastWin32Error();
3828 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
3832 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
3836 // if the asynchronous native call fails synchronously
3837 // we'll throw a SocketException
3839 if (errorCode != SocketError.Success)
3841 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3842 UpdateStatusAfterSocketError(errorCode);
3843 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSend", new SocketException(errorCode));
3851 Routine Description:
3853 EndSend - Called by user code addressFamilyter I/O is done or the user wants to wait.
3854 until Async completion, needed to retrieve error result from call
3858 AsyncResult - the AsyncResult Returned fron BeginSend call
3862 int - Number of bytes transferred
3866 /// <para>[To be supplied.]</para>
3870 public int EndSend(IAsyncResult asyncResult) {
3871 SocketError errorCode;
3872 int bytesTransferred = EndSend(asyncResult, out errorCode);
3873 if(errorCode != SocketError.Success){
3874 throw new SocketException(errorCode);
3876 return bytesTransferred;
3880 public int EndSend(IAsyncResult asyncResult, out SocketError errorCode) {
3881 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSend", asyncResult);
3883 throw new ObjectDisposedException(this.GetType().FullName);
3886 // parameter validation
3888 if (asyncResult==null) {
3889 throw new ArgumentNullException("asyncResult");
3891 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
3892 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
3893 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
3895 if (castedAsyncResult.EndCalled) {
3896 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSend"));
3899 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
3900 castedAsyncResult.EndCalled = true;
3901 castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3903 #if !FEATURE_PAL // perfcounter
3904 if (s_PerfCountersEnabled)
3906 if (bytesTransferred>0) {
3907 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
3908 if (Transport==TransportType.Udp) {
3909 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
3913 #endif //!FEATURE_PAL
3914 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSend() bytesTransferred:" + bytesTransferred.ToString());
3917 // if the asynchronous native call failed asynchronously
3918 // we'll throw a SocketException
3920 errorCode = (SocketError)castedAsyncResult.ErrorCode;
3921 if (errorCode != SocketError.Success) {
3923 // update our internal state after this socket error and throw
3925 UpdateStatusAfterSocketError(errorCode);
3926 if(s_LoggingEnabled){
3927 Logging.Exception(Logging.Sockets, this, "EndSend", new SocketException(errorCode));
3928 Logging.Exit(Logging.Sockets, this, "EndSend", 0);
3932 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSend", bytesTransferred);
3933 return bytesTransferred;
3939 /// <para>[To be supplied.]</para>
3941 public void EndSendFile(IAsyncResult asyncResult) {
3942 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSendFile", asyncResult);
3944 throw new ObjectDisposedException(this.GetType().FullName);
3947 #if FEATURE_PAL && !MONO
3948 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
3949 #endif // FEATURE_PAL && !MONO
3951 // parameter validation
3953 if (asyncResult==null) {
3954 throw new ArgumentNullException("asyncResult");
3956 TransmitFileOverlappedAsyncResult castedAsyncResult = asyncResult as TransmitFileOverlappedAsyncResult;
3957 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
3958 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
3960 if (castedAsyncResult.EndCalled) {
3961 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSendFile"));
3964 castedAsyncResult.InternalWaitForCompletion();
3965 castedAsyncResult.EndCalled = true;
3966 castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
3968 if ((castedAsyncResult.Flags & (TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket) )!=0) {
3969 SetToDisconnected();
3970 m_RemoteEndPoint = null;
3974 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSendFile()");
3977 // if the asynchronous native call failed asynchronously
3978 // we'll throw a SocketException
3980 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
3982 // update our internal state after this socket error and throw
3984 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
3985 UpdateStatusAfterSocketError(socketException);
3986 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndSendFile", socketException);
3987 throw socketException;
3989 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSendFile","");
3992 #endif // !FEATURE_PAL
3997 Routine Description:
3999 BeginSendTo - Async implimentation of SendTo,
4001 This routine may go pending at which time,
4002 but any case the callback Delegate will be called upon completion
4006 WriteBuffer - Buffer to transmit
4007 Index - Offset into WriteBuffer to begin sending from
4008 Size - Size of Buffer to transmit
4009 Flags - Specific Socket flags to pass to winsock
4010 remoteEP - EndPoint to transmit To
4011 Callback - Delegate function that holds callback, called on completeion of I/O
4012 State - State used to track callback, set by caller, not required
4016 IAsyncResult - Async result used to retreive result
4020 /// <para>[To be supplied.]</para>
4022 [HostProtection(ExternalThreading=true)]
4023 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP, AsyncCallback callback, object state)
4026 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginSendTo", "");
4029 throw new ObjectDisposedException(this.GetType().FullName);
4033 // parameter validation
4036 throw new ArgumentNullException("buffer");
4038 if (remoteEP==null) {
4039 throw new ArgumentNullException("remoteEP");
4041 if (offset<0 || offset>buffer.Length) {
4042 throw new ArgumentOutOfRangeException("offset");
4044 if (size<0 || size>buffer.Length-offset) {
4045 throw new ArgumentOutOfRangeException("size");
4048 // This will check the permissions for connect.
4049 EndPoint endPointSnapshot = remoteEP;
4050 SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, false);
4052 // Set up the async result and indicate to flow the context.
4053 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4054 asyncResult.StartPostingAsyncOp(false);
4057 DoBeginSendTo(buffer, offset, size, socketFlags, endPointSnapshot, socketAddress, asyncResult);
4059 // Finish, possibly posting the callback. The callback won't be posted before this point is reached.
4060 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
4062 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginSendTo", asyncResult);
4066 private void DoBeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint endPointSnapshot, SocketAddress socketAddress, OverlappedAsyncResult asyncResult)
4068 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() size:" + size.ToString());
4069 EndPoint oldEndPoint = m_RightEndPoint;
4071 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4072 // avoid a Socket leak in case of error.
4073 SocketError errorCode = SocketError.SocketError;
4076 // Set up asyncResult for overlapped WSASendTo.
4077 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
4078 asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, false /* don't pin RemoteEP*/, ref Caches.SendOverlappedCache);
4080 if (m_RightEndPoint == null)
4082 m_RightEndPoint = endPointSnapshot;
4085 int bytesTransferred;
4086 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
4088 ref asyncResult.m_SingleBuffer,
4089 1, // only ever 1 buffer being sent
4090 out bytesTransferred,
4092 asyncResult.GetSocketAddressPtr(),
4093 asyncResult.SocketAddress.Size,
4094 asyncResult.OverlappedHandle,
4097 if (errorCode!=SocketError.Success) {
4098 errorCode = (SocketError)Marshal.GetLastWin32Error();
4100 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + size + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4102 catch (ObjectDisposedException)
4104 m_RightEndPoint = oldEndPoint;
4109 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4113 // if the asynchronous native call fails synchronously
4114 // we'll throw a SocketException
4116 if (errorCode!=SocketError.Success) {
4118 // update our internal state after this socket error and throw
4120 m_RightEndPoint = oldEndPoint;
4121 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
4122 SocketException socketException = new SocketException(errorCode);
4123 UpdateStatusAfterSocketError(socketException);
4124 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginSendTo", socketException);
4125 throw socketException;
4128 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginSendTo() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4133 Routine Description:
4135 EndSendTo - Called by user code addressFamilyter I/O is done or the user wants to wait.
4136 until Async completion, needed to retrieve error result from call
4140 AsyncResult - the AsyncResult Returned fron BeginSend call
4144 int - Number of bytes transferred
4148 /// <para>[To be supplied.]</para>
4150 public int EndSendTo(IAsyncResult asyncResult) {
4151 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndSendTo", asyncResult);
4153 throw new ObjectDisposedException(this.GetType().FullName);
4156 // parameter validation
4158 if (asyncResult==null) {
4159 throw new ArgumentNullException("asyncResult");
4161 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
4162 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
4163 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
4165 if (castedAsyncResult.EndCalled) {
4166 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndSendTo"));
4169 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
4170 castedAsyncResult.EndCalled = true;
4171 castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
4173 #if !FEATURE_PAL // perfcounter
4174 if (s_PerfCountersEnabled)
4176 if (bytesTransferred>0) {
4177 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
4178 if (Transport==TransportType.Udp) {
4179 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
4183 #endif //!FEATURE_PAL
4185 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndSendTo() bytesTransferred:" + bytesTransferred.ToString());
4188 // if the asynchronous native call failed asynchronously
4189 // we'll throw a SocketException
4191 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
4193 // update our internal state after this socket error and throw
4195 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
4196 UpdateStatusAfterSocketError(socketException);
4197 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndSendTo", socketException);
4198 throw socketException;
4200 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndSendTo", bytesTransferred);
4201 return bytesTransferred;
4207 Routine Description:
4209 BeginReceive - Async implimentation of Recv call,
4211 Called when we want to start an async receive.
4212 We kick off the receive, and if it completes synchronously we'll
4213 call the callback. Otherwise we'll return an IASyncResult, which
4214 the caller can use to wait on or retrieve the final status, as needed.
4216 Uses Winsock 2 overlapped I/O.
4220 ReadBuffer - status line that we wish to parse
4221 Index - Offset into ReadBuffer to begin reading from
4222 Size - Size of Buffer to recv
4223 Callback - Delegate function that holds callback, called on completeion of I/O
4224 State - State used to track callback, set by caller, not required
4228 IAsyncResult - Async result used to retreive result
4234 /// <para>[To be supplied.]</para>
4237 [HostProtection(ExternalThreading=true)]
4238 public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
4240 SocketError errorCode;
4241 IAsyncResult result = BeginReceive(buffer, offset, size, socketFlags, out errorCode, callback, state);
4242 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
4243 throw new SocketException(errorCode);
4250 [HostProtection(ExternalThreading=true)]
4251 public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
4254 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginReceive", "");
4257 throw new ObjectDisposedException(this.GetType().FullName);
4261 // parameter validation
4264 throw new ArgumentNullException("buffer");
4266 if (offset<0 || offset>buffer.Length) {
4267 throw new ArgumentOutOfRangeException("offset");
4269 if (size<0 || size>buffer.Length-offset) {
4270 throw new ArgumentOutOfRangeException("size");
4273 // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
4274 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4275 asyncResult.StartPostingAsyncOp(false);
4277 // Run the receive with this asyncResult.
4278 errorCode = DoBeginReceive(buffer, offset, size, socketFlags, asyncResult);
4280 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
4285 // We're not throwing, so finish the async op posting code so we can return to the user.
4286 // If the operation already finished, the callback will be called from here.
4287 asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
4290 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceive", asyncResult);
4294 internal IAsyncResult UnsafeBeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
4297 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "UnsafeBeginReceive", "");
4300 throw new ObjectDisposedException(this.GetType().FullName);
4303 // No need to flow the context.
4304 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4305 DoBeginReceive(buffer, offset, size, socketFlags, asyncResult);
4307 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "UnsafeBeginReceive", asyncResult);
4311 private SocketError DoBeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
4313 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() size:" + size.ToString());
4316 IntPtr lastHandle = m_Handle.DangerousGetHandle();
4318 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4319 // avoid a Socket leak in case of error.
4320 SocketError errorCode = SocketError.SocketError;
4323 // Set up asyncResult for overlapped WSARecv.
4324 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
4325 asyncResult.SetUnmanagedStructures(buffer, offset, size, null, false /* don't pin null RemoteEP*/, ref Caches.ReceiveOverlappedCache);
4327 // This can throw ObjectDisposedException.
4328 int bytesTransferred;
4329 errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv(
4331 ref asyncResult.m_SingleBuffer,
4333 out bytesTransferred,
4335 asyncResult.OverlappedHandle,
4338 if (errorCode!=SocketError.Success) {
4339 errorCode = (SocketError)Marshal.GetLastWin32Error();
4340 GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
4342 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " bytesTransferred:" + bytesTransferred.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4346 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4350 // if the asynchronous native call fails synchronously
4351 // we'll throw a SocketException
4353 if (errorCode != SocketError.Success)
4356 // update our internal state after this socket error and throw
4357 asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4358 UpdateStatusAfterSocketError(errorCode);
4359 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
4360 asyncResult.InvokeCallback(new SocketException(errorCode));
4365 m_LastReceiveHandle = lastHandle;
4366 m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
4367 m_LastReceiveTick = Environment.TickCount;
4375 [HostProtection(ExternalThreading=true)]
4376 public IAsyncResult BeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
4378 SocketError errorCode;
4379 IAsyncResult result = BeginReceive(buffers, socketFlags, out errorCode, callback, state);
4380 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
4381 throw new SocketException(errorCode);
4387 [HostProtection(ExternalThreading=true)]
4388 public IAsyncResult BeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
4391 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginReceive", "");
4394 throw new ObjectDisposedException(this.GetType().FullName);
4398 // parameter validation
4400 if (buffers==null) {
4401 throw new ArgumentNullException("buffers");
4404 if(buffers.Count == 0){
4405 throw new ArgumentException(SR.GetString(SR.net_sockets_zerolist,"buffers"), "buffers");
4408 // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback.
4409 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4410 asyncResult.StartPostingAsyncOp(false);
4412 // Run the receive with this asyncResult.
4413 errorCode = DoBeginReceive(buffers, socketFlags, asyncResult);
4415 if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
4420 // We're not throwing, so finish the async op posting code so we can return to the user.
4421 // If the operation already finished, the callback will be called from here.
4422 asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
4425 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceive", asyncResult);
4429 private SocketError DoBeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
4432 IntPtr lastHandle = m_Handle.DangerousGetHandle();
4434 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4435 // avoid a Socket leak in case of error.
4436 SocketError errorCode = SocketError.SocketError;
4439 // Set up asyncResult for overlapped WSASend.
4440 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
4441 asyncResult.SetUnmanagedStructures(buffers, ref Caches.ReceiveOverlappedCache);
4443 // This can throw ObjectDisposedException.
4444 int bytesTransferred;
4445 errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv(
4447 asyncResult.m_WSABuffers,
4448 asyncResult.m_WSABuffers.Length,
4449 out bytesTransferred,
4451 asyncResult.OverlappedHandle,
4454 if (errorCode!=SocketError.Success) {
4455 errorCode = (SocketError)Marshal.GetLastWin32Error();
4456 GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
4458 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4462 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4466 // if the asynchronous native call fails synchronously
4467 // we'll throw a SocketException
4469 if (errorCode != SocketError.Success)
4472 // update our internal state after this socket error and throw
4473 asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4474 UpdateStatusAfterSocketError(errorCode);
4475 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
4480 m_LastReceiveHandle = lastHandle;
4481 m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
4482 m_LastReceiveTick = Environment.TickCount;
4490 private IntPtr m_LastReceiveHandle;
4491 private int m_LastReceiveThread;
4492 private int m_LastReceiveTick;
4499 Routine Description:
4501 EndReceive - Called when I/O is done or the user wants to wait. If
4502 the I/O isn't done, we'll wait for it to complete, and then we'll return
4503 the bytes of I/O done.
4507 AsyncResult - the AsyncResult Returned fron BeginSend call
4511 int - Number of bytes transferred
4516 /// <para>[To be supplied.]</para>
4518 public int EndReceive(IAsyncResult asyncResult) {
4519 SocketError errorCode;
4520 int bytesTransferred = EndReceive(asyncResult, out errorCode);
4521 if(errorCode != SocketError.Success){
4522 throw new SocketException(errorCode);
4524 return bytesTransferred;
4528 public int EndReceive(IAsyncResult asyncResult, out SocketError errorCode) {
4529 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceive", asyncResult);
4531 throw new ObjectDisposedException(this.GetType().FullName);
4534 // parameter validation
4536 if (asyncResult==null) {
4537 throw new ArgumentNullException("asyncResult");
4539 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
4540 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
4541 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
4543 if (castedAsyncResult.EndCalled) {
4544 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceive"));
4547 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
4548 castedAsyncResult.EndCalled = true;
4549 castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4551 #if !FEATURE_PAL // perfcounter
4552 if (s_PerfCountersEnabled)
4554 if (bytesTransferred>0) {
4555 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
4556 if (Transport==TransportType.Udp) {
4557 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
4561 #endif //!FEATURE_PAL
4566 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceive() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " bytesTransferred:" + bytesTransferred.ToString());
4568 catch (ObjectDisposedException) { }
4572 // if the asynchronous native call failed asynchronously
4573 // we'll throw a SocketException
4575 errorCode = (SocketError)castedAsyncResult.ErrorCode;
4576 if (errorCode!=SocketError.Success) {
4578 // update our internal state after this socket error and throw
4580 UpdateStatusAfterSocketError(errorCode);
4581 if(s_LoggingEnabled){
4582 Logging.Exception(Logging.Sockets, this, "EndReceive", new SocketException(errorCode));
4583 Logging.Exit(Logging.Sockets, this, "EndReceive", 0);
4587 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceive", bytesTransferred);
4588 return bytesTransferred;
4593 public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state) {
4594 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "BeginReceiveMessageFrom", "");
4595 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() size:" + size.ToString());
4598 throw new ObjectDisposedException(this.GetType().FullName);
4601 throw new ArgumentNullException("buffer");
4603 if (remoteEP==null) {
4604 throw new ArgumentNullException("remoteEP");
4606 if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
4607 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
4608 remoteEP.AddressFamily, addressFamily), "remoteEP");
4610 if (offset<0 || offset>buffer.Length) {
4611 throw new ArgumentOutOfRangeException("offset");
4613 if (size<0 || size>buffer.Length-offset) {
4614 throw new ArgumentOutOfRangeException("size");
4616 if (m_RightEndPoint==null) {
4617 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
4621 // Set up the result and set it to collect the context.
4622 ReceiveMessageOverlappedAsyncResult asyncResult = new ReceiveMessageOverlappedAsyncResult(this, state, callback);
4623 asyncResult.StartPostingAsyncOp(false);
4625 // Start the ReceiveFrom.
4626 EndPoint oldEndPoint = m_RightEndPoint;
4628 // We don't do a CAS demand here because the contents of remoteEP aren't used by
4629 // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
4630 // with the right address family
4631 SocketAddress socketAddress = SnapshotAndSerialize(ref remoteEP);
4633 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4634 // avoid a Socket leak in case of error.
4635 SocketError errorCode = SocketError.SocketError;
4638 asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, socketFlags, ref Caches.ReceiveOverlappedCache);
4640 // save a copy of the original EndPoint in the asyncResult
4641 asyncResult.SocketAddressOriginal = remoteEP.Serialize();
4643 int bytesTransfered;
4645 SetReceivingPacketInformation();
4647 if (m_RightEndPoint == null)
4649 m_RightEndPoint = remoteEP;
4652 errorCode = (SocketError) WSARecvMsg(
4654 Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.m_MessageBuffer,0),
4655 out bytesTransfered,
4656 asyncResult.OverlappedHandle,
4659 if (errorCode!=SocketError.Success) {
4660 errorCode = (SocketError)Marshal.GetLastWin32Error();
4662 // I have guarantees from Brad Williamson that WSARecvMsg() will never return WSAEMSGSIZE directly, since a completion
4663 // is queued in this case. We wouldn't be able to handle this easily because of assumptions OverlappedAsyncResult
4664 // makes about whether there would be a completion or not depending on the error code. If WSAEMSGSIZE would have been
4665 // normally returned, it returns WSA_IO_PENDING instead. That same map is implemented here just in case.
4666 if (errorCode == SocketError.MessageSize)
4668 GlobalLog.Assert("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom()|Returned WSAEMSGSIZE!");
4669 errorCode = SocketError.IOPending;
4673 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() UnsafeNclNativeMethods.OSSOCK.WSARecvMsg returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4675 catch (ObjectDisposedException)
4677 m_RightEndPoint = oldEndPoint;
4682 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4686 // if the asynchronous native call fails synchronously
4687 // we'll throw a SocketException
4689 if (errorCode!=SocketError.Success)
4692 // update our internal state after this socket error and throw
4694 m_RightEndPoint = oldEndPoint;
4695 asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4696 SocketException socketException = new SocketException(errorCode);
4697 UpdateStatusAfterSocketError(socketException);
4698 if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "BeginReceiveMessageFrom", socketException);
4699 throw socketException;
4702 // Capture the context, maybe call the callback, and return.
4703 asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
4705 if (asyncResult.CompletedSynchronously && !asyncResult.SocketAddressOriginal.Equals(asyncResult.SocketAddress)) {
4707 remoteEP = remoteEP.Create(asyncResult.SocketAddress);
4713 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceiveMessageFrom() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4714 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceiveMessageFrom", asyncResult);
4719 public int EndReceiveMessageFrom(IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation) {
4720 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceiveMessageFrom", asyncResult);
4722 throw new ObjectDisposedException(this.GetType().FullName);
4724 if (endPoint==null) {
4725 throw new ArgumentNullException("endPoint");
4727 if (!CanTryAddressFamily(endPoint.AddressFamily)) {
4728 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
4729 endPoint.AddressFamily, addressFamily), "endPoint");
4731 if (asyncResult==null) {
4732 throw new ArgumentNullException("asyncResult");
4734 ReceiveMessageOverlappedAsyncResult castedAsyncResult = asyncResult as ReceiveMessageOverlappedAsyncResult;
4735 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
4736 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
4738 if (castedAsyncResult.EndCalled) {
4739 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceiveMessageFrom"));
4742 SocketAddress socketAddressOriginal = SnapshotAndSerialize(ref endPoint);
4744 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
4745 castedAsyncResult.EndCalled = true;
4746 castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4748 // Update socket address size
4749 castedAsyncResult.SocketAddress.SetSize(castedAsyncResult.GetSocketAddressSizePtr());
4751 if (!socketAddressOriginal.Equals(castedAsyncResult.SocketAddress)) {
4753 endPoint = endPoint.Create(castedAsyncResult.SocketAddress);
4759 #if !FEATURE_PAL // perfcounter
4760 if (s_PerfCountersEnabled)
4762 if (bytesTransferred>0) {
4763 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
4764 if (Transport==TransportType.Udp) {
4765 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
4769 #endif //!FEATURE_PAL
4771 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceiveMessageFrom() bytesTransferred:" + bytesTransferred.ToString());
4774 // if the asynchronous native call failed asynchronously
4775 // we'll throw a SocketException
4777 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success && (SocketError)castedAsyncResult.ErrorCode != SocketError.MessageSize) {
4779 // update our internal state after this socket error and throw
4781 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
4782 UpdateStatusAfterSocketError(socketException);
4783 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndReceiveMessageFrom", socketException);
4784 throw socketException;
4787 socketFlags = castedAsyncResult.m_flags;
4788 ipPacketInformation = castedAsyncResult.m_IPPacketInformation;
4790 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceiveMessageFrom", bytesTransferred);
4791 return bytesTransferred;
4798 Routine Description:
4800 BeginReceiveFrom - Async implimentation of RecvFrom call,
4802 Called when we want to start an async receive.
4803 We kick off the receive, and if it completes synchronously we'll
4804 call the callback. Otherwise we'll return an IASyncResult, which
4805 the caller can use to wait on or retrieve the final status, as needed.
4807 Uses Winsock 2 overlapped I/O.
4811 ReadBuffer - status line that we wish to parse
4812 Index - Offset into ReadBuffer to begin reading from
4813 Request - Size of Buffer to recv
4814 Flags - Additonal Flags that may be passed to the underlying winsock call
4815 remoteEP - EndPoint that are to receive from
4816 Callback - Delegate function that holds callback, called on completeion of I/O
4817 State - State used to track callback, set by caller, not required
4821 IAsyncResult - Async result used to retreive result
4826 /// <para>[To be supplied.]</para>
4828 [HostProtection(ExternalThreading=true)]
4829 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state) {
4831 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "BeginReceiveFrom", "");
4834 throw new ObjectDisposedException(this.GetType().FullName);
4837 // parameter validation
4840 throw new ArgumentNullException("buffer");
4842 if (remoteEP==null) {
4843 throw new ArgumentNullException("remoteEP");
4845 if (!CanTryAddressFamily(remoteEP.AddressFamily)) {
4846 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
4847 remoteEP.AddressFamily, addressFamily), "remoteEP");
4849 if (offset<0 || offset>buffer.Length) {
4850 throw new ArgumentOutOfRangeException("offset");
4852 if (size<0 || size>buffer.Length-offset) {
4853 throw new ArgumentOutOfRangeException("size");
4855 if (m_RightEndPoint==null) {
4856 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
4859 // We don't do a CAS demand here because the contents of remoteEP aren't used by
4860 // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
4861 // with the right address family
4862 SocketAddress socketAddress = SnapshotAndSerialize(ref remoteEP);
4864 // Set up the result and set it to collect the context.
4865 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
4866 asyncResult.StartPostingAsyncOp(false);
4868 // Start the ReceiveFrom.
4869 DoBeginReceiveFrom(buffer, offset, size, socketFlags, remoteEP, socketAddress, asyncResult);
4871 // Capture the context, maybe call the callback, and return.
4872 asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache);
4874 if (asyncResult.CompletedSynchronously && !asyncResult.SocketAddressOriginal.Equals(asyncResult.SocketAddress)) {
4876 remoteEP = remoteEP.Create(asyncResult.SocketAddress);
4883 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceiveFrom", asyncResult);
4887 private void DoBeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint endPointSnapshot, SocketAddress socketAddress, OverlappedAsyncResult asyncResult)
4889 EndPoint oldEndPoint = m_RightEndPoint;
4890 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() size:" + size.ToString());
4892 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
4893 // avoid a Socket leak in case of error.
4894 SocketError errorCode = SocketError.SocketError;
4897 // Set up asyncResult for overlapped WSARecvFrom.
4898 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
4899 asyncResult.SetUnmanagedStructures(buffer, offset, size, socketAddress, true /* pin remoteEP*/, ref Caches.ReceiveOverlappedCache);
4901 // save a copy of the original EndPoint in the asyncResult
4902 asyncResult.SocketAddressOriginal = endPointSnapshot.Serialize();
4904 if (m_RightEndPoint == null) {
4905 m_RightEndPoint = endPointSnapshot;
4908 int bytesTransferred;
4909 errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
4911 ref asyncResult.m_SingleBuffer,
4913 out bytesTransferred,
4915 asyncResult.GetSocketAddressPtr(),
4916 asyncResult.GetSocketAddressSizePtr(),
4917 asyncResult.OverlappedHandle,
4920 if (errorCode!=SocketError.Success) {
4921 errorCode = (SocketError)Marshal.GetLastWin32Error();
4923 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() UnsafeNclNativeMethods.OSSOCK.WSARecvFrom returns:" + errorCode.ToString() + " size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4925 catch (ObjectDisposedException)
4927 m_RightEndPoint = oldEndPoint;
4932 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
4936 // if the asynchronous native call fails synchronously
4937 // we'll throw a SocketException
4939 if (errorCode!=SocketError.Success) {
4941 // update our internal state after this socket error and throw
4943 m_RightEndPoint = oldEndPoint;
4944 asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
4945 SocketException socketException = new SocketException(errorCode);
4946 UpdateStatusAfterSocketError(socketException);
4947 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceiveFrom", socketException);
4948 throw socketException;
4951 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginReceiveFrom() size:" + size.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
4957 Routine Description:
4959 EndReceiveFrom - Called when I/O is done or the user wants to wait. If
4960 the I/O isn't done, we'll wait for it to complete, and then we'll return
4961 the bytes of I/O done.
4965 AsyncResult - the AsyncResult Returned fron BeginReceiveFrom call
4969 int - Number of bytes transferred
4974 /// <para>[To be supplied.]</para>
4976 public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint) {
4977 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndReceiveFrom", asyncResult);
4979 throw new ObjectDisposedException(this.GetType().FullName);
4982 // parameter validation
4984 if (endPoint==null) {
4985 throw new ArgumentNullException("endPoint");
4987 if (!CanTryAddressFamily(endPoint.AddressFamily)) {
4988 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
4989 endPoint.AddressFamily, addressFamily), "endPoint");
4991 if (asyncResult==null) {
4992 throw new ArgumentNullException("asyncResult");
4994 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
4995 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
4996 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
4998 if (castedAsyncResult.EndCalled) {
4999 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndReceiveFrom"));
5002 SocketAddress socketAddressOriginal = SnapshotAndSerialize(ref endPoint);
5004 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
5005 castedAsyncResult.EndCalled = true;
5006 castedAsyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
5008 // Update socket address size
5009 castedAsyncResult.SocketAddress.SetSize(castedAsyncResult.GetSocketAddressSizePtr());
5011 if (!socketAddressOriginal.Equals(castedAsyncResult.SocketAddress)) {
5013 endPoint = endPoint.Create(castedAsyncResult.SocketAddress);
5019 #if !FEATURE_PAL // perfcounter
5020 if (s_PerfCountersEnabled)
5022 if (bytesTransferred>0) {
5023 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
5024 if (Transport==TransportType.Udp) {
5025 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
5029 #endif //!FEATURE_PAL
5031 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndReceiveFrom() bytesTransferred:" + bytesTransferred.ToString());
5034 // if the asynchronous native call failed asynchronously
5035 // we'll throw a SocketException
5037 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
5039 // update our internal state after this socket error and throw
5041 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
5042 UpdateStatusAfterSocketError(socketException);
5043 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndReceiveFrom", socketException);
5044 throw socketException;
5046 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndReceiveFrom", bytesTransferred);
5047 return bytesTransferred;
5053 Routine Description:
5055 BeginAccept - Does a async winsock accept, creating a new socket on success
5057 Works by creating a pending accept request the first time,
5058 and subsequent calls are queued so that when the first accept completes,
5059 the next accept can be resubmitted in the callback.
5060 this routine may go pending at which time,
5061 but any case the callback Delegate will be called upon completion
5065 Callback - Async Callback Delegate that is called upon Async Completion
5066 State - State used to track callback, set by caller, not required
5070 IAsyncResult - Async result used to retreive resultant new socket
5075 /// <para>[To be supplied.]</para>
5077 [HostProtection(ExternalThreading=true)]
5078 public IAsyncResult BeginAccept(AsyncCallback callback, object state) {
5083 return BeginAccept(0,callback,state);
5086 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginAccept", "");
5088 throw new ObjectDisposedException(this.GetType().FullName);
5091 // Set up the context flow.
5092 AcceptAsyncResult asyncResult = new AcceptAsyncResult(this, state, callback);
5093 asyncResult.StartPostingAsyncOp(false);
5096 DoBeginAccept(asyncResult);
5098 // Set up for return.
5099 asyncResult.FinishPostingAsyncOp(ref Caches.AcceptClosureCache);
5101 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginAccept", asyncResult);
5105 private void DoBeginAccept(LazyAsyncResult asyncResult)
5107 if (m_RightEndPoint==null) {
5108 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
5112 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
5116 // We keep a queue, which lists the set of requests that want to
5117 // be called when an accept queue completes. We call accept
5118 // once, and then as it completes asyncrounsly we pull the
5119 // requests out of the queue and call their callback.
5121 // We start by grabbing Critical Section, then attempt to
5122 // determine if we haven an empty Queue of Accept Sockets
5123 // or if its in a Callback on the Callback thread.
5125 // If its in the callback thread proocessing of the callback, then we
5126 // just need to notify the callback by adding an additional request
5129 // If its an empty queue, and its not in the callback, then
5130 // we just need to get the Accept going, make it go async
5133 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept()");
5135 bool needFinishedCall = false;
5136 SocketError errorCode = 0;
5138 Queue acceptQueue = GetAcceptQueue();
5141 if (acceptQueue.Count == 0)
5143 SocketAddress socketAddress = m_RightEndPoint.Serialize();
5145 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() queue is empty calling UnsafeNclNativeMethods.OSSOCK.accept");
5147 // Check if a socket is already available. We need to be non-blocking to do this.
5148 InternalSetBlocking(false);
5150 SafeCloseSocket acceptedSocketHandle = null;
5153 acceptedSocketHandle = SafeCloseSocket.Accept(
5155 socketAddress.m_Buffer,
5156 ref socketAddress.m_Size);
5157 errorCode = acceptedSocketHandle.IsInvalid ? (SocketError) Marshal.GetLastWin32Error() : SocketError.Success;
5159 catch (ObjectDisposedException)
5161 errorCode = SocketError.NotSocket;
5164 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() UnsafeNclNativeMethods.OSSOCK.accept returns:" + errorCode.ToString());
5166 if (errorCode != SocketError.WouldBlock)
5168 if (errorCode == SocketError.Success)
5170 asyncResult.Result = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress), false);
5174 asyncResult.ErrorCode = (int) errorCode;
5177 // Reset the blocking.
5178 InternalSetBlocking(true);
5180 // Continue outside the lock.
5181 needFinishedCall = true;
5185 // It would block. Start listening for accepts, and add ourselves to the queue.
5186 acceptQueue.Enqueue(asyncResult);
5187 if (!SetAsyncEventSelect(AsyncEventBits.FdAccept))
5189 acceptQueue.Dequeue();
5190 throw new ObjectDisposedException(this.GetType().FullName);
5195 acceptQueue.Enqueue(asyncResult);
5197 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() queue is not empty Count:" + acceptQueue.Count.ToString());
5201 if (needFinishedCall) {
5202 if (errorCode == SocketError.Success)
5204 // Completed synchronously, invoke the callback.
5205 asyncResult.InvokeCallback();
5210 // update our internal state after this socket error and throw
5212 SocketException socketException = new SocketException(errorCode);
5213 UpdateStatusAfterSocketError(socketException);
5214 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginAccept", socketException);
5215 throw socketException;
5219 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
5223 // This is a shortcut to AcceptCallback when called from dispose.
5224 // The only business is lock and complete all results with an error
5226 private void CompleteAcceptResults(object nullState)
5228 Queue acceptQueue = GetAcceptQueue();
5229 bool acceptNeeded = true;
5230 while (acceptNeeded)
5232 LazyAsyncResult asyncResult = null;
5235 // If the queue is empty, cancel the select and indicate not to loop anymore.
5236 if (acceptQueue.Count == 0)
5238 asyncResult = (LazyAsyncResult) acceptQueue.Dequeue();
5240 if (acceptQueue.Count == 0)
5241 acceptNeeded = false;
5244 // Notify about the completion outside the lock.
5246 asyncResult.InvokeCallback(new SocketException(SocketError.OperationAborted));
5249 // Exception from the user callback,
5250 // If we need to loop, offload to a different thread and re-throw for debugging
5252 ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(CompleteAcceptResults), null);
5259 // This method was originally in an AcceptAsyncResult class but that class got useless.
5260 private void AcceptCallback(object nullState)
5262 // We know we need to try completing an accept at first. Keep going until the queue is empty (inside the lock).
5263 // At that point, BeginAccept() takes control of restarting the pump if necessary.
5264 bool acceptNeeded = true;
5265 Queue acceptQueue = GetAcceptQueue();
5267 while (acceptNeeded)
5269 LazyAsyncResult asyncResult = null;
5270 SocketError errorCode = SocketError.OperationAborted;
5271 SocketAddress socketAddress = null;
5272 SafeCloseSocket acceptedSocket = null;
5273 Exception otherException = null;
5274 object result = null;
5279 // Accept Callback - called on the callback path, when we expect to release
5280 // an accept socket that winsock says has completed.
5282 // While we still have items in our Queued list of Accept Requests,
5283 // we recall the Winsock accept, to attempt to gather new
5284 // results, and then match them again the queued items,
5285 // when accept call returns would_block, we reinvoke ourselves
5286 // and rewait for the next asyc callback.
5290 // We may not have items in the queue because of possible ----
5291 // between re-entering this callback manually and from the thread pool.
5293 if (acceptQueue.Count == 0)
5296 // pick an element from the head of the list
5297 asyncResult = (LazyAsyncResult) acceptQueue.Peek();
5301 socketAddress = m_RightEndPoint.Serialize();
5305 // We know we're in non-blocking because of SetAsyncEventSelect().
5306 GlobalLog.Assert(!willBlockInternal, "Socket#{0}::AcceptCallback|Socket should be in non-blocking state.", ValidationHelper.HashString(this));
5307 acceptedSocket = SafeCloseSocket.Accept(
5309 socketAddress.m_Buffer,
5310 ref socketAddress.m_Size);
5312 errorCode = acceptedSocket.IsInvalid ? (SocketError) Marshal.GetLastWin32Error() : SocketError.Success;
5314 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::AcceptCallback() UnsafeNclNativeMethods.OSSOCK.accept returns:" + errorCode.ToString());
5316 catch (ObjectDisposedException)
5318 // Listener socket was closed.
5319 errorCode = SocketError.OperationAborted;
5321 catch (Exception exception)
5323 if (NclUtilities.IsFatal(exception)) throw;
5325 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::AcceptCallback() caught exception:" + exception.Message + " CleanedUp:" + CleanedUp);
5326 otherException = exception;
5330 if (errorCode == SocketError.WouldBlock && otherException == null)
5332 // The accept found no waiting connections, so start listening for more.
5335 m_AsyncEvent.Reset(); // reset event to wait for the next client.
5336 if (SetAsyncEventSelect(AsyncEventBits.FdAccept))
5339 catch (ObjectDisposedException)
5341 // Handle ---- with Dispose, m_AsyncEvent may have been Close()'d already.
5343 otherException = new ObjectDisposedException(this.GetType().FullName);
5346 // CreateAcceptSocket() must be done before InternalSetBlocking() so that the fixup is correct inside
5347 // UpdateAcceptSocket(). InternalSetBlocking() must happen in the lock.
5348 if (otherException != null)
5350 result = otherException;
5352 else if (errorCode == SocketError.Success)
5354 result = CreateAcceptSocket(acceptedSocket, m_RightEndPoint.Create(socketAddress), true);
5358 asyncResult.ErrorCode = (int) errorCode;
5361 // This request completed, so it can be taken off the queue.
5362 acceptQueue.Dequeue();
5364 // If the queue is empty, cancel the select and indicate not to loop anymore.
5365 if (acceptQueue.Count == 0)
5368 UnsetAsyncEventSelect();
5370 acceptNeeded = false;
5374 // Notify about the completion outside the lock.
5376 asyncResult.InvokeCallback(result);
5379 // Exception from the user callback,
5380 // If we need to loop, offload to a different thread and re-throw for debugging
5382 ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(AcceptCallback), nullState);
5392 private bool CanUseAcceptEx
5397 (Thread.CurrentThread.IsThreadPoolThread || SettingsSectionInternal.Section.AlwaysUseCompletionPortsForAccept || m_IsDisconnected);
5403 /// <para>[To be supplied.]</para>
5405 [HostProtection(ExternalThreading=true)]
5406 public IAsyncResult BeginAccept(int receiveSize, AsyncCallback callback, object state) {
5407 return BeginAccept(null,receiveSize,callback,state);
5410 /// This is the true async version that uses AcceptEx
5414 /// <para>[To be supplied.]</para>
5416 [HostProtection(ExternalThreading=true)]
5417 public IAsyncResult BeginAccept(Socket acceptSocket, int receiveSize, AsyncCallback callback, object state) {
5418 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginAccept", "");
5420 throw new ObjectDisposedException(this.GetType().FullName);
5424 // parameter validation
5426 if (receiveSize<0) {
5427 throw new ArgumentOutOfRangeException("size");
5430 // Set up the async result with flowing.
5431 AcceptOverlappedAsyncResult asyncResult = new AcceptOverlappedAsyncResult(this, state, callback);
5432 asyncResult.StartPostingAsyncOp(false);
5434 // Start the accept.
5435 DoBeginAccept(acceptSocket, receiveSize, asyncResult);
5437 // Finish the flow capture, maybe complete here.
5438 asyncResult.FinishPostingAsyncOp(ref Caches.AcceptClosureCache);
5440 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginAccept", asyncResult);
5444 private void DoBeginAccept(Socket acceptSocket, int receiveSize, AcceptOverlappedAsyncResult asyncResult)
5446 if (m_RightEndPoint==null) {
5447 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
5451 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
5454 // if a acceptSocket isn't specified, then we need to create it.
5455 if (acceptSocket == null) {
5456 acceptSocket = new Socket(addressFamily,socketType,protocolType);
5460 if (acceptSocket.m_RightEndPoint != null) {
5461 throw new InvalidOperationException(SR.GetString(SR.net_sockets_namedmustnotbebound, "acceptSocket"));
5464 asyncResult.AcceptSocket = acceptSocket;
5466 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() AcceptSocket:" + ValidationHelper.HashString(acceptSocket));
5468 //the buffer needs to contain the requested data plus room for two sockaddrs and 16 bytes
5469 //of associated data for each.
5470 int addressBufferSize = m_RightEndPoint.Serialize().Size + 16;
5471 byte[] buffer = new byte[receiveSize + ((addressBufferSize) * 2)];
5474 // Set up asyncResult for overlapped AcceptEx.
5475 // This call will use
5476 // completion ports on WinNT
5479 asyncResult.SetUnmanagedStructures(buffer, addressBufferSize);
5481 // This can throw ObjectDisposedException.
5482 int bytesTransferred;
5483 SocketError errorCode = SocketError.Success;
5486 acceptSocket.m_Handle,
5487 Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.Buffer, 0),
5491 out bytesTransferred,
5492 asyncResult.OverlappedHandle))
5494 errorCode = (SocketError)Marshal.GetLastWin32Error();
5496 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
5498 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginAccept() UnsafeNclNativeMethods.OSSOCK.AcceptEx returns:" + errorCode.ToString() + ValidationHelper.HashString(asyncResult));
5501 // if the asynchronous native call fails synchronously
5502 // we'll throw a SocketException
5504 if (errorCode!=SocketError.Success) {
5505 SocketException socketException = new SocketException(errorCode);
5506 UpdateStatusAfterSocketError(socketException);
5507 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginAccept", socketException);
5508 throw socketException;
5512 #endif // !FEATURE_PAL
5516 Routine Description:
5518 EndAccept - Called by user code addressFamilyter I/O is done or the user wants to wait.
5519 until Async completion, so it provides End handling for aync Accept calls,
5520 and retrieves new Socket object
5524 AsyncResult - the AsyncResult Returned fron BeginAccept call
5528 Socket - a valid socket if successful
5534 /// <para>[To be supplied.]</para>
5539 public Socket EndAccept(IAsyncResult asyncResult) {
5540 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndAccept", asyncResult);
5542 throw new ObjectDisposedException(this.GetType().FullName);
5546 if (asyncResult != null && (asyncResult is AcceptOverlappedAsyncResult)) {
5547 int bytesTransferred;
5549 return EndAccept(out buffer, out bytesTransferred, asyncResult);
5551 #endif // !FEATURE_PAL
5554 // parameter validation
5556 if (asyncResult==null) {
5557 throw new ArgumentNullException("asyncResult");
5560 AcceptAsyncResult castedAsyncResult = asyncResult as AcceptAsyncResult;
5561 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
5562 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
5564 if (castedAsyncResult.EndCalled) {
5565 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndAccept"));
5568 object result = castedAsyncResult.InternalWaitForCompletion();
5569 castedAsyncResult.EndCalled = true;
5571 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndAccept() acceptedSocket:" + ValidationHelper.HashString(result));
5574 // if the asynchronous native call failed asynchronously
5575 // we'll throw a SocketException
5577 Exception exception = result as Exception;
5578 if (exception != null)
5583 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
5585 // update our internal state after this socket error and throw
5587 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
5588 UpdateStatusAfterSocketError(socketException);
5589 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndAccept", socketException);
5590 throw socketException;
5593 Socket acceptedSocket = (Socket)result;
5595 if (s_LoggingEnabled) {
5596 Logging.PrintInfo(Logging.Sockets, acceptedSocket,
5597 SR.GetString(SR.net_log_socket_accepted, acceptedSocket.RemoteEndPoint, acceptedSocket.LocalEndPoint));
5598 Logging.Exit(Logging.Sockets, this, "EndAccept", result);
5600 return acceptedSocket;
5606 /// <para>[To be supplied.]</para>
5609 public Socket EndAccept( out byte[] buffer, IAsyncResult asyncResult) {
5610 int bytesTransferred;
5613 Socket socket = EndAccept(out innerBuffer,out bytesTransferred, asyncResult);
5614 buffer = new byte[bytesTransferred];
5615 Array.Copy(innerBuffer,buffer,bytesTransferred);
5621 /// <para>[To be supplied.]</para>
5624 public Socket EndAccept( out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) {
5625 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndAccept", asyncResult);
5627 throw new ObjectDisposedException(this.GetType().FullName);
5631 // parameter validation
5633 if (asyncResult==null) {
5634 throw new ArgumentNullException("asyncResult");
5636 AcceptOverlappedAsyncResult castedAsyncResult = asyncResult as AcceptOverlappedAsyncResult;
5637 if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
5638 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
5640 if (castedAsyncResult.EndCalled) {
5641 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndAccept"));
5644 Socket socket = (Socket)castedAsyncResult.InternalWaitForCompletion();
5645 bytesTransferred = (int)castedAsyncResult.BytesTransferred;
5646 buffer = castedAsyncResult.Buffer;
5648 castedAsyncResult.EndCalled = true;
5650 #if !FEATURE_PAL // perfcounter
5651 if (s_PerfCountersEnabled)
5653 if (bytesTransferred>0) {
5654 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, bytesTransferred);
5659 // if the asynchronous native call failed asynchronously
5660 // we'll throw a SocketException
5662 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
5664 // update our internal state after this socket error and throw
5666 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
5667 UpdateStatusAfterSocketError(socketException);
5668 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndAccept", socketException);
5669 throw socketException;
5675 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());
5677 catch (ObjectDisposedException) { }
5680 if (s_LoggingEnabled) {
5681 Logging.PrintInfo(Logging.Sockets, socket, SR.GetString(SR.net_log_socket_accepted, socket.RemoteEndPoint, socket.LocalEndPoint));
5682 Logging.Exit(Logging.Sockets, this, "EndAccept", socket);
5687 #endif // !FEATURE_PAL
5695 /// Disables sends and receives on a socket.
5698 public void Shutdown(SocketShutdown how) {
5699 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Shutdown", how);
5701 throw new ObjectDisposedException(this.GetType().FullName);
5704 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Shutdown() how:" + how.ToString());
5706 // This can throw ObjectDisposedException.
5707 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int) how);
5710 // if the native call fails we'll throw a SocketException
5712 errorCode = errorCode!=SocketError.SocketError ? SocketError.Success : (SocketError)Marshal.GetLastWin32Error();
5714 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Shutdown() UnsafeNclNativeMethods.OSSOCK.shutdown returns errorCode:" + errorCode);
5717 // skip good cases: success, socket already closed
5719 if (errorCode!=SocketError.Success && errorCode!=SocketError.NotSocket) {
5721 // update our internal state after this socket error and throw
5723 SocketException socketException = new SocketException(errorCode);
5724 UpdateStatusAfterSocketError(socketException);
5725 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Shutdown", socketException );
5726 throw socketException;
5729 SetToDisconnected();
5730 InternalSetBlocking(willBlockInternal);
5731 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Shutdown", "");
5736 //************* internal and private properties *************************
5738 private static object InternalSyncObject {
5740 if (s_InternalSyncObject == null) {
5741 object o = new object();
5742 Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
5744 return s_InternalSyncObject;
5749 private CacheSet Caches
5753 if (m_Caches == null)
5755 // It's not too bad if extra of these are created and lost.
5756 m_Caches = new CacheSet();
5762 private void EnsureDynamicWinsockMethods()
5764 if (m_DynamicWinsockMethods == null)
5766 m_DynamicWinsockMethods = DynamicWinsockMethods.GetMethods(addressFamily, socketType, protocolType);
5770 private bool AcceptEx(SafeCloseSocket listenSocketHandle,
5771 SafeCloseSocket acceptSocketHandle,
5774 int localAddressLength,
5775 int remoteAddressLength,
5776 out int bytesReceived,
5777 SafeHandle overlapped)
5779 EnsureDynamicWinsockMethods();
5780 AcceptExDelegate acceptEx = m_DynamicWinsockMethods.GetDelegate<AcceptExDelegate>(listenSocketHandle);
5782 return acceptEx(listenSocketHandle,
5787 remoteAddressLength,
5792 internal void GetAcceptExSockaddrs(IntPtr buffer,
5793 int receiveDataLength,
5794 int localAddressLength,
5795 int remoteAddressLength,
5796 out IntPtr localSocketAddress,
5797 out int localSocketAddressLength,
5798 out IntPtr remoteSocketAddress,
5799 out int remoteSocketAddressLength)
5801 EnsureDynamicWinsockMethods();
5802 GetAcceptExSockaddrsDelegate getAcceptExSockaddrs = m_DynamicWinsockMethods.GetDelegate<GetAcceptExSockaddrsDelegate>(m_Handle);
5804 getAcceptExSockaddrs(buffer,
5807 remoteAddressLength,
5808 out localSocketAddress,
5809 out localSocketAddressLength,
5810 out remoteSocketAddress,
5811 out remoteSocketAddressLength);
5814 private bool DisconnectEx(SafeCloseSocket socketHandle, SafeHandle overlapped, int flags, int reserved)
5816 EnsureDynamicWinsockMethods();
5817 DisconnectExDelegate disconnectEx = m_DynamicWinsockMethods.GetDelegate<DisconnectExDelegate>(socketHandle);
5819 return disconnectEx(socketHandle, overlapped, flags, reserved);
5822 private bool DisconnectEx_Blocking(IntPtr socketHandle, IntPtr overlapped, int flags, int reserved)
5824 EnsureDynamicWinsockMethods();
5825 DisconnectExDelegate_Blocking disconnectEx_Blocking = m_DynamicWinsockMethods.GetDelegate<DisconnectExDelegate_Blocking>(m_Handle);
5827 return disconnectEx_Blocking(socketHandle, overlapped, flags, reserved);
5830 private bool ConnectEx(SafeCloseSocket socketHandle,
5831 IntPtr socketAddress,
5832 int socketAddressSize,
5836 SafeHandle overlapped)
5838 EnsureDynamicWinsockMethods();
5839 ConnectExDelegate connectEx = m_DynamicWinsockMethods.GetDelegate<ConnectExDelegate>(socketHandle);
5841 return connectEx(socketHandle, socketAddress, socketAddressSize, buffer, dataLength, out bytesSent, overlapped);
5844 private SocketError WSARecvMsg(SafeCloseSocket socketHandle, IntPtr msg, out int bytesTransferred, SafeHandle overlapped, IntPtr completionRoutine)
5846 EnsureDynamicWinsockMethods();
5847 WSARecvMsgDelegate recvMsg = m_DynamicWinsockMethods.GetDelegate<WSARecvMsgDelegate>(socketHandle);
5849 return recvMsg(socketHandle, msg, out bytesTransferred, overlapped, completionRoutine);
5852 private SocketError WSARecvMsg_Blocking(IntPtr socketHandle, IntPtr msg, out int bytesTransferred, IntPtr overlapped, IntPtr completionRoutine)
5854 EnsureDynamicWinsockMethods();
5855 WSARecvMsgDelegate_Blocking recvMsg_Blocking = m_DynamicWinsockMethods.GetDelegate<WSARecvMsgDelegate_Blocking>(m_Handle);
5857 return recvMsg_Blocking(socketHandle, msg, out bytesTransferred, overlapped, completionRoutine);
5860 private bool TransmitPackets(SafeCloseSocket socketHandle, IntPtr packetArray, int elementCount, int sendSize, SafeNativeOverlapped overlapped, TransmitFileOptions flags)
5862 EnsureDynamicWinsockMethods();
5863 TransmitPacketsDelegate transmitPackets = m_DynamicWinsockMethods.GetDelegate<TransmitPacketsDelegate>(socketHandle);
5865 return transmitPackets(socketHandle, packetArray, elementCount, sendSize, overlapped, flags);
5868 private Queue GetAcceptQueue() {
5869 if (m_AcceptQueueOrConnectResult == null)
5870 Interlocked.CompareExchange(ref m_AcceptQueueOrConnectResult, new Queue(16), null);
5871 return (Queue)m_AcceptQueueOrConnectResult;
5875 internal bool CleanedUp {
5877 return (m_IntCleanedUp == 1);
5882 internal TransportType Transport {
5885 protocolType==Sockets.ProtocolType.Tcp ?
5887 protocolType==Sockets.ProtocolType.Udp ?
5894 //************* internal and private methods *************************
5898 private void CheckSetOptionPermissions(SocketOptionLevel optionLevel, SocketOptionName optionName) {
5899 // freely allow only those below
5900 if ( !(optionLevel == SocketOptionLevel.Tcp &&
5901 (optionName == SocketOptionName.NoDelay ||
5902 optionName == SocketOptionName.BsdUrgent ||
5903 optionName == SocketOptionName.Expedited))
5905 !(optionLevel == SocketOptionLevel.Udp &&
5906 (optionName == SocketOptionName.NoChecksum||
5907 optionName == SocketOptionName.ChecksumCoverage))
5909 !(optionLevel == SocketOptionLevel.Socket &&
5910 (optionName == SocketOptionName.KeepAlive ||
5911 optionName == SocketOptionName.Linger ||
5912 optionName == SocketOptionName.DontLinger ||
5913 optionName == SocketOptionName.SendBuffer ||
5914 optionName == SocketOptionName.ReceiveBuffer ||
5915 optionName == SocketOptionName.SendTimeout ||
5916 optionName == SocketOptionName.ExclusiveAddressUse ||
5917 optionName == SocketOptionName.ReceiveTimeout))
5919 //ipv6 protection level
5920 !(optionLevel == SocketOptionLevel.IPv6 &&
5921 optionName == (SocketOptionName)23)){
5923 ExceptionHelper.UnmanagedPermission.Demand();
5927 private SocketAddress SnapshotAndSerialize(ref EndPoint remoteEP)
5929 IPEndPoint ipSnapshot = remoteEP as IPEndPoint;
5931 if (ipSnapshot != null)
5933 ipSnapshot = ipSnapshot.Snapshot();
5934 remoteEP = RemapIPEndPoint(ipSnapshot);
5937 return CallSerializeCheckDnsEndPoint(remoteEP);
5940 // Give a nicer exception for DnsEndPoint in cases where it is not supported
5941 private SocketAddress CallSerializeCheckDnsEndPoint(EndPoint remoteEP)
5943 if (remoteEP is DnsEndPoint)
5945 throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_dnsendpoint, "remoteEP"), "remoteEP");
5948 return remoteEP.Serialize();
5951 // DualMode: Automatically re-map IPv4 addresses to IPv6 addresses
5952 private IPEndPoint RemapIPEndPoint(IPEndPoint input)
5954 if (input.AddressFamily == AddressFamily.InterNetwork && IsDualMode)
5956 return new IPEndPoint(input.Address.MapToIPv6(), input.Port);
5962 // socketAddress must always be the result of remoteEP.Serialize()
5964 private SocketAddress CheckCacheRemote(ref EndPoint remoteEP, bool isOverwrite)
5966 IPEndPoint ipSnapshot = remoteEP as IPEndPoint;
5968 if (ipSnapshot != null)
5970 // Snapshot to avoid external tampering and malicious derivations if IPEndPoint
5971 ipSnapshot = ipSnapshot.Snapshot();
5972 // DualMode: Do the security check on the user input address, but return an IPEndPoint
5973 // mapped to an IPv6 address.
5974 remoteEP = RemapIPEndPoint(ipSnapshot);
5977 // This doesn't use SnapshotAndSerialize() because we need the ipSnapshot later.
5978 SocketAddress socketAddress = CallSerializeCheckDnsEndPoint(remoteEP);
5980 // We remember the first peer we have communicated with
5981 SocketAddress permittedRemoteAddress = m_PermittedRemoteAddress;
5982 if (permittedRemoteAddress != null && permittedRemoteAddress.Equals(socketAddress))
5984 return permittedRemoteAddress;
5988 // for now SocketPermission supports only IPEndPoint
5990 if (ipSnapshot != null)
5993 // create the permissions the user would need for the call
5995 SocketPermission socketPermission
5996 = new SocketPermission(
5997 NetworkAccess.Connect,
5999 ipSnapshot.Address.ToString(),
6004 socketPermission.Demand();
6008 // for V1 we will demand permission to run UnmanagedCode for
6009 // an EndPoint that is not an IPEndPoint until we figure out how these fit
6010 // into the whole picture of SocketPermission
6013 ExceptionHelper.UnmanagedPermission.Demand();
6015 //cache only the first peer we communicated with
6016 if (m_PermittedRemoteAddress == null || isOverwrite) {
6017 m_PermittedRemoteAddress = socketAddress;
6020 return socketAddress;
6024 internal static void InitializeSockets() {
6025 if (!s_Initialized) {
6026 lock(InternalSyncObject){
6027 if (!s_Initialized) {
6030 WSAData wsaData = new WSAData();
6032 SocketError errorCode =
6033 UnsafeNclNativeMethods.OSSOCK.WSAStartup(
6034 (short)0x0202, // we need 2.2
6037 if (errorCode!=SocketError.Success) {
6039 // failed to initialize, throw
6041 // WSAStartup does not set LastWin32Error
6042 throw new SocketException(errorCode);
6048 // we're on WinNT4 or greater, we could use CompletionPort if we
6049 // wanted. check if the user has disabled this functionality in
6050 // the registry, otherwise use CompletionPort.
6054 BooleanSwitch disableCompletionPortSwitch = new BooleanSwitch("DisableNetCompletionPort", "System.Net disabling of Completion Port");
6057 // the following will be true if they've disabled the completionPort
6059 UseOverlappedIO = disableCompletionPortSwitch.Enabled;
6066 ipv4 = IsProtocolSupported (System.Net.NetworkInformation.NetworkInterfaceComponent.IPv4);
6067 ipv6 = IsProtocolSupported (System.Net.NetworkInformation.NetworkInterfaceComponent.IPv6);
6069 SafeCloseSocket.InnerSafeCloseSocket socketV4 =
6070 UnsafeNclNativeMethods.OSSOCK.WSASocket(
6071 AddressFamily.InterNetwork,
6076 (SocketConstructorFlags) 0);
6077 if (socketV4.IsInvalid) {
6078 errorCode = (SocketError) Marshal.GetLastWin32Error();
6079 if (errorCode == SocketError.AddressFamilyNotSupported)
6085 SafeCloseSocket.InnerSafeCloseSocket socketV6 =
6086 UnsafeNclNativeMethods.OSSOCK.WSASocket(
6087 AddressFamily.InterNetworkV6,
6092 (SocketConstructorFlags) 0);
6093 if (socketV6.IsInvalid) {
6094 errorCode = (SocketError) Marshal.GetLastWin32Error();
6095 if (errorCode == SocketError.AddressFamilyNotSupported)
6105 #if COMNET_DISABLEIPV6
6107 // Turn off IPv6 support
6112 // Now read the switch as the final check: by checking the current value for IPv6
6113 // support we may be able to avoid a painful configuration file read.
6116 s_OSSupportsIPv6 = true;
6117 ipv6 = SettingsSectionInternal.Section.Ipv6Enabled;
6122 // Update final state
6124 s_SupportsIPv4 = ipv4;
6125 s_SupportsIPv6 = ipv6;
6127 #else //!FEATURE_PAL
6129 s_SupportsIPv4 = true;
6130 s_SupportsIPv6 = false;
6132 #endif //!FEATURE_PAL
6134 // Cache some settings locally.
6137 #if !FEATURE_PAL // perfcounter
6138 s_PerfCountersEnabled = NetworkingPerfCounters.Instance.Enabled;
6142 s_Initialized = true;
6149 internal void InternalConnect(EndPoint remoteEP)
6151 EndPoint endPointSnapshot = remoteEP;
6152 SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
6153 DoConnect(endPointSnapshot, socketAddress);
6156 private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
6158 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Connect", endPointSnapshot);
6160 // This can throw ObjectDisposedException.
6161 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.WSAConnect(
6162 m_Handle.DangerousGetHandle(),
6163 socketAddress.m_Buffer,
6164 socketAddress.m_Size,
6173 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalConnect() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint) + " UnsafeNclNativeMethods.OSSOCK.WSAConnect returns errorCode:" + errorCode);
6175 catch (ObjectDisposedException) { }
6179 // if the native call fails we'll throw a SocketException
6181 if (errorCode!=SocketError.Success) {
6183 // update our internal state after this socket error and throw
6185 SocketException socketException = new SocketException(endPointSnapshot);
6186 UpdateStatusAfterSocketError(socketException);
6187 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Connect", socketException);
6188 throw socketException;
6191 if (m_RightEndPoint==null) {
6193 // save a copy of the EndPoint so we can use it for Create()
6195 m_RightEndPoint = endPointSnapshot;
6198 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoConnect() connection to:" + endPointSnapshot.ToString());
6201 // update state and performance counter
6204 if (s_LoggingEnabled) {
6205 Logging.PrintInfo(Logging.Sockets, this, SR.GetString(SR.net_log_socket_connected, LocalEndPoint, RemoteEndPoint));
6206 Logging.Exit(Logging.Sockets, this, "Connect", "");
6211 protected virtual void Dispose(bool disposing)
6220 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() disposing:true CleanedUp:" + CleanedUp.ToString());
6221 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Dispose", null);
6223 catch (Exception exception)
6225 if (NclUtilities.IsFatal(exception)) throw;
6228 // make sure we're the first call to Dispose and no SetAsyncEventSelect is in progress
6230 while ((last = Interlocked.CompareExchange(ref m_IntCleanedUp, 1, 0)) == 2)
6237 if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "Dispose", null);
6239 catch (Exception exception)
6241 if (NclUtilities.IsFatal(exception)) throw;
6246 SetToDisconnected();
6248 AsyncEventBits pendingAsync = AsyncEventBits.FdNone;
6249 if (m_BlockEventBits != AsyncEventBits.FdNone)
6251 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Pending nonblocking operations! m_BlockEventBits:" + m_BlockEventBits.ToString());
6252 UnsetAsyncEventSelect();
6253 if (m_BlockEventBits == AsyncEventBits.FdConnect)
6255 LazyAsyncResult connectResult = m_AcceptQueueOrConnectResult as LazyAsyncResult;
6256 if (connectResult != null && !connectResult.InternalPeekCompleted)
6257 pendingAsync = AsyncEventBits.FdConnect;
6259 else if (m_BlockEventBits == AsyncEventBits.FdAccept)
6261 Queue acceptQueue = m_AcceptQueueOrConnectResult as Queue;
6262 if (acceptQueue != null && acceptQueue.Count != 0)
6263 pendingAsync = AsyncEventBits.FdAccept;
6267 #if SOCKETTHREADPOOL
6268 if (m_BoundToThreadPool) SocketThreadPool.UnBindHandle(m_Handle);
6270 // Close the handle in one of several ways depending on the timeout.
6271 // Ignore ObjectDisposedException just in case the handle somehow gets disposed elsewhere.
6274 int timeout = m_CloseTimeout;
6278 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Calling m_Handle.Dispose()");
6283 SocketError errorCode;
6285 // Go to blocking mode. We know no WSAEventSelect is pending because of the lock and UnsetAsyncEventSelect() above.
6286 if (!willBlock || !willBlockInternal)
6288 int nonBlockCmd = 0;
6289 errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
6291 IoctlSocketConstants.FIONBIO,
6293 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") ioctlsocket(FIONBIO):" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
6298 // Close with existing user-specified linger option.
6299 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() Calling m_Handle.CloseAsIs()");
6300 m_Handle.CloseAsIs();
6304 // Since our timeout is in ms and linger is in seconds, implement our own sortof linger here.
6305 errorCode = UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int) SocketShutdown.Send);
6306 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") shutdown():" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
6308 // This should give us a timeout in milliseconds.
6309 errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6311 SocketOptionLevel.Socket,
6312 SocketOptionName.ReceiveTimeout,
6315 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") setsockopt():" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
6317 if (errorCode != SocketError.Success)
6325 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.recv(m_Handle.DangerousGetHandle(), null, 0, SocketFlags.None);
6327 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") recv():" + errorCode.ToString());
6329 if (errorCode != (SocketError) 0)
6331 // We got a timeout - abort.
6336 // We got a FIN or data. Use ioctlsocket to find out which.
6337 int dataAvailable = 0;
6338 errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
6340 IoctlSocketConstants.FIONREAD,
6342 GlobalLog.Print("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ") ioctlsocket(FIONREAD):" + (errorCode == SocketError.SocketError ? (SocketError) Marshal.GetLastWin32Error() : errorCode).ToString());
6344 if (errorCode != SocketError.Success || dataAvailable != 0)
6346 // If we have data or don't know, safest thing is to reset.
6351 // We got a FIN. It'd be nice to block for the remainder of the timeout for the handshake to finsh.
6352 // Since there's no real way to do that, close the socket with the user's preferences. This lets
6353 // the user decide how best to handle this case via the linger options.
6354 m_Handle.CloseAsIs();
6361 catch (ObjectDisposedException)
6363 GlobalLog.Assert("SafeCloseSocket::Dispose(handle:" + m_Handle.DangerousGetHandle().ToString("x") + ")", "Closing the handle threw ObjectDisposedException.");
6367 // Clear out the Overlapped caches.
6368 if (m_Caches != null)
6370 OverlappedCache.InterlockedFree(ref m_Caches.SendOverlappedCache);
6371 OverlappedCache.InterlockedFree(ref m_Caches.ReceiveOverlappedCache);
6375 if (pendingAsync == AsyncEventBits.FdConnect)
6377 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() QueueUserWorkItem for ConnectCallback");
6378 // This will try to complete connectResult on a different thread
6379 ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(((LazyAsyncResult)m_AcceptQueueOrConnectResult).InvokeCallback), new SocketException(SocketError.OperationAborted));
6381 else if (pendingAsync == AsyncEventBits.FdAccept)
6383 // This will try to complete all acceptResults on a different thread
6384 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Dispose() QueueUserWorkItem for AcceptCallback");
6385 ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(CompleteAcceptResults), null);
6388 if (m_AsyncEvent != null)
6390 m_AsyncEvent.Close();
6395 public void Dispose() {
6397 GC.SuppressFinalize(this);
6405 // this version does not throw.
6406 internal void InternalShutdown(SocketShutdown how) {
6407 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalShutdown() how:" + how.ToString());
6409 if (CleanedUp || m_Handle.IsInvalid) {
6415 UnsafeNclNativeMethods.OSSOCK.shutdown(m_Handle, (int)how);
6417 catch (ObjectDisposedException) { }
6420 // Set the socket option to begin receiving packet information if it has not been
6421 // set for this socket previously
6422 internal void SetReceivingPacketInformation()
6424 if (!m_ReceivingPacketInformation)
6426 // DualMode: When bound to IPv6Any you must enable both socket options.
6427 // When bound to an IPv4 mapped IPv6 address you must enable the IPv4 socket option.
6428 IPEndPoint ipEndPoint = m_RightEndPoint as IPEndPoint;
6429 IPAddress boundAddress = (ipEndPoint != null ? ipEndPoint.Address : null);
6430 Debug.Assert(boundAddress != null, "Not Bound");
6431 if (this.addressFamily == AddressFamily.InterNetwork
6432 || (boundAddress != null && IsDualMode
6433 && (boundAddress.IsIPv4MappedToIPv6 || boundAddress.Equals(IPAddress.IPv6Any))))
6435 SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
6438 if (this.addressFamily == AddressFamily.InterNetworkV6
6439 && (boundAddress == null || !boundAddress.IsIPv4MappedToIPv6))
6441 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true);
6444 m_ReceivingPacketInformation = true;
6448 internal unsafe void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue, bool silent) {
6449 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() optionLevel:" + optionLevel + " optionName:" + optionName + " optionValue:" + optionValue + " silent:" + silent);
6450 if (silent && (CleanedUp || m_Handle.IsInvalid)) {
6451 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() skipping the call");
6454 SocketError errorCode = SocketError.Success;
6456 // This can throw ObjectDisposedException.
6457 errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6464 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetSocketOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
6467 if (silent && m_Handle.IsInvalid) {
6473 // Keep the internal state in [....] if the user manually resets this
6474 if (optionName == SocketOptionName.PacketInformation && optionValue == 0 &&
6475 errorCode == SocketError.Success)
6477 m_ReceivingPacketInformation = false;
6485 // if the native call fails we'll throw a SocketException
6487 if (errorCode==SocketError.SocketError) {
6489 // update our internal state after this socket error and throw
6491 SocketException socketException = new SocketException();
6492 UpdateStatusAfterSocketError(socketException);
6493 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "SetSocketOption", socketException);
6494 throw socketException;
6498 private void setMulticastOption(SocketOptionName optionName, MulticastOption MR) {
6499 IPMulticastRequest ipmr = new IPMulticastRequest();
6501 ipmr.MulticastAddress = unchecked((int)MR.Group.m_Address);
6504 if(MR.LocalAddress != null){
6505 ipmr.InterfaceAddress = unchecked((int)MR.LocalAddress.m_Address);
6507 else { //this structure works w/ interfaces as well
6508 int ifIndex =IPAddress.HostToNetworkOrder(MR.InterfaceIndex);
6509 ipmr.InterfaceAddress = unchecked((int)ifIndex);
6513 ipmr.MulticastAddress = (int) (((uint) ipmr.MulticastAddress << 24) |
6514 (((uint) ipmr.MulticastAddress & 0x0000FF00) << 8) |
6515 (((uint) ipmr.MulticastAddress >> 8) & 0x0000FF00) |
6516 ((uint) ipmr.MulticastAddress >> 24));
6518 if(MR.LocalAddress != null){
6519 ipmr.InterfaceAddress = (int) (((uint) ipmr.InterfaceAddress << 24) |
6520 (((uint) ipmr.InterfaceAddress & 0x0000FF00) << 8) |
6521 (((uint) ipmr.InterfaceAddress >> 8) & 0x0000FF00) |
6522 ((uint) ipmr.InterfaceAddress >> 24));
6526 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setMulticastOption(): optionName:" + optionName.ToString() + " MR:" + MR.ToString() + " ipmr:" + ipmr.ToString() + " IPMulticastRequest.Size:" + IPMulticastRequest.Size.ToString());
6528 // This can throw ObjectDisposedException.
6529 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6531 SocketOptionLevel.IP,
6534 IPMulticastRequest.Size);
6536 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setMulticastOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
6539 // if the native call fails we'll throw a SocketException
6541 if (errorCode==SocketError.SocketError) {
6543 // update our internal state after this socket error and throw
6545 SocketException socketException = new SocketException();
6546 UpdateStatusAfterSocketError(socketException);
6547 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setMulticastOption", socketException);
6548 throw socketException;
6555 /// IPv6 setsockopt for JOIN / LEAVE multicast group
6558 private void setIPv6MulticastOption(SocketOptionName optionName, IPv6MulticastOption MR) {
6559 IPv6MulticastRequest ipmr = new IPv6MulticastRequest();
6561 ipmr.MulticastAddress = MR.Group.GetAddressBytes();
6562 ipmr.InterfaceIndex = unchecked((int)MR.InterfaceIndex);
6564 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setIPv6MulticastOption(): optionName:" + optionName.ToString() + " MR:" + MR.ToString() + " ipmr:" + ipmr.ToString() + " IPv6MulticastRequest.Size:" + IPv6MulticastRequest.Size.ToString());
6566 // This can throw ObjectDisposedException.
6567 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6569 SocketOptionLevel.IPv6,
6572 IPv6MulticastRequest.Size);
6574 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setIPv6MulticastOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
6577 // if the native call fails we'll throw a SocketException
6579 if (errorCode==SocketError.SocketError) {
6581 // update our internal state after this socket error and throw
6583 SocketException socketException = new SocketException();
6584 UpdateStatusAfterSocketError(socketException);
6585 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setIPv6MulticastOption", socketException);
6586 throw socketException;
6590 private void setLingerOption(LingerOption lref) {
6591 Linger lngopt = new Linger();
6592 lngopt.OnOff = lref.Enabled ? (ushort)1 : (ushort)0;
6593 lngopt.Time = (ushort)lref.LingerTime;
6595 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setLingerOption(): lref:" + lref.ToString());
6597 // This can throw ObjectDisposedException.
6598 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
6600 SocketOptionLevel.Socket,
6601 SocketOptionName.Linger,
6605 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::setLingerOption() UnsafeNclNativeMethods.OSSOCK.setsockopt returns errorCode:" + errorCode);
6608 // if the native call fails we'll throw a SocketException
6610 if (errorCode==SocketError.SocketError) {
6612 // update our internal state after this socket error and throw
6614 SocketException socketException = new SocketException();
6615 UpdateStatusAfterSocketError(socketException);
6616 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "setLingerOption", socketException);
6617 throw socketException;
6621 private LingerOption getLingerOpt() {
6622 Linger lngopt = new Linger();
6625 // This can throw ObjectDisposedException.
6626 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
6628 SocketOptionLevel.Socket,
6629 SocketOptionName.Linger,
6633 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getLingerOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
6636 // if the native call fails we'll throw a SocketException
6638 if (errorCode==SocketError.SocketError) {
6640 // update our internal state after this socket error and throw
6642 SocketException socketException = new SocketException();
6643 UpdateStatusAfterSocketError(socketException);
6644 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getLingerOpt", socketException);
6645 throw socketException;
6648 LingerOption lingerOption = new LingerOption(lngopt.OnOff!=0, (int)lngopt.Time);
6649 return lingerOption;
6652 private MulticastOption getMulticastOpt(SocketOptionName optionName) {
6653 IPMulticastRequest ipmr = new IPMulticastRequest();
6654 int optlen = IPMulticastRequest.Size;
6656 // This can throw ObjectDisposedException.
6657 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
6659 SocketOptionLevel.IP,
6664 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getMulticastOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
6667 // if the native call fails we'll throw a SocketException
6669 if (errorCode==SocketError.SocketError) {
6671 // update our internal state after this socket error and throw
6673 SocketException socketException = new SocketException();
6674 UpdateStatusAfterSocketError(socketException);
6675 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getMulticastOpt", socketException);
6676 throw socketException;
6680 ipmr.MulticastAddress = (int) (((uint) ipmr.MulticastAddress << 24) |
6681 (((uint) ipmr.MulticastAddress & 0x0000FF00) << 8) |
6682 (((uint) ipmr.MulticastAddress >> 8) & 0x0000FF00) |
6683 ((uint) ipmr.MulticastAddress >> 24));
6684 ipmr.InterfaceAddress = (int) (((uint) ipmr.InterfaceAddress << 24) |
6685 (((uint) ipmr.InterfaceAddress & 0x0000FF00) << 8) |
6686 (((uint) ipmr.InterfaceAddress >> 8) & 0x0000FF00) |
6687 ((uint) ipmr.InterfaceAddress >> 24));
6690 IPAddress multicastAddr = new IPAddress(ipmr.MulticastAddress);
6691 IPAddress multicastIntr = new IPAddress(ipmr.InterfaceAddress);
6693 MulticastOption multicastOption = new MulticastOption(multicastAddr, multicastIntr);
6695 return multicastOption;
6701 /// IPv6 getsockopt for JOIN / LEAVE multicast group
6704 private IPv6MulticastOption getIPv6MulticastOpt(SocketOptionName optionName) {
6705 IPv6MulticastRequest ipmr = new IPv6MulticastRequest();
6707 int optlen = IPv6MulticastRequest.Size;
6709 // This can throw ObjectDisposedException.
6710 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockopt(
6712 SocketOptionLevel.IP,
6717 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::getIPv6MulticastOpt() UnsafeNclNativeMethods.OSSOCK.getsockopt returns errorCode:" + errorCode);
6720 // if the native call fails we'll throw a SocketException
6722 if (errorCode==SocketError.SocketError) {
6724 // update our internal state after this socket error and throw
6726 SocketException socketException = new SocketException();
6727 UpdateStatusAfterSocketError(socketException);
6728 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "getIPv6MulticastOpt", socketException);
6729 throw socketException;
6732 IPv6MulticastOption multicastOption = new IPv6MulticastOption(new IPAddress(ipmr.MulticastAddress),ipmr.InterfaceIndex);
6734 return multicastOption;
6738 // this version will ignore failures but it returns the win32
6739 // error code, and it will update internal state on success.
6741 private SocketError InternalSetBlocking(bool desired, out bool current) {
6742 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "desired:" + desired.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
6745 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "ObjectDisposed");
6746 current = willBlock;
6747 return SocketError.Success;
6750 int intBlocking = desired ? 0 : -1;
6753 SocketError errorCode;
6756 errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
6758 IoctlSocketConstants.FIONBIO,
6761 if (errorCode == SocketError.SocketError)
6763 errorCode = (SocketError) Marshal.GetLastWin32Error();
6766 catch (ObjectDisposedException)
6768 errorCode = SocketError.NotSocket;
6771 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking() UnsafeNclNativeMethods.OSSOCK.ioctlsocket returns errorCode:" + errorCode);
6774 // we will update only internal state but only on successfull win32 call
6775 // so if the native call fails, the state will remain the same.
6777 if (errorCode==SocketError.Success) {
6779 // success, update internal state
6781 willBlockInternal = intBlocking==0;
6784 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::InternalSetBlocking", "errorCode:" + errorCode.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
6785 current = willBlockInternal;
6789 // this version will ignore all failures.
6791 internal void InternalSetBlocking(bool desired) {
6793 InternalSetBlocking(desired, out current);
6796 private static IntPtr[] SocketListToFileDescriptorSet(IList socketList) {
6797 if (socketList==null || socketList.Count==0) {
6800 IntPtr[] fileDescriptorSet = new IntPtr[socketList.Count + 1];
6801 fileDescriptorSet[0] = (IntPtr)socketList.Count;
6802 for (int current=0; current<socketList.Count; current++) {
6803 if (!(socketList[current] is Socket)) {
6804 throw new ArgumentException(SR.GetString(SR.net_sockets_select, socketList[current].GetType().FullName, typeof(System.Net.Sockets.Socket).FullName), "socketList");
6806 fileDescriptorSet[current + 1] = ((Socket)socketList[current]).m_Handle.DangerousGetHandle();
6808 return fileDescriptorSet;
6812 // Transform the list socketList such that the only sockets left are those
6813 // with a file descriptor contained in the array "fileDescriptorArray"
6815 private static void SelectFileDescriptor(IList socketList, IntPtr[] fileDescriptorSet) {
6816 // Walk the list in order
6817 // Note that the counter is not necessarily incremented at each step;
6818 // when the socket is removed, advancing occurs automatically as the
6819 // other elements are shifted down.
6820 if (socketList==null || socketList.Count==0) {
6823 if ((int)fileDescriptorSet[0]==0) {
6824 // no socket present, will never find any socket, remove them all
6829 for (int currentSocket=0; currentSocket<socketList.Count; currentSocket++) {
6830 Socket socket = socketList[currentSocket] as Socket;
6831 // Look for the file descriptor in the array
6832 int currentFileDescriptor;
6833 for (currentFileDescriptor=0; currentFileDescriptor<(int)fileDescriptorSet[0]; currentFileDescriptor++) {
6834 if (fileDescriptorSet[currentFileDescriptor + 1]==socket.m_Handle.DangerousGetHandle()) {
6838 if (currentFileDescriptor==(int)fileDescriptorSet[0]) {
6839 // descriptor not found: remove the current socket and start again
6840 socketList.RemoveAt(currentSocket--);
6847 private static void MicrosecondsToTimeValue(long microSeconds, ref TimeValue socketTime) {
6848 socketTime.Seconds = (int) (microSeconds / microcnv);
6849 socketTime.Microseconds = (int) (microSeconds % microcnv);
6851 //Implements ConnectEx - this provides completion port IO and support for
6852 //disconnect and reconnects
6854 // Since this is private, the unsafe mode is specified with a flag instead of an overload.
6855 private IAsyncResult BeginConnectEx(EndPoint remoteEP, bool flowContext, AsyncCallback callback, object state)
6857 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginConnectEx", "");
6859 // This will check the permissions for connect.
6860 EndPoint endPointSnapshot = remoteEP;
6861 SocketAddress socketAddress = flowContext ? CheckCacheRemote(ref endPointSnapshot, true) : SnapshotAndSerialize(ref endPointSnapshot);
6863 //socket must be bound first
6864 //the calling method BeginConnect will ensure that this method is only
6865 //called if m_RightEndPoint is not null, of that the endpoint is an ipendpoint
6866 if (m_RightEndPoint==null){
6867 GlobalLog.Assert(endPointSnapshot.GetType() == typeof(IPEndPoint), "Socket#{0}::BeginConnectEx()|Socket not bound and endpoint not IPEndPoint.", ValidationHelper.HashString(this));
6868 if (endPointSnapshot.AddressFamily == AddressFamily.InterNetwork)
6869 InternalBind(new IPEndPoint(IPAddress.Any, 0));
6871 InternalBind(new IPEndPoint(IPAddress.IPv6Any, 0));
6875 // Allocate the async result and the event we'll pass to the
6878 ConnectOverlappedAsyncResult asyncResult = new ConnectOverlappedAsyncResult(this, endPointSnapshot, state, callback);
6880 // If context flowing is enabled, set it up here. No need to lock since the context isn't used until the callback.
6883 asyncResult.StartPostingAsyncOp(false);
6886 // This will pin socketAddress buffer
6887 asyncResult.SetUnmanagedStructures(socketAddress.m_Buffer);
6889 //we should fix this in Whidbey.
6890 EndPoint oldEndPoint = m_RightEndPoint;
6891 if (m_RightEndPoint == null) {
6892 m_RightEndPoint = endPointSnapshot;
6895 SocketError errorCode=SocketError.Success;
6897 int ignoreBytesSent;
6903 Marshal.UnsafeAddrOfPinnedArrayElement(socketAddress.m_Buffer, 0),
6904 socketAddress.m_Size,
6907 out ignoreBytesSent,
6908 asyncResult.OverlappedHandle))
6910 errorCode = (SocketError)Marshal.GetLastWin32Error();
6916 // Bug 152350: If ConnectEx throws we need to unpin the socketAddress buffer.
6917 // m_RightEndPoint will always equal oldEndPoint anyways...
6919 asyncResult.InternalCleanup();
6920 m_RightEndPoint = oldEndPoint;
6925 if (errorCode == SocketError.Success) {
6929 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginConnectEx() UnsafeNclNativeMethods.OSSOCK.connect returns:" + errorCode.ToString());
6931 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
6934 // if the asynchronous native call fails synchronously
6935 // we'll throw a SocketException
6937 if (errorCode != SocketError.Success) {
6939 // update our internal state after this socket error and throw
6941 m_RightEndPoint = oldEndPoint;
6942 SocketException socketException = new SocketException(errorCode);
6943 UpdateStatusAfterSocketError(socketException);
6944 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginConnectEx", socketException);
6945 throw socketException;
6948 // We didn't throw, so indicate that we're returning this result to the user. This may call the callback.
6949 // This is a nop if the context isn't being flowed.
6950 asyncResult.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
6952 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginConnectEx() to:" + endPointSnapshot.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
6953 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginConnectEx", asyncResult);
6958 internal void MultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags) {
6959 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "MultipleSend", "");
6961 throw new ObjectDisposedException(this.GetType().FullName);
6964 // parameter validation
6966 GlobalLog.Assert(buffers != null, "Socket#{0}::MultipleSend()|buffers == null", ValidationHelper.HashString(this));
6967 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::MultipleSend() buffers.Length:" + buffers.Length.ToString());
6969 WSABuffer[] WSABuffers = new WSABuffer[buffers.Length];
6970 GCHandle[] objectsToPin = null;
6971 int bytesTransferred;
6972 SocketError errorCode;
6975 objectsToPin = new GCHandle[buffers.Length];
6976 for (int i = 0; i < buffers.Length; ++i)
6978 objectsToPin[i] = GCHandle.Alloc(buffers[i].Buffer, GCHandleType.Pinned);
6979 WSABuffers[i].Length = buffers[i].Size;
6980 WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffers[i].Buffer, buffers[i].Offset);
6983 // This can throw ObjectDisposedException.
6984 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend_Blocking(
6985 m_Handle.DangerousGetHandle(),
6988 out bytesTransferred,
6990 SafeNativeOverlapped.Zero,
6993 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::MultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString());
6997 if (objectsToPin != null)
6998 for (int i = 0; i < objectsToPin.Length; ++i)
6999 if (objectsToPin[i].IsAllocated)
7000 objectsToPin[i].Free();
7003 if (errorCode!=SocketError.Success) {
7004 SocketException socketException = new SocketException();
7005 UpdateStatusAfterSocketError(socketException);
7006 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "MultipleSend", socketException);
7007 throw socketException;
7010 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "MultipleSend", "");
7014 private static void DnsCallback(IAsyncResult result){
7015 if (result.CompletedSynchronously)
7018 bool invokeCallback = false;
7020 MultipleAddressConnectAsyncResult context = (MultipleAddressConnectAsyncResult) result.AsyncState;
7023 invokeCallback = DoDnsCallback(result, context);
7025 catch (Exception exception)
7027 context.InvokeCallback(exception);
7030 // Invoke the callback outside of the try block so we don't catch user Exceptions
7033 context.InvokeCallback();
7037 private static bool DoDnsCallback(IAsyncResult result, MultipleAddressConnectAsyncResult context)
7039 IPAddress[] addresses = Dns.EndGetHostAddresses(result);
7040 context.addresses = addresses;
7041 return DoMultipleAddressConnectCallback(PostOneBeginConnect(context), context);
7044 private class MultipleAddressConnectAsyncResult : ContextAwareResult
7046 internal MultipleAddressConnectAsyncResult(IPAddress[] addresses, int port, Socket socket, object myState, AsyncCallback myCallBack) :
7047 base(socket, myState, myCallBack)
7049 this.addresses = addresses;
7051 this.socket = socket;
7054 internal Socket socket; // Keep this member just to avoid all the casting.
7055 internal IPAddress[] addresses;
7058 internal Exception lastException;
7060 internal EndPoint RemoteEndPoint {
7062 if (addresses != null && index > 0 && index < addresses.Length) {
7063 return new IPEndPoint(addresses[index], port);
7071 private static object PostOneBeginConnect(MultipleAddressConnectAsyncResult context)
7073 IPAddress currentAddressSnapshot = context.addresses[context.index];
7075 if (!context.socket.CanTryAddressFamily(currentAddressSnapshot.AddressFamily))
7077 return context.lastException != null ? context.lastException : new ArgumentException(SR.GetString(SR.net_invalidAddressList), "context");
7082 EndPoint endPoint = new IPEndPoint(currentAddressSnapshot, context.port);
7083 // MSRC 11081 - Do the necessary security demand
7084 context.socket.CheckCacheRemote(ref endPoint, true);
7086 IAsyncResult connectResult = context.socket.UnsafeBeginConnect(endPoint,
7087 new AsyncCallback(MultipleAddressConnectCallback), context);
7089 if (connectResult.CompletedSynchronously)
7091 return connectResult;
7094 catch (Exception exception)
7096 if (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException)
7105 private static void MultipleAddressConnectCallback(IAsyncResult result)
7107 if (result.CompletedSynchronously)
7110 bool invokeCallback = false;
7112 MultipleAddressConnectAsyncResult context = (MultipleAddressConnectAsyncResult) result.AsyncState;
7115 invokeCallback = DoMultipleAddressConnectCallback(result, context);
7117 catch (Exception exception)
7119 context.InvokeCallback(exception);
7122 // Invoke the callback outside of the try block so we don't catch user Exceptions
7125 context.InvokeCallback();
7129 // This is like a regular async callback worker, except the result can be an exception. This is a useful pattern when
7130 // processing should continue whether or not an async step failed.
7131 private static bool DoMultipleAddressConnectCallback(object result, MultipleAddressConnectAsyncResult context)
7133 while (result != null)
7135 Exception ex = result as Exception;
7140 context.socket.EndConnect((IAsyncResult) result);
7142 catch (Exception exception)
7150 // Don't invoke the callback from here, because we're probably inside
7151 // a catch-all block that would eat exceptions from the callback.
7152 // Instead tell our caller to invoke the callback outside of its catchall.
7157 if (++context.index >= context.addresses.Length)
7160 context.lastException = ex;
7161 result = PostOneBeginConnect(context);
7165 // Don't invoke the callback at all, because we've posted another async connection attempt
7170 internal IAsyncResult BeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state) {
7171 // Set up the async result and start the flow.
7172 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
7173 asyncResult.StartPostingAsyncOp(false);
7176 DoBeginMultipleSend(buffers, socketFlags, asyncResult);
7178 // Finish it up (capture, complete).
7179 asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache);
7183 internal IAsyncResult UnsafeBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
7185 // Unsafe - don't flow.
7186 OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
7187 DoBeginMultipleSend(buffers, socketFlags, asyncResult);
7191 private void DoBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult)
7193 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginMultipleSend", "");
7195 throw new ObjectDisposedException(this.GetType().FullName);
7198 // parameter validation
7200 GlobalLog.Assert(buffers != null, "Socket#{0}::DoBeginMultipleSend()|buffers == null", ValidationHelper.HashString(this));
7201 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginMultipleSend() buffers.Length:" + buffers.Length.ToString());
7203 // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to
7204 // avoid a Socket leak in case of error.
7205 SocketError errorCode = SocketError.SocketError;
7208 // Set up asyncResult for overlapped WSASend.
7209 // This call will use completion ports on WinNT and Overlapped IO on Win9x.
7210 asyncResult.SetUnmanagedStructures(buffers, ref Caches.SendOverlappedCache);
7212 // This can throw ObjectDisposedException.
7213 int bytesTransferred;
7214 errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend(
7216 asyncResult.m_WSABuffers,
7217 asyncResult.m_WSABuffers.Length,
7218 out bytesTransferred,
7220 asyncResult.OverlappedHandle,
7223 if (errorCode!=SocketError.Success) {
7224 errorCode = (SocketError)Marshal.GetLastWin32Error();
7226 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginMultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
7230 errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
7234 // if the asynchronous native call fails synchronously
7235 // we'll throw a SocketException
7237 if (errorCode!=SocketError.Success) {
7239 // update our internal state after this socket error and throw
7241 asyncResult.ExtractCache(ref Caches.SendOverlappedCache);
7242 SocketException socketException = new SocketException(errorCode);
7243 UpdateStatusAfterSocketError(socketException);
7244 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginMultipleSend", socketException);
7245 throw socketException;
7247 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginMultipleSend", asyncResult);
7250 internal int EndMultipleSend(IAsyncResult asyncResult) {
7251 if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "EndMultipleSend", asyncResult);
7253 // parameter validation
7255 GlobalLog.Assert(asyncResult != null, "Socket#{0}::EndMultipleSend()|asyncResult == null", ValidationHelper.HashString(this));
7257 OverlappedAsyncResult castedAsyncResult = asyncResult as OverlappedAsyncResult;
7259 GlobalLog.Assert(castedAsyncResult != null, "Socket#{0}::EndMultipleSend()|castedAsyncResult == null", ValidationHelper.HashString(this));
7260 GlobalLog.Assert(castedAsyncResult.AsyncObject == this, "Socket#{0}::EndMultipleSend()|castedAsyncResult.AsyncObject != this", ValidationHelper.HashString(this));
7261 GlobalLog.Assert(!castedAsyncResult.EndCalled, "Socket#{0}::EndMultipleSend()|castedAsyncResult.EndCalled", ValidationHelper.HashString(this));
7263 int bytesTransferred = (int)castedAsyncResult.InternalWaitForCompletion();
7264 castedAsyncResult.EndCalled = true;
7265 castedAsyncResult.ExtractCache(ref Caches.SendOverlappedCache);
7267 #if !FEATURE_PAL // perfcounter
7268 if (s_PerfCountersEnabled)
7270 if (bytesTransferred>0) {
7271 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, bytesTransferred);
7272 if (Transport==TransportType.Udp) {
7273 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
7277 #endif //!FEATURE_PAL
7279 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::EndMultipleSend() bytesTransferred:" + bytesTransferred.ToString());
7282 // if the asynchronous native call failed asynchronously
7283 // we'll throw a SocketException
7285 if ((SocketError)castedAsyncResult.ErrorCode!=SocketError.Success) {
7287 // update our internal state after this socket error and throw
7289 SocketException socketException = new SocketException(castedAsyncResult.ErrorCode);
7290 if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "EndMultipleSend", socketException);
7291 throw socketException;
7293 if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "EndMultipleSend", bytesTransferred);
7294 return bytesTransferred;
7298 // CreateAcceptSocket - pulls unmanaged results and assembles them
7299 // into a new Socket object
7301 private Socket CreateAcceptSocket(SafeCloseSocket fd, EndPoint remoteEP, bool needCancelSelect) {
7303 // Internal state of the socket is inherited from listener
7305 Socket socket = new Socket(fd);
7306 return UpdateAcceptSocket(socket,remoteEP, needCancelSelect);
7309 internal Socket UpdateAcceptSocket(Socket socket, EndPoint remoteEP, bool needCancelSelect) {
7311 // Internal state of the socket is inherited from listener
7313 socket.addressFamily = addressFamily;
7314 socket.socketType = socketType;
7315 socket.protocolType = protocolType;
7316 socket.m_RightEndPoint = m_RightEndPoint;
7317 socket.m_RemoteEndPoint = remoteEP;
7319 // the socket is connected
7321 socket.SetToConnected();
7323 // if the socket is returned by an Endb), the socket might have
7324 // inherited the WSAEventSelect() call from the accepting socket.
7325 // we need to cancel this otherwise the socket will be in non-blocking
7326 // mode and we cannot force blocking mode using the ioctlsocket() in
7327 // Socket.set_Blocking(), since it fails returing 10022 as documented in MSDN.
7328 // (note that the m_AsyncEvent event will not be created in this case.
7331 socket.willBlock = willBlock;
7332 if (needCancelSelect) {
7333 socket.UnsetAsyncEventSelect();
7336 // We need to make sure the Socket is in the right blocking state
7337 // even if we don't have to call UnsetAsyncEventSelect
7338 socket.InternalSetBlocking(willBlock);
7347 // SetToConnected - updates the status of the socket to connected
7349 internal void SetToConnected() {
7350 if (m_IsConnected) {
7352 // socket was already connected
7357 // update the status: this socket was indeed connected at
7358 // some point in time update the perf counter as well.
7360 m_IsConnected = true;
7361 m_IsDisconnected = false;
7362 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToConnected() now connected SRC:" + ValidationHelper.ToString(LocalEndPoint) + " DST:" + ValidationHelper.ToString(RemoteEndPoint));
7363 #if !FEATURE_PAL // perfcounter
7364 if (s_PerfCountersEnabled)
7366 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketConnectionsEstablished);
7368 #endif //!FEATURE_PAL
7372 // SetToDisconnected - updates the status of the socket to disconnected
7374 internal void SetToDisconnected() {
7375 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToDisconnected()");
7376 if (!m_IsConnected) {
7378 // socket was already disconnected
7383 // update the status: this socket was indeed disconnected at
7384 // some point in time, clear any async select bits.
7386 m_IsConnected = false;
7387 m_IsDisconnected = true;
7391 // if socket is still alive cancel WSAEventSelect()
7393 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetToDisconnected()");
7395 UnsetAsyncEventSelect();
7400 // UpdateStatusAfterSocketError(socketException) - updates the status of a connected socket
7401 // on which a failure occured. it'll go to winsock and check if the connection
7402 // is still open and if it needs to update our internal state.
7404 internal void UpdateStatusAfterSocketError(SocketException socketException){
7405 UpdateStatusAfterSocketError((SocketError) socketException.NativeErrorCode);
7408 internal void UpdateStatusAfterSocketError(SocketError errorCode)
7411 // if we already know the socket is disconnected
7412 // we don't need to do anything else.
7414 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UpdateStatusAfterSocketError(socketException)");
7415 if (s_LoggingEnabled) Logging.PrintError(Logging.Sockets, this, "UpdateStatusAfterSocketError", errorCode.ToString());
7417 if (m_IsConnected && (m_Handle.IsInvalid || (errorCode != SocketError.WouldBlock &&
7418 errorCode != SocketError.IOPending && errorCode != SocketError.NoBufferSpaceAvailable &&
7419 errorCode != SocketError.TimedOut)))
7423 // the socket is no longer a valid socket
7425 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UpdateStatusAfterSocketError(socketException) Invalidating socket.");
7426 SetToDisconnected();
7432 // Does internal initalization before async winsock
7433 // call to BeginConnect() or BeginAccept().
7435 private void UnsetAsyncEventSelect()
7437 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
7439 RegisteredWaitHandle registeredWait = m_RegisteredWait;
7440 if (registeredWait != null)
7442 m_RegisteredWait = null;
7443 registeredWait.Unregister(null);
7446 SocketError errorCode = SocketError.NotSocket;
7448 errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_Handle, IntPtr.Zero, AsyncEventBits.FdNone);
7452 if (NclUtilities.IsFatal(e))
7454 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect() !!! (ignoring) Exception: " + e.ToString());
7455 GlobalLog.Assert(CleanedUp, "Socket#{0}::UnsetAsyncEventSelect|Got exception and CleanedUp not set.", ValidationHelper.HashString(this));
7459 // May be re-used in future, reset if the event got signalled after registeredWait.Unregister call
7461 if (m_AsyncEvent != null)
7465 m_AsyncEvent.Reset();
7467 catch (ObjectDisposedException) { }
7470 if (errorCode == SocketError.SocketError)
7473 // update our internal state after this socket error
7474 // we won't throw since this is an internal method
7476 UpdateStatusAfterSocketError(errorCode);
7479 // The call to WSAEventSelect will always put us into non-blocking mode.
7480 // Revert back to what the user has requested.
7481 InternalSetBlocking(willBlock);
7483 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::UnsetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
7486 private bool SetAsyncEventSelect(AsyncEventBits blockEventBits)
7488 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "blockEventBits:" + blockEventBits.ToString() + " m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
7489 GlobalLog.Assert(blockEventBits != AsyncEventBits.FdNone, "Socket#{0}::SetAsyncEventSelect|Use UnsetAsyncEventSelect for FdNone.", ValidationHelper.HashString(this));
7490 GlobalLog.Assert(m_BlockEventBits == AsyncEventBits.FdNone || m_BlockEventBits == blockEventBits, "Socket#{0}::SetAsyncEventSelect|Can't change from one active wait to another.", ValidationHelper.HashString(this));
7491 GlobalLog.Assert(m_RegisteredWait == null, "Socket#{0}::SetAsyncEventSelect|Already actively waiting on an op.", ValidationHelper.HashString(this));
7493 // This check is bogus, too late diggin into a historical reason for it.
7494 // Make sure the upper level will fail with ObjectDisposedException
7495 if (m_RegisteredWait != null)
7499 // This will put us into non-blocking mode. Create the event if it isn't, and register a wait.
7501 if (m_AsyncEvent == null)
7503 Interlocked.CompareExchange<ManualResetEvent>(ref m_AsyncEvent, new ManualResetEvent(false), null);
7504 if (s_RegisteredWaitCallback == null)
7505 s_RegisteredWaitCallback = new WaitOrTimerCallback(RegisteredWaitCallback);
7509 // Try to win over Dispose is there is a ----
7511 if (Interlocked.CompareExchange(ref m_IntCleanedUp, 2, 0) != 0)
7513 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect() Already Cleaned up, returning ... ", string.Empty);
7519 m_BlockEventBits = blockEventBits;
7520 m_RegisteredWait = ThreadPool.UnsafeRegisterWaitForSingleObject(m_AsyncEvent, s_RegisteredWaitCallback, this, Timeout.Infinite, true);
7525 // Release dispose if any is waiting
7527 Interlocked.Exchange(ref m_IntCleanedUp, 0);
7530 SocketError errorCode = SocketError.NotSocket;
7532 // issue the native call
7535 errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_Handle, m_AsyncEvent.SafeWaitHandle, blockEventBits);
7539 if (NclUtilities.IsFatal(e))
7541 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect() !!! (converting to ObjectDisposed) Exception :" + e.ToString());
7542 GlobalLog.Assert(CleanedUp, "Socket#{0}::SetAsyncEventSelect|WSAEventSelect got exception and CleanedUp not set.", ValidationHelper.HashString(this));
7545 if (errorCode==SocketError.SocketError) {
7547 // update our internal state after this socket error
7548 // we won't throw since this is an internal method
7550 UpdateStatusAfterSocketError(errorCode);
7554 // the call to WSAEventSelect will put us in non-blocking mode,
7555 // hence we need update internal status
7557 willBlockInternal = false;
7559 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
7560 return errorCode == SocketError.Success;
7563 private static void RegisteredWaitCallback(object state, bool timedOut)
7565 GlobalLog.Enter("Socket#" + ValidationHelper.HashString(state) + "::RegisteredWaitCallback", "m_BlockEventBits:" + ((Socket)state).m_BlockEventBits.ToString());
7567 // GlobalLog.SetThreadSource(ThreadKinds.Worker); Because of change 1077887, need logic to determine thread type here.
7568 using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
7570 Socket me = (Socket)state;
7572 // Interlocked to avoid a race condition with DoBeginConnect
7573 if (Interlocked.Exchange(ref me.m_RegisteredWait, null) != null)
7575 switch (me.m_BlockEventBits)
7577 case AsyncEventBits.FdConnect:
7578 me.ConnectCallback();
7581 case AsyncEventBits.FdAccept:
7582 me.AcceptCallback(null);
7589 GlobalLog.Leave("Socket#" + ValidationHelper.HashString(state) + "::RegisteredWaitCallback", "m_BlockEventBits:" + ((Socket)state).m_BlockEventBits.ToString());
7593 // ValidateBlockingMode - called before synchronous calls to validate
7594 // the fact that we are in blocking mode (not in non-blocking mode) so the
7595 // call will actually be synchronous
7597 private void ValidateBlockingMode() {
7598 if (willBlock && !willBlockInternal) {
7599 throw new InvalidOperationException(SR.GetString(SR.net_invasync));
7605 // This Method binds the Socket Win32 Handle to the ThreadPool's CompletionPort
7606 // (make sure we only bind once per socket)
7608 [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
7609 internal void BindToCompletionPort()
7612 // Check to see if the socket native m_Handle is already
7613 // bound to the ThreadPool's completion port.
7615 if (!m_BoundToThreadPool && !UseOverlappedIO) {
7617 if (!m_BoundToThreadPool) {
7618 #if SOCKETTHREADPOOL
7619 // bind the socket native m_Handle to prototype SocketThreadPool
7620 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BindToCompletionPort() calling SocketThreadPool.BindHandle()");
7621 SocketThreadPool.BindHandle(m_Handle);
7622 m_BoundToThreadPool = true;
7625 // bind the socket native m_Handle to the ThreadPool
7627 GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BindToCompletionPort() calling ThreadPool.BindHandle()");
7631 ThreadPool.BindHandle(m_Handle);
7632 m_BoundToThreadPool = true;
7634 catch (Exception exception)
7636 if (NclUtilities.IsFatal(exception)) throw;
7647 [System.Diagnostics.Conditional("TRAVE")]
7648 internal void DebugMembers() {
7649 GlobalLog.Print("m_Handle:" + m_Handle.DangerousGetHandle().ToString("x") );
7650 GlobalLog.Print("m_IsConnected: " + m_IsConnected);
7657 public bool AcceptAsync(SocketAsyncEventArgs e) {
7661 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "AcceptAsync", "");
7663 // Throw if socket disposed
7665 throw new ObjectDisposedException(GetType().FullName);
7668 // Throw if multiple buffers specified.
7669 if(e.m_BufferList != null) {
7670 throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
7673 // Throw if not bound.
7674 if(m_RightEndPoint == null) {
7675 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
7678 // Throw if not listening.
7680 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
7683 // Handle AcceptSocket property.
7684 if(e.AcceptSocket == null) {
7685 // Accept socket not specified - create it.
7686 e.AcceptSocket = new Socket(addressFamily, socketType, protocolType);
7688 // Validate accept socket for use here.
7689 if(e.AcceptSocket.m_RightEndPoint != null && !e.AcceptSocket.m_IsDisconnected) {
7690 throw new InvalidOperationException(SR.GetString(SR.net_sockets_namedmustnotbebound, "AcceptSocket"));
7694 // Prepare for the native call.
7695 e.StartOperationCommon(this);
7696 e.StartOperationAccept();
7697 BindToCompletionPort();
7699 // Local variables for [....] completion.
7700 int bytesTransferred;
7701 SocketError socketError = SocketError.Success;
7703 // Make the native call.
7707 e.AcceptSocket.m_Handle,
7708 (e.m_PtrSingleBuffer != IntPtr.Zero) ? e.m_PtrSingleBuffer : e.m_PtrAcceptBuffer,
7709 (e.m_PtrSingleBuffer != IntPtr.Zero) ? e.Count - e.m_AcceptAddressBufferCount : 0,
7710 e.m_AcceptAddressBufferCount / 2,
7711 e.m_AcceptAddressBufferCount / 2,
7712 out bytesTransferred,
7713 e.m_PtrNativeOverlapped)) {
7714 socketError = (SocketError)Marshal.GetLastWin32Error();
7717 catch (Exception ex) {
7718 // clear in-use on event arg object
7723 // Handle completion when completion port is not posted.
7724 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
7725 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
7731 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "AcceptAsync", retval);
7738 public bool ConnectAsync(SocketAsyncEventArgs e) {
7742 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ConnectAsync", "");
7744 // Throw if socket disposed
7746 throw new ObjectDisposedException(GetType().FullName);
7749 // Throw if multiple buffers specified.
7750 if(e.m_BufferList != null) {
7751 throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
7754 // Throw if RemoteEndPoint is null.
7755 if(e.RemoteEndPoint == null) {
7756 throw new ArgumentNullException("remoteEP");
7758 // Throw if listening.
7760 throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
7764 // Check permissions for connect and prepare SocketAddress.
7765 EndPoint endPointSnapshot = e.RemoteEndPoint;
7766 DnsEndPoint dnsEP = endPointSnapshot as DnsEndPoint;
7768 if (dnsEP != null) {
7769 if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, "Socket#" + ValidationHelper.HashString(this)
7770 + "::ConnectAsync " + SR.GetString(SR.net_log_socket_connect_dnsendpoint));
7772 if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily)) {
7773 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
7776 MultipleConnectAsync multipleConnectAsync = new SingleSocketMultipleConnectAsync(this, true);
7778 e.StartOperationCommon(this);
7779 e.StartOperationWrapperConnect(multipleConnectAsync);
7781 retval = multipleConnectAsync.StartConnectAsync(e, dnsEP);
7784 // Throw if remote address family doesn't match socket.
7785 if (!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
7786 throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
7789 e.m_SocketAddress = CheckCacheRemote(ref endPointSnapshot, false);
7791 // Do wildcard bind if socket not bound.
7792 if(m_RightEndPoint == null) {
7793 if(endPointSnapshot.AddressFamily == AddressFamily.InterNetwork)
7794 InternalBind(new IPEndPoint(IPAddress.Any, 0));
7796 InternalBind(new IPEndPoint(IPAddress.IPv6Any, 0));
7799 // Save the old RightEndPoint and prep new RightEndPoint.
7800 EndPoint oldEndPoint = m_RightEndPoint;
7801 if(m_RightEndPoint == null) {
7802 m_RightEndPoint = endPointSnapshot;
7805 // Prepare for the native call.
7806 e.StartOperationCommon(this);
7807 e.StartOperationConnect();
7808 BindToCompletionPort();
7811 // Make the native call.
7812 int bytesTransferred;
7813 SocketError socketError = SocketError.Success;
7817 e.m_PtrSocketAddressBuffer,
7818 e.m_SocketAddress.m_Size,
7819 e.m_PtrSingleBuffer,
7821 out bytesTransferred,
7822 e.m_PtrNativeOverlapped)) {
7823 socketError = (SocketError)Marshal.GetLastWin32Error();
7826 catch (Exception ex) {
7827 m_RightEndPoint = oldEndPoint;
7828 // clear in-use on event arg object
7833 // Handle failure where completion port is not posted.
7834 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
7835 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
7842 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ConnectAsync", retval);
7847 public static bool ConnectAsync(SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e) {
7851 if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, null, "ConnectAsync", "");
7853 // Throw if multiple buffers specified.
7854 if (e.m_BufferList != null) {
7855 throw new ArgumentException(SR.GetString(SR.net_multibuffernotsupported), "BufferList");
7858 // Throw if RemoteEndPoint is null.
7859 if (e.RemoteEndPoint == null) {
7860 throw new ArgumentNullException("remoteEP");
7863 EndPoint endPointSnapshot = e.RemoteEndPoint;
7864 DnsEndPoint dnsEP = endPointSnapshot as DnsEndPoint;
7866 if (dnsEP != null) {
7867 Socket attemptSocket = null;
7868 MultipleConnectAsync multipleConnectAsync = null;
7869 if (dnsEP.AddressFamily == AddressFamily.Unspecified) {
7870 multipleConnectAsync = new MultipleSocketMultipleConnectAsync(socketType, protocolType);
7872 attemptSocket = new Socket(dnsEP.AddressFamily, socketType, protocolType);
7873 multipleConnectAsync = new SingleSocketMultipleConnectAsync(attemptSocket, false);
7876 e.StartOperationCommon(attemptSocket);
7877 e.StartOperationWrapperConnect(multipleConnectAsync);
7879 retval = multipleConnectAsync.StartConnectAsync(e, dnsEP);
7881 Socket attemptSocket = new Socket(endPointSnapshot.AddressFamily, socketType, protocolType);
7882 retval = attemptSocket.ConnectAsync(e);
7885 if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, null, "ConnectAsync", retval);
7890 public static void CancelConnectAsync(SocketAsyncEventArgs e) {
7893 throw new ArgumentNullException("e");
7895 e.CancelConnectAsync();
7901 public bool DisconnectAsync(SocketAsyncEventArgs e) {
7905 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "DisconnectAsync", "");
7907 // Throw if socket disposed
7909 throw new ObjectDisposedException(GetType().FullName);
7912 // Prepare for the native call.
7913 e.StartOperationCommon(this);
7914 e.StartOperationDisconnect();
7915 BindToCompletionPort();
7917 // Make the native call.
7918 SocketError socketError = SocketError.Success;
7922 e.m_PtrNativeOverlapped,
7923 (int)(e.DisconnectReuseSocket ? TransmitFileOptions.ReuseSocket : 0),
7925 socketError = (SocketError)Marshal.GetLastWin32Error();
7928 catch(Exception ex) {
7929 // clear in-use on event arg object
7934 // Handle completion when completion port is not posted.
7935 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
7936 e.FinishOperationSyncFailure(socketError, 0, SocketFlags.None);
7942 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "DisconnectAsync", retval);
7950 public bool ReceiveAsync(SocketAsyncEventArgs e) {
7954 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveAsync", "");
7956 // Throw if socket disposed
7958 throw new ObjectDisposedException(GetType().FullName);
7961 // Prepare for the native call.
7962 e.StartOperationCommon(this);
7963 e.StartOperationReceive();
7964 BindToCompletionPort();
7966 // Local vars for [....] completion of native call.
7967 SocketFlags flags = e.m_SocketFlags;
7968 int bytesTransferred;
7969 SocketError socketError;
7971 // Wrap native methods with try/catch so event args object can be cleaned up
7973 if(e.m_Buffer != null) {
7974 // Single buffer case
7975 socketError = UnsafeNclNativeMethods.OSSOCK.WSARecv(
7979 out bytesTransferred,
7981 e.m_PtrNativeOverlapped,
7984 // Multi buffer case
7985 socketError = UnsafeNclNativeMethods.OSSOCK.WSARecv(
7988 e.m_WSABufferArray.Length,
7989 out bytesTransferred,
7991 e.m_PtrNativeOverlapped,
7995 catch(Exception ex) {
7996 // clear in-use on event arg object
8001 // Native method emits single catch-all error code when error occurs.
8002 // Must get Win32 error for specific error code.
8003 if(socketError != SocketError.Success) {
8004 socketError = (SocketError)Marshal.GetLastWin32Error();
8007 // Handle completion when completion port is not posted.
8008 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8009 e.FinishOperationSyncFailure(socketError, bytesTransferred, flags);
8015 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveAsync", retval);
8022 public bool ReceiveFromAsync(SocketAsyncEventArgs e) {
8026 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveFromAsync", "");
8028 // Throw if socket disposed
8030 throw new ObjectDisposedException(GetType().FullName);
8033 // Throw if remote endpoint property is null.
8034 if(e.RemoteEndPoint == null) {
8035 throw new ArgumentNullException("RemoteEndPoint");
8038 if(!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
8039 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
8040 e.RemoteEndPoint.AddressFamily, addressFamily), "RemoteEndPoint");
8043 // We don't do a CAS demand here because the contents of remoteEP aren't used by
8044 // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
8045 // with the right address family
8046 EndPoint endPointSnapshot = e.RemoteEndPoint;
8047 e.m_SocketAddress = SnapshotAndSerialize(ref endPointSnapshot);
8048 // DualMode may have updated the endPointSnapshot, and it has to have the same AddressFamily as
8049 // e.m_SocketAddres for Create to work later.
8050 e.RemoteEndPoint = endPointSnapshot;
8052 // Prepare for the native call.
8053 e.StartOperationCommon(this);
8054 e.StartOperationReceiveFrom();
8055 BindToCompletionPort();
8057 // Make the native call.
8058 SocketFlags flags = e.m_SocketFlags;
8059 int bytesTransferred;
8060 SocketError socketError;
8063 if(e.m_Buffer != null) {
8064 socketError = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
8068 out bytesTransferred,
8070 e.m_PtrSocketAddressBuffer,
8071 e.m_PtrSocketAddressBufferSize,
8072 e.m_PtrNativeOverlapped,
8075 socketError = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
8078 e.m_WSABufferArray.Length,
8079 out bytesTransferred,
8081 e.m_PtrSocketAddressBuffer,
8082 e.m_PtrSocketAddressBufferSize,
8083 e.m_PtrNativeOverlapped,
8087 catch(Exception ex) {
8088 // clear in-use on event arg object
8093 // Native method emits single catch-all error code when error occurs.
8094 // Must get Win32 error for specific error code.
8095 if(socketError != SocketError.Success) {
8096 socketError = (SocketError)Marshal.GetLastWin32Error();
8099 // Handle completion when completion port is not posted.
8100 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8101 e.FinishOperationSyncFailure(socketError, bytesTransferred, flags);
8107 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveFromAsync", retval);
8112 // ReceiveMessageFromAsync
8114 public bool ReceiveMessageFromAsync(SocketAsyncEventArgs e) {
8118 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "ReceiveMessageFromAsync", "");
8120 // Throw if socket disposed
8122 throw new ObjectDisposedException(GetType().FullName);
8125 // Throw if remote endpoint property is null.
8126 if(e.RemoteEndPoint == null) {
8127 throw new ArgumentNullException("RemoteEndPoint");
8130 if(!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) {
8131 throw new ArgumentException(SR.GetString(SR.net_InvalidEndPointAddressFamily,
8132 e.RemoteEndPoint.AddressFamily, addressFamily), "RemoteEndPoint");
8135 // We don't do a CAS demand here because the contents of remoteEP aren't used by
8136 // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
8137 // with the right address family
8138 EndPoint endPointSnapshot = e.RemoteEndPoint;
8139 e.m_SocketAddress = SnapshotAndSerialize(ref endPointSnapshot);
8140 // DualMode may have updated the endPointSnapshot, and it has to have the same AddressFamily as
8141 // e.m_SocketAddres for Create to work later.
8142 e.RemoteEndPoint = endPointSnapshot;
8144 SetReceivingPacketInformation();
8146 // Prepare for the native call.
8147 e.StartOperationCommon(this);
8148 e.StartOperationReceiveMessageFrom();
8149 BindToCompletionPort();
8152 // Make the native call.
8153 int bytesTransferred;
8154 SocketError socketError;
8157 socketError = WSARecvMsg(
8159 e.m_PtrWSAMessageBuffer,
8160 out bytesTransferred,
8161 e.m_PtrNativeOverlapped,
8164 catch(Exception ex) {
8165 // clear in-use on event arg object
8170 // Native method emits single catch-all error code when error occurs.
8171 // Must get Win32 error for specific error code.
8172 if(socketError != SocketError.Success) {
8173 socketError = (SocketError)Marshal.GetLastWin32Error();
8176 // Handle completion when completion port is not posted.
8177 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8178 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
8184 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "ReceiveMessageFromAsync", retval);
8192 public bool SendAsync(SocketAsyncEventArgs e) {
8196 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendAsync", "");
8198 // Throw if socket disposed
8200 throw new ObjectDisposedException(GetType().FullName);
8203 // Prepare for the native call.
8204 e.StartOperationCommon(this);
8205 e.StartOperationSend();
8206 BindToCompletionPort();
8209 // Local vars for [....] completion of native call.
8210 int bytesTransferred;
8211 SocketError socketError;
8213 // Wrap native methods with try/catch so event args object can be cleaned up
8215 if(e.m_Buffer != null) {
8216 // Single buffer case
8217 socketError = UnsafeNclNativeMethods.OSSOCK.WSASend(
8221 out bytesTransferred,
8223 e.m_PtrNativeOverlapped,
8226 // Multi buffer case
8227 socketError = UnsafeNclNativeMethods.OSSOCK.WSASend(
8230 e.m_WSABufferArray.Length,
8231 out bytesTransferred,
8233 e.m_PtrNativeOverlapped,
8237 catch(Exception ex) {
8238 // clear in-use on event arg object
8243 // Native method emits single catch-all error code when error occurs.
8244 // Must get Win32 error for specific error code.
8245 if(socketError != SocketError.Success) {
8246 socketError = (SocketError)Marshal.GetLastWin32Error();
8249 // Handle completion when completion port is not posted.
8250 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8251 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
8257 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendAsync", retval);
8265 public bool SendPacketsAsync(SocketAsyncEventArgs e) {
8269 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendPacketsAsync", "");
8271 // Throw if socket disposed
8273 throw new ObjectDisposedException(GetType().FullName);
8276 // Throw if not connected.
8278 throw new NotSupportedException(SR.GetString(SR.net_notconnected));
8281 // Prepare for the native call.
8282 e.StartOperationCommon(this);
8283 e.StartOperationSendPackets();
8284 BindToCompletionPort();
8286 // Make the native call.
8287 SocketError socketError;
8290 if (e.m_SendPacketsDescriptor.Length > 0) {
8292 result = TransmitPackets(
8294 e.m_PtrSendPacketsDescriptor,
8295 e.m_SendPacketsDescriptor.Length,
8296 e.m_SendPacketsSendSize,
8297 e.m_PtrNativeOverlapped,
8298 e.m_SendPacketsFlags);
8301 // clear in-use on event arg object
8307 socketError = (SocketError)Marshal.GetLastWin32Error();
8309 socketError = SocketError.Success;
8312 // Handle completion when completion port is not posted.
8313 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8314 e.FinishOperationSyncFailure(socketError, 0, SocketFlags.None);
8321 // No buffers or files to send.
8322 e.FinishOperationSuccess(SocketError.Success, 0, SocketFlags.None);
8327 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "SendPacketsAsync", retval);
8335 public bool SendToAsync(SocketAsyncEventArgs e) {
8339 if(s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "SendToAsync", "");
8341 // Throw if socket disposed
8343 throw new ObjectDisposedException(GetType().FullName);
8346 // Throw if remote endpoint property is null.
8347 if(e.RemoteEndPoint == null) {
8348 throw new ArgumentNullException("RemoteEndPoint");
8351 // Check permissions for connect and prepare SocketAddress
8352 EndPoint endPointSnapshot = e.RemoteEndPoint;
8353 e.m_SocketAddress = CheckCacheRemote(ref endPointSnapshot, false);
8355 // Prepare for the native call.
8356 e.StartOperationCommon(this);
8357 e.StartOperationSendTo();
8358 BindToCompletionPort();
8360 // Make the native call.
8361 int bytesTransferred;
8362 SocketError socketError;
8364 // Wrap native methods with try/catch so event args object can be cleaned up
8366 if(e.m_Buffer != null) {
8367 // Single buffer case
8368 socketError = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
8372 out bytesTransferred,
8374 e.m_PtrSocketAddressBuffer,
8375 e.m_SocketAddress.m_Size,
8376 e.m_PtrNativeOverlapped,
8379 socketError = UnsafeNclNativeMethods.OSSOCK.WSASendTo(
8382 e.m_WSABufferArray.Length,
8383 out bytesTransferred,
8385 e.m_PtrSocketAddressBuffer,
8386 e.m_SocketAddress.m_Size,
8387 e.m_PtrNativeOverlapped,
8393 catch(Exception ex) {
8394 // clear in-use on event arg object
8399 // Native method emits single catch-all error code when error occurs.
8400 // Must get Win32 error for specific error code.
8401 if(socketError != SocketError.Success) {
8402 socketError = (SocketError)Marshal.GetLastWin32Error();
8405 // Handle completion when completion port is not posted.
8406 if(socketError != SocketError.Success && socketError != SocketError.IOPending) {
8407 e.FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
8413 if(s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "SendToAsync", retval);
8418 } // end of class Socket
8421 internal class ConnectAsyncResult:ContextAwareResult{
8422 private EndPoint m_EndPoint;
8423 internal ConnectAsyncResult(object myObject, EndPoint endPoint, object myState, AsyncCallback myCallBack):base(myObject, myState, myCallBack) {
8424 m_EndPoint = endPoint;
8426 internal EndPoint RemoteEndPoint {
8427 get { return m_EndPoint; }
8431 internal class AcceptAsyncResult:ContextAwareResult{
8432 internal AcceptAsyncResult(object myObject, object myState, AsyncCallback myCallBack):base(myObject, myState, myCallBack) {
8437 public enum SocketAsyncOperation {
8450 // class that wraps the semantics of a winsock TRANSMIT_PACKETS_ELEMENTS struct
8451 public class SendPacketsElement {
8452 internal string m_FilePath;
8453 internal byte [] m_Buffer;
8454 internal int m_Offset;
8455 internal int m_Count;
8459 internal UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags m_Flags;
8462 // hide default constructor
8463 private SendPacketsElement() {}
8465 // constructors for file elements
8466 public SendPacketsElement(string filepath) :
8467 this(filepath, 0, 0, false) { }
8469 public SendPacketsElement(string filepath, int offset, int count) :
8470 this(filepath, offset, count, false) { }
8472 public SendPacketsElement(string filepath, int offset, int count, bool endOfPacket) {
8473 // We will validate if the file exists on send
8474 if (filepath == null) {
8475 throw new ArgumentNullException("filepath");
8477 // The native API will validate the file length on send
8479 throw new ArgumentOutOfRangeException("offset");
8482 throw new ArgumentOutOfRangeException("count");
8484 Contract.EndContractBlock();
8487 Initialize(filepath, null, offset, count, /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.File,*/
8490 Initialize(filepath, null, offset, count, UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.File,
8495 // constructors for buffer elements
8496 public SendPacketsElement(byte[] buffer) :
8497 this(buffer, 0, (buffer != null ? buffer.Length : 0), false) { }
8499 public SendPacketsElement(byte[] buffer, int offset, int count) :
8500 this(buffer, offset, count, false) { }
8502 public SendPacketsElement(byte[] buffer, int offset, int count, bool endOfPacket) {
8503 if (buffer == null) {
8504 throw new ArgumentNullException("buffer");
8506 if (offset < 0 || offset > buffer.Length) {
8507 throw new ArgumentOutOfRangeException("offset");
8509 if (count < 0 || count > (buffer.Length - offset)) {
8510 throw new ArgumentOutOfRangeException("count");
8512 Contract.EndContractBlock();
8515 Initialize(null, buffer, offset, count, /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.Memory,*/
8518 Initialize(null, buffer, offset, count, UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.Memory,
8523 private void Initialize(string filePath, byte[] buffer, int offset, int count,
8524 /*UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags flags,*/ bool endOfPacket) {
8526 m_FilePath = filePath;
8531 m_endOfPacket = endOfPacket;
8535 m_Flags |= UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.EndOfPacket;
8540 // Filename property
8541 public string FilePath {
8542 get { return m_FilePath; }
8546 public byte[] Buffer {
8547 get { return m_Buffer; }
8552 get { return m_Count; }
8557 get { return m_Offset; }
8560 // EndOfPacket property
8561 public bool EndOfPacket {
8564 return m_endOfPacket;
8566 return (m_Flags & UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElementFlags.EndOfPacket) != 0;
8572 #region designer support for System.Windows.dll
8573 //introduced for supporting design-time loading of System.Windows.dll
8574 [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
8575 [EditorBrowsable(EditorBrowsableState.Never)]
8576 public enum SocketClientAccessPolicyProtocol
8584 public class SocketAsyncEventArgs : EventArgs, IDisposable {
8586 // Struct sizes needed for some custom marshalling.
8587 internal static readonly int s_ControlDataSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.ControlData));
8588 internal static readonly int s_ControlDataIPv6Size = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6));
8589 internal static readonly int s_WSAMsgSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.WSAMsg));
8591 // AcceptSocket property variables.
8592 internal Socket m_AcceptSocket;
8593 private Socket m_ConnectSocket;
8595 // Buffer,Offset,Count property variables.
8596 internal byte[] m_Buffer;
8597 internal WSABuffer m_WSABuffer;
8598 internal IntPtr m_PtrSingleBuffer;
8599 internal int m_Count;
8600 internal int m_Offset;
8602 // BufferList property variables.
8603 internal IList<ArraySegment<byte> > m_BufferList;
8604 private bool m_BufferListChanged;
8605 internal WSABuffer[] m_WSABufferArray;
8607 // BytesTransferred property variables.
8608 private int m_BytesTransferred;
8610 // Completed event property variables.
8611 private event EventHandler<SocketAsyncEventArgs> m_Completed;
8612 private bool m_CompletedChanged;
8614 // DisconnectReuseSocket propery variables.
8615 private bool m_DisconnectReuseSocket;
8617 // LastOperation property variables.
8618 private SocketAsyncOperation m_CompletedOperation;
8620 // ReceiveMessageFromPacketInfo property variables.
8621 private IPPacketInformation m_ReceiveMessageFromPacketInfo;
8623 // RemoteEndPoint property variables.
8624 private EndPoint m_RemoteEndPoint;
8626 // SendPacketsFlags property variable.
8627 internal TransmitFileOptions m_SendPacketsFlags;
8629 // SendPacketsSendSize property variable.
8630 internal int m_SendPacketsSendSize;
8632 // SendPacketsElements property variables.
8633 internal SendPacketsElement[] m_SendPacketsElements;
8634 private SendPacketsElement[] m_SendPacketsElementsInternal;
8635 internal int m_SendPacketsElementsFileCount;
8636 internal int m_SendPacketsElementsBufferCount;
8638 // SocketError property variables.
8639 private SocketError m_SocketError;
8640 private Exception m_ConnectByNameError;
8642 // SocketFlags property variables.
8643 internal SocketFlags m_SocketFlags;
8645 // UserToken property variables.
8646 private object m_UserToken;
8648 // Internal buffer for AcceptEx when Buffer not supplied.
8649 internal byte[] m_AcceptBuffer;
8650 internal int m_AcceptAddressBufferCount;
8651 internal IntPtr m_PtrAcceptBuffer;
8653 // Internal SocketAddress buffer
8654 internal SocketAddress m_SocketAddress;
8655 private GCHandle m_SocketAddressGCHandle;
8656 private SocketAddress m_PinnedSocketAddress;
8657 internal IntPtr m_PtrSocketAddressBuffer;
8658 internal IntPtr m_PtrSocketAddressBufferSize;
8660 // Internal buffers for WSARecvMsg
8661 private byte[] m_WSAMessageBuffer;
8662 private GCHandle m_WSAMessageBufferGCHandle;
8663 internal IntPtr m_PtrWSAMessageBuffer;
8664 private byte[] m_ControlBuffer;
8665 private GCHandle m_ControlBufferGCHandle;
8666 internal IntPtr m_PtrControlBuffer;
8667 private WSABuffer[] m_WSARecvMsgWSABufferArray;
8668 private GCHandle m_WSARecvMsgWSABufferArrayGCHandle;
8669 private IntPtr m_PtrWSARecvMsgWSABufferArray;
8671 // Internal variables for SendPackets
8672 internal FileStream[] m_SendPacketsFileStreams;
8673 internal SafeHandle[] m_SendPacketsFileHandles;
8674 internal UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElement[] m_SendPacketsDescriptor;
8675 internal IntPtr m_PtrSendPacketsDescriptor;
8677 // Misc state variables.
8678 private ExecutionContext m_Context;
8679 private ExecutionContext m_ContextCopy;
8680 private ContextCallback m_ExecutionCallback;
8681 private Socket m_CurrentSocket;
8682 private bool m_DisposeCalled;
8684 // Controls thread safety via Interlocked
8685 private const int Configuring = -1;
8686 private const int Free = 0;
8687 private const int InProgress = 1;
8688 private const int Disposed = 2;
8689 private int m_Operating;
8691 // Overlapped object related variables.
8692 internal SafeNativeOverlapped m_PtrNativeOverlapped;
8693 private Overlapped m_Overlapped;
8694 private object[] m_ObjectsToPin;
8695 private enum PinState {
8703 private PinState m_PinState;
8704 private byte[] m_PinnedAcceptBuffer;
8705 private byte[] m_PinnedSingleBuffer;
8706 private int m_PinnedSingleBufferOffset;
8707 private int m_PinnedSingleBufferCount;
8709 private MultipleConnectAsync m_MultipleConnect;
8711 private static bool s_LoggingEnabled = Logging.On;
8713 #region designer support for System.Windows.dll
8714 //introduced for supporting design-time loading of System.Windows.dll
8715 [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
8716 [EditorBrowsable(EditorBrowsableState.Never)]
8717 public SocketClientAccessPolicyProtocol SocketClientAccessPolicyProtocol { get; set; }
8721 // Public constructor.
8722 public SocketAsyncEventArgs() {
8724 // Create callback delegate
8725 m_ExecutionCallback = new ContextCallback(ExecutionCallback);
8727 // Zero tells TransmitPackets to select a default send size.
8728 m_SendPacketsSendSize = 0;
8731 // AcceptSocket property.
8732 public Socket AcceptSocket {
8733 get { return m_AcceptSocket; }
8734 set { m_AcceptSocket = value; }
8737 public Socket ConnectSocket {
8738 get { return m_ConnectSocket; }
8742 public byte[] Buffer {
8743 get { return m_Buffer; }
8748 get { return m_Offset; }
8753 get { return m_Count; }
8756 // BufferList property.
8757 // Mutually exclusive with Buffer.
8758 // Setting this property with an existing non-null Buffer will throw.
8759 public IList<ArraySegment<byte> > BufferList {
8760 get { return m_BufferList; }
8764 if(value != null && m_Buffer != null) {
8765 throw new ArgumentException(SR.GetString(SR.net_ambiguousbuffers, "Buffer"));
8767 m_BufferList = value;
8768 m_BufferListChanged = true;
8769 CheckPinMultipleBuffers();
8776 // BytesTransferred property.
8777 public int BytesTransferred {
8778 get { return m_BytesTransferred; }
8781 // Completed property.
8782 public event EventHandler<SocketAsyncEventArgs> Completed {
8784 m_Completed += value;
8785 m_CompletedChanged = true;
8788 m_Completed -= value;
8789 m_CompletedChanged = true;
8793 // Method to raise Completed event.
8794 protected virtual void OnCompleted(SocketAsyncEventArgs e) {
8795 EventHandler<SocketAsyncEventArgs> handler = m_Completed;
8796 if(handler != null) {
8797 handler(e.m_CurrentSocket, e);
8801 // DisconnectResuseSocket property.
8802 public bool DisconnectReuseSocket {
8803 get { return m_DisconnectReuseSocket; }
8804 set { m_DisconnectReuseSocket = value; }
8807 // LastOperation property.
8808 public SocketAsyncOperation LastOperation {
8809 get { return m_CompletedOperation; }
8812 // ReceiveMessageFromPacketInfo property.
8813 public IPPacketInformation ReceiveMessageFromPacketInfo {
8814 get { return m_ReceiveMessageFromPacketInfo; }
8817 // RemoteEndPoint property.
8818 public EndPoint RemoteEndPoint {
8819 get { return m_RemoteEndPoint; }
8820 set { m_RemoteEndPoint = value; }
8823 // SendPacketsElements property.
8824 public SendPacketsElement[] SendPacketsElements {
8825 get { return m_SendPacketsElements; }
8829 m_SendPacketsElements = value;
8830 m_SendPacketsElementsInternal = null;
8837 // SendPacketsFlags property.
8838 public TransmitFileOptions SendPacketsFlags {
8839 get { return m_SendPacketsFlags; }
8840 set { m_SendPacketsFlags = value; }
8843 // SendPacketsSendSize property.
8844 public int SendPacketsSendSize {
8845 get { return m_SendPacketsSendSize; }
8846 set { m_SendPacketsSendSize = value; }
8849 // SocketError property.
8850 public SocketError SocketError {
8851 get { return m_SocketError; }
8852 set { m_SocketError = value; }
8855 public Exception ConnectByNameError {
8856 get { return m_ConnectByNameError; }
8859 // SocketFlags property.
8860 public SocketFlags SocketFlags {
8861 get { return m_SocketFlags; }
8862 set { m_SocketFlags = value; }
8865 // UserToken property.
8866 public object UserToken {
8867 get { return m_UserToken; }
8868 set { m_UserToken = value; }
8871 // SetBuffer(byte[], int, int) method.
8872 public void SetBuffer(byte [] buffer, int offset, int count) {
8873 SetBufferInternal(buffer, offset, count);
8876 // SetBuffer(int, int) method.
8877 public void SetBuffer(int offset, int count) {
8878 SetBufferInternal(m_Buffer, offset, count);
8881 private void SetBufferInternal(byte [] buffer, int offset, int count) {
8884 if (buffer == null) {
8886 // Clear out existing buffer.
8892 // Can't have both Buffer and BufferList
8893 if(m_BufferList != null) {
8894 throw new ArgumentException(SR.GetString(SR.net_ambiguousbuffers, "BufferList"));
8896 // Offset and count can't be negative and the
8897 // combination must be in bounds of the array.
8898 if (offset < 0 || offset > buffer.Length) {
8899 throw new ArgumentOutOfRangeException("offset");
8901 if (count < 0 || count > (buffer.Length - offset)) {
8902 throw new ArgumentOutOfRangeException("count");
8909 // Pin new or unpin old buffer.
8910 CheckPinSingleBuffer(true);
8918 // Method to update internal state after [....] or async completion.
8919 internal void SetResults(SocketError socketError, int bytesTransferred, SocketFlags flags) {
8920 m_SocketError = socketError;
8921 m_ConnectByNameError = null;
8922 m_BytesTransferred = bytesTransferred;
8923 m_SocketFlags = flags;
8926 internal void SetResults(Exception exception, int bytesTransferred, SocketFlags flags) {
8927 m_ConnectByNameError = exception;
8928 m_BytesTransferred = bytesTransferred;
8929 m_SocketFlags = flags;
8931 if (exception == null) {
8932 m_SocketError = SocketError.Success;
8935 SocketException socketException = exception as SocketException;
8936 if (socketException != null) {
8937 m_SocketError = socketException.SocketErrorCode;
8940 m_SocketError = SocketError.SocketError;
8945 // Context callback delegate.
8946 private void ExecutionCallback(object ignored) {
8950 // Method to mark this object as no longer "in-use".
8951 // Will also execute a Dispose deferred because I/O was in progress.
8952 internal void Complete() {
8954 // Mark as not in-use
8957 // Check for deferred Dispose().
8958 // The deferred Dispose is not guaranteed if Dispose is called while an operation is in progress.
8959 // The m_DisposeCalled variable is not managed in a thread-safe manner on purpose for performance.
8960 if (m_DisposeCalled) {
8965 // Dispose call to implement IDisposable.
8966 public void Dispose() {
8968 // Remember that Dispose was called.
8969 m_DisposeCalled = true;
8971 // Check if this object is in-use for an async socket operation.
8972 if(Interlocked.CompareExchange(ref m_Operating, Disposed, Free) != Free) {
8973 // Either already disposed or will be disposed when current operation completes.
8977 // OK to dispose now.
8978 // Free native overlapped data.
8979 FreeOverlapped(false);
8981 // Don't bother finalizing later.
8982 GC.SuppressFinalize(this);
8986 ~SocketAsyncEventArgs() {
8987 FreeOverlapped(true);
8990 // Us a try/Finally to make sure Complete is called when you're done
8991 private void StartConfiguring() {
8992 int status = Interlocked.CompareExchange(ref m_Operating, Configuring, Free);
8993 if (status == InProgress || status == Configuring) {
8994 throw new InvalidOperationException(SR.GetString(SR.net_socketopinprogress));
8996 else if (status == Disposed)
8998 throw new ObjectDisposedException(GetType().FullName);
9002 // Method called to prepare for a native async socket call.
9003 // This method performs the tasks common to all socket operations.
9004 internal void StartOperationCommon(Socket socket) {
9006 // Change status to "in-use".
9007 if(Interlocked.CompareExchange(ref m_Operating, InProgress, Free) != Free) {
9009 // If it was already "in-use" check if Dispose was called.
9010 if(m_DisposeCalled) {
9012 // Dispose was called - throw ObjectDisposed.
9013 throw new ObjectDisposedException(GetType().FullName);
9016 // Only one at a time.
9017 throw new InvalidOperationException(SR.GetString(SR.net_socketopinprogress));
9020 // Prepare execution context for callback.
9022 if (ExecutionContext.IsFlowSuppressed()) {
9024 // Fast path for when flow is suppressed.
9027 m_ContextCopy = null;
9031 // Flow is not suppressed.
9033 // If event delegates have changed or socket has changed
9034 // then discard any existing context.
9036 if (m_CompletedChanged || socket != m_CurrentSocket) {
9038 m_CompletedChanged = false;
9040 m_ContextCopy = null;
9043 // Capture execution context if none already.
9045 if (m_Context == null) {
9046 m_Context = ExecutionContext.Capture();
9049 // If there is an execution context we need a fresh copy for each completion.
9051 if(m_Context != null) {
9052 m_ContextCopy = m_Context.CreateCopy();
9056 // Remember current socket.
9057 m_CurrentSocket = socket;
9060 internal void StartOperationAccept() {
9061 // Remember the operation type.
9062 m_CompletedOperation = SocketAsyncOperation.Accept;
9064 // AcceptEx needs a single buffer with room for two special sockaddr data structures.
9065 // It can also take additional buffer space in front of those special sockaddr
9066 // structures that can be filled in with initial data coming in on a connection.
9068 // First calculate the special AcceptEx address buffer size.
9069 // It is the size of two native sockaddr buffers with 16 extra bytes each.
9070 // The native sockaddr buffers vary by address family so must reference the current socket.
9071 m_AcceptAddressBufferCount = 2 * (m_CurrentSocket.m_RightEndPoint.Serialize().Size + 16);
9073 // If our caller specified a buffer (willing to get received data with the Accept) then
9074 // it needs to be large enough for the two special sockaddr buffers that AcceptEx requires.
9075 // Throw if that buffer is not large enough.
9076 if(m_Buffer != null) {
9078 // Caller specified a buffer - see if it is large enough
9079 if(m_Count < m_AcceptAddressBufferCount) {
9080 throw new ArgumentException(SR.GetString(SR.net_buffercounttoosmall, "Count"));
9082 // Buffer is already pinned.
9086 // Caller didn't specify a buffer so use an internal one.
9087 // See if current internal one is big enough, otherwise create a new one.
9088 if(m_AcceptBuffer == null || m_AcceptBuffer.Length < m_AcceptAddressBufferCount) {
9089 m_AcceptBuffer = new byte[m_AcceptAddressBufferCount];
9091 CheckPinSingleBuffer(false);
9095 internal void StartOperationConnect() {
9096 // Remember the operation type.
9097 m_CompletedOperation = SocketAsyncOperation.Connect;
9098 m_MultipleConnect = null;
9099 m_ConnectSocket = null;
9101 // ConnectEx uses a sockaddr buffer containing he remote address to which to connect.
9102 // It can also optionally take a single buffer of data to send after the connection is complete.
9104 // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
9105 // The optional buffer is pinned using the Overlapped.UnsafePack method that takes a single object to pin.
9107 PinSocketAddressBuffer();
9111 internal void StartOperationWrapperConnect(MultipleConnectAsync args) {
9112 m_CompletedOperation = SocketAsyncOperation.Connect;
9113 m_MultipleConnect = args;
9114 m_ConnectSocket = null;
9117 internal void CancelConnectAsync() {
9118 if (m_Operating == InProgress && m_CompletedOperation == SocketAsyncOperation.Connect) {
9120 if (m_MultipleConnect != null) {
9121 // if a multiple connect is in progress, abort it
9122 m_MultipleConnect.Cancel();
9125 // otherwise we're doing a normal ConnectAsync - cancel it by closing the socket
9126 // m_CurrentSocket will only be null if m_MultipleConnect was set, so we don't have to check
9127 GlobalLog.Assert(m_CurrentSocket != null, "SocketAsyncEventArgs::CancelConnectAsync - CurrentSocket and MultipleConnect both null!");
9128 m_CurrentSocket.Close();
9133 internal void StartOperationDisconnect() {
9134 // Remember the operation type.
9135 m_CompletedOperation = SocketAsyncOperation.Disconnect;
9139 internal void StartOperationReceive() {
9140 // Remember the operation type.
9141 m_CompletedOperation = SocketAsyncOperation.Receive;
9143 // WWSARecv uses a WSABuffer array describing buffers of data to send.
9144 // Single and multiple buffers are handled differently so as to optimize
9145 // performance for the more common single buffer case.
9146 // For a single buffer:
9147 // The Overlapped.UnsafePack method is used that takes a single object to pin.
9148 // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
9149 // For multiple buffers:
9150 // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
9151 // An array to reference the multiple buffer is allocated.
9152 // An array of WSABuffer descriptors is allocated.
9155 internal void StartOperationReceiveFrom() {
9156 // Remember the operation type.
9157 m_CompletedOperation = SocketAsyncOperation.ReceiveFrom;
9159 // WSARecvFrom uses e a WSABuffer array describing buffers in which to
9160 // receive data and from which to send data respectively. Single and multiple buffers
9161 // are handled differently so as to optimize performance for the more common single buffer case.
9162 // For a single buffer:
9163 // The Overlapped.UnsafePack method is used that takes a single object to pin.
9164 // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
9165 // For multiple buffers:
9166 // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
9167 // An array to reference the multiple buffer is allocated.
9168 // An array of WSABuffer descriptors is allocated.
9169 // WSARecvFrom and WSASendTo also uses a sockaddr buffer in which to store the address from which the data was received.
9170 // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
9171 PinSocketAddressBuffer();
9174 internal void StartOperationReceiveMessageFrom() {
9175 // Remember the operation type.
9176 m_CompletedOperation = SocketAsyncOperation.ReceiveMessageFrom;
9178 // WSARecvMsg uses a WSAMsg descriptor.
9179 // The WSAMsg buffer is pinned with a GCHandle to avoid complicating the use of Overlapped.
9180 // WSAMsg contains a pointer to a sockaddr.
9181 // The sockaddr is pinned with a GCHandle to avoid complicating the use of Overlapped.
9182 // WSAMsg contains a pointer to a WSABuffer array describing data buffers.
9183 // WSAMsg also contains a single WSABuffer describing a control buffer.
9185 PinSocketAddressBuffer();
9187 // Create and pin a WSAMessageBuffer if none already.
9188 if(m_WSAMessageBuffer == null) {
9189 m_WSAMessageBuffer = new byte[s_WSAMsgSize];
9190 m_WSAMessageBufferGCHandle = GCHandle.Alloc(m_WSAMessageBuffer, GCHandleType.Pinned);
9191 m_PtrWSAMessageBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSAMessageBuffer, 0);
9194 // Create and pin an appropriately sized control buffer if none already
9195 IPAddress ipAddress = (m_SocketAddress.Family == AddressFamily.InterNetworkV6
9196 ? m_SocketAddress.GetIPAddress() : null);
9197 bool ipv4 = (m_CurrentSocket.AddressFamily == AddressFamily.InterNetwork
9198 || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode
9199 bool ipv6 = m_CurrentSocket.AddressFamily == AddressFamily.InterNetworkV6;
9201 if(ipv4 && (m_ControlBuffer == null || m_ControlBuffer.Length != s_ControlDataSize)) {
9202 if(m_ControlBufferGCHandle.IsAllocated) {
9203 m_ControlBufferGCHandle.Free();
9205 m_ControlBuffer = new byte[s_ControlDataSize];
9206 } else if(ipv6 && (m_ControlBuffer == null || m_ControlBuffer.Length != s_ControlDataIPv6Size)) {
9207 if(m_ControlBufferGCHandle.IsAllocated) {
9208 m_ControlBufferGCHandle.Free();
9210 m_ControlBuffer = new byte[s_ControlDataIPv6Size];
9212 if(!m_ControlBufferGCHandle.IsAllocated) {
9213 m_ControlBufferGCHandle = GCHandle.Alloc(m_ControlBuffer, GCHandleType.Pinned);
9214 m_PtrControlBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_ControlBuffer, 0);
9217 // If single buffer we need a pinned 1 element WSABuffer.
9218 if(m_Buffer != null) {
9219 if(m_WSARecvMsgWSABufferArray == null) {
9220 m_WSARecvMsgWSABufferArray = new WSABuffer[1];
9222 m_WSARecvMsgWSABufferArray[0].Pointer = m_PtrSingleBuffer;
9223 m_WSARecvMsgWSABufferArray[0].Length = m_Count;
9224 m_WSARecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(m_WSARecvMsgWSABufferArray, GCHandleType.Pinned);
9225 m_PtrWSARecvMsgWSABufferArray = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSARecvMsgWSABufferArray, 0);
9227 // just pin the multi-buffer WSABuffer
9228 m_WSARecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(m_WSABufferArray, GCHandleType.Pinned);
9229 m_PtrWSARecvMsgWSABufferArray = Marshal.UnsafeAddrOfPinnedArrayElement(m_WSABufferArray, 0);
9232 // Fill in WSAMessageBuffer
9234 UnsafeNclNativeMethods.OSSOCK.WSAMsg* pMessage = (UnsafeNclNativeMethods.OSSOCK.WSAMsg*)m_PtrWSAMessageBuffer;;
9235 pMessage->socketAddress = m_PtrSocketAddressBuffer;
9236 pMessage->addressLength = (uint)m_SocketAddress.Size;
9237 pMessage->buffers = m_PtrWSARecvMsgWSABufferArray;
9238 if(m_Buffer != null) {
9239 pMessage->count = (uint)1;
9241 pMessage->count = (uint)m_WSABufferArray.Length;
9243 if(m_ControlBuffer != null) {
9244 pMessage->controlBuffer.Pointer = m_PtrControlBuffer;
9245 pMessage->controlBuffer.Length = m_ControlBuffer.Length;
9247 pMessage->flags = m_SocketFlags;
9251 internal void StartOperationSend() {
9252 // Remember the operation type.
9253 m_CompletedOperation = SocketAsyncOperation.Send;
9255 // WSASend uses a WSABuffer array describing buffers of data to send.
9256 // Single and multiple buffers are handled differently so as to optimize
9257 // performance for the more common single buffer case.
9258 // For a single buffer:
9259 // The Overlapped.UnsafePack method is used that takes a single object to pin.
9260 // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
9261 // For multiple buffers:
9262 // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
9263 // An array to reference the multiple buffer is allocated.
9264 // An array of WSABuffer descriptors is allocated.
9267 internal void StartOperationSendPackets() {
9268 // Remember the operation type.
9269 m_CompletedOperation = SocketAsyncOperation.SendPackets;
9271 // Prevent mutithreaded manipulation of the list.
9272 if (m_SendPacketsElements != null) {
9273 m_SendPacketsElementsInternal = (SendPacketsElement[])m_SendPacketsElements.Clone();
9276 // TransmitPackets uses an array of TRANSMIT_PACKET_ELEMENT structs as
9277 // descriptors for buffers and files to be sent. It also takes a send size
9278 // and some flags. The TRANSMIT_PACKET_ELEMENT for a file contains a native file handle.
9279 // This function basically opens the files to get the file handles, pins down any buffers
9280 // specified and builds the native TRANSMIT_PACKET_ELEMENT array that will be passed
9281 // to TransmitPackets.
9283 // Scan the elements to count files and buffers
9284 m_SendPacketsElementsFileCount = 0;
9285 m_SendPacketsElementsBufferCount = 0;
9286 foreach (SendPacketsElement spe in m_SendPacketsElementsInternal) {
9288 if(spe.m_FilePath != null) {
9289 m_SendPacketsElementsFileCount++;
9291 if(spe.m_Buffer != null && spe.m_Count > 0) {
9292 m_SendPacketsElementsBufferCount++;
9297 // Attempt to open the files if any
9298 if(m_SendPacketsElementsFileCount > 0) {
9300 // Create arrays for streams and handles
9301 m_SendPacketsFileStreams = new FileStream[m_SendPacketsElementsFileCount];
9302 m_SendPacketsFileHandles = new SafeHandle[m_SendPacketsElementsFileCount];
9304 // Loop through the elements attempting to open each files and get its handle
9306 foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
9307 if(spe != null && spe.m_FilePath != null) {
9308 Exception fileStreamException = null;
9310 // Create a FileStream to open the file
9311 m_SendPacketsFileStreams[index] =
9312 new FileStream(spe.m_FilePath,FileMode.Open,FileAccess.Read,FileShare.Read);
9314 catch (Exception ex) {
9315 // Save the exception to throw after closing any previous successful file opens
9316 fileStreamException = ex;
9318 if (fileStreamException != null) {
9319 // Got exception opening a file - do some cleanup then throw
9320 for(int i = 0; i < m_SendPacketsElementsFileCount; i++) {
9321 // Dereference handles
9322 m_SendPacketsFileHandles[i] = null;
9323 // Close any open streams
9324 if(m_SendPacketsFileStreams[i] != null) {
9325 m_SendPacketsFileStreams[i].Close();
9326 m_SendPacketsFileStreams[i] = null;
9329 throw fileStreamException;
9331 // Get the file handle from the stream
9332 ExceptionHelper.UnmanagedPermission.Assert();
9334 m_SendPacketsFileHandles[index] = m_SendPacketsFileStreams[index].SafeFileHandle;
9337 SecurityPermission.RevertAssert();
9344 CheckPinSendPackets();
9347 internal void StartOperationSendTo() {
9348 // Remember the operation type.
9349 m_CompletedOperation = SocketAsyncOperation.SendTo;
9351 // WSASendTo uses a WSABuffer array describing buffers in which to
9352 // receive data and from which to send data respectively. Single and multiple buffers
9353 // are handled differently so as to optimize performance for the more common single buffer case.
9354 // For a single buffer:
9355 // The Overlapped.UnsafePack method is used that takes a single object to pin.
9356 // A single WSABuffer that pre-exists in SocketAsyncEventArgs is used.
9357 // For multiple buffers:
9358 // The Overlapped.UnsafePack method is used that takes an array of objects to pin.
9359 // An array to reference the multiple buffer is allocated.
9360 // An array of WSABuffer descriptors is allocated.
9361 // WSARecvFrom and WSASendTo also uses a sockaddr buffer in which to store the address from which the data was received.
9362 // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
9363 PinSocketAddressBuffer();
9366 // Method to ensure Overlapped object exists for operations that need no data buffer.
9367 private void CheckPinNoBuffer() {
9369 if (m_PinState == PinState.None) {
9370 SetupOverlappedSingle(true);
9374 // Method to maintain pinned state of single buffer
9375 private void CheckPinSingleBuffer(bool pinUsersBuffer) {
9377 if (pinUsersBuffer) {
9379 // Using app supplied buffer.
9381 if (m_Buffer == null) {
9383 // No user buffer is set so unpin any existing single buffer pinning.
9384 if(m_PinState == PinState.SingleBuffer) {
9385 FreeOverlapped(false);
9390 if(m_PinState == PinState.SingleBuffer && m_PinnedSingleBuffer == m_Buffer) {
9391 // This buffer is already pinned - update if offset or count has changed.
9392 if (m_Offset != m_PinnedSingleBufferOffset) {
9393 m_PinnedSingleBufferOffset = m_Offset;
9394 m_PtrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, m_Offset);
9395 m_WSABuffer.Pointer = m_PtrSingleBuffer;
9397 if (m_Count != m_PinnedSingleBufferCount) {
9398 m_PinnedSingleBufferCount = m_Count;
9399 m_WSABuffer.Length = m_Count;
9402 FreeOverlapped(false);
9403 SetupOverlappedSingle(true);
9408 // Using internal accept buffer.
9410 if(!(m_PinState == PinState.SingleAcceptBuffer) || !(m_PinnedSingleBuffer == m_AcceptBuffer)) {
9412 // Not already pinned - so pin it.
9413 FreeOverlapped(false);
9414 SetupOverlappedSingle(false);
9419 // Method to ensure Overlapped object exists with appropriate multiple buffers pinned.
9420 private void CheckPinMultipleBuffers() {
9422 if (m_BufferList == null) {
9424 // No buffer list is set so unpin any existing multiple buffer pinning.
9426 if(m_PinState == PinState.MultipleBuffer) {
9427 FreeOverlapped(false);
9431 if(!(m_PinState == PinState.MultipleBuffer) || m_BufferListChanged) {
9432 // Need to setup new Overlapped
9433 m_BufferListChanged = false;
9434 FreeOverlapped(false);
9437 SetupOverlappedMultiple();
9441 FreeOverlapped(false);
9448 // Method to ensure Overlapped object exists with appropriate buffers pinned.
9449 private void CheckPinSendPackets() {
9450 if(m_PinState != PinState.None) {
9451 FreeOverlapped(false);
9453 SetupOverlappedSendPackets();
9456 // Method to ensure appropriate SocketAddress buffer is pinned.
9457 private void PinSocketAddressBuffer() {
9458 // Check if already pinned.
9459 if(m_PinnedSocketAddress == m_SocketAddress) {
9463 // Unpin any existing.
9464 if(m_SocketAddressGCHandle.IsAllocated) {
9465 m_SocketAddressGCHandle.Free();
9468 // Pin down the new one.
9469 m_SocketAddressGCHandle = GCHandle.Alloc(m_SocketAddress.m_Buffer, GCHandleType.Pinned);
9470 m_SocketAddress.CopyAddressSizeIntoBuffer();
9471 m_PtrSocketAddressBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_SocketAddress.m_Buffer, 0);
9472 m_PtrSocketAddressBufferSize = Marshal.UnsafeAddrOfPinnedArrayElement(m_SocketAddress.m_Buffer, m_SocketAddress.GetAddressSizeOffset());
9473 m_PinnedSocketAddress = m_SocketAddress;
9476 // Method to clean up any existing Overlapped object and related state variables.
9477 private void FreeOverlapped(bool checkForShutdown) {
9478 if (!checkForShutdown || !NclUtilities.HasShutdownStarted) {
9480 // Free the overlapped object
9482 if(m_PtrNativeOverlapped != null && !m_PtrNativeOverlapped.IsInvalid) {
9483 m_PtrNativeOverlapped.Dispose();
9484 m_PtrNativeOverlapped = null;
9485 m_Overlapped = null;
9486 m_PinState = PinState.None;
9487 m_PinnedAcceptBuffer = null;
9488 m_PinnedSingleBuffer = null;
9489 m_PinnedSingleBufferOffset = 0;
9490 m_PinnedSingleBufferCount = 0;
9493 // Free any alloc'd GCHandles
9495 if(m_SocketAddressGCHandle.IsAllocated) {
9496 m_SocketAddressGCHandle.Free();
9498 if(m_WSAMessageBufferGCHandle.IsAllocated) {
9499 m_WSAMessageBufferGCHandle.Free();
9501 if(m_WSARecvMsgWSABufferArrayGCHandle.IsAllocated) {
9502 m_WSARecvMsgWSABufferArrayGCHandle.Free();
9504 if(m_ControlBufferGCHandle.IsAllocated) {
9505 m_ControlBufferGCHandle.Free();
9511 // Method to setup an Overlapped object with either m_Buffer or m_AcceptBuffer pinned.
9512 unsafe private void SetupOverlappedSingle(bool pinSingleBuffer) {
9514 // Alloc new Overlapped.
9515 m_Overlapped = new Overlapped();
9517 // Pin buffer, get native pointers, and fill in WSABuffer descriptor.
9518 if(pinSingleBuffer) {
9519 if(m_Buffer != null) {
9520 #if SOCKETTHREADPOOL
9521 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9522 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_Buffer));
9524 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_Buffer));
9526 m_PinnedSingleBuffer = m_Buffer;
9527 m_PinnedSingleBufferOffset = m_Offset;
9528 m_PinnedSingleBufferCount = m_Count;
9529 m_PtrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, m_Offset);
9530 m_PtrAcceptBuffer = IntPtr.Zero;
9531 m_WSABuffer.Pointer = m_PtrSingleBuffer;
9532 m_WSABuffer.Length = m_Count;
9533 m_PinState = PinState.SingleBuffer;
9535 #if SOCKETTHREADPOOL
9536 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9537 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, null));
9539 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, null));
9541 m_PinnedSingleBuffer = null;
9542 m_PinnedSingleBufferOffset = 0;
9543 m_PinnedSingleBufferCount = 0;
9544 m_PtrSingleBuffer = IntPtr.Zero;
9545 m_PtrAcceptBuffer = IntPtr.Zero;
9546 m_WSABuffer.Pointer = m_PtrSingleBuffer;
9547 m_WSABuffer.Length = m_Count;
9548 m_PinState = PinState.NoBuffer;
9551 #if SOCKETTHREADPOOL
9552 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9553 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_AcceptBuffer));
9555 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_AcceptBuffer));
9557 m_PinnedAcceptBuffer = m_AcceptBuffer;
9558 m_PtrAcceptBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_AcceptBuffer, 0);
9559 m_PtrSingleBuffer = IntPtr.Zero;
9560 m_PinState = PinState.SingleAcceptBuffer;
9564 // Method to setup an Overlapped object with with multiple buffers pinned.
9565 unsafe private void SetupOverlappedMultiple() {
9567 ArraySegment<byte>[] tempList = new ArraySegment<byte>[m_BufferList.Count];
9568 m_BufferList.CopyTo(tempList, 0);
9570 // Alloc new Overlapped.
9571 m_Overlapped = new Overlapped();
9573 // Number of things to pin is number of buffers.
9574 // Ensure we have properly sized object array.
9575 if(m_ObjectsToPin == null || (m_ObjectsToPin.Length != tempList.Length)) {
9576 m_ObjectsToPin = new object[tempList.Length];
9579 // Fill in object array.
9580 for(int i = 0; i < (tempList.Length); i++) {
9581 m_ObjectsToPin[i] = tempList[i].Array;
9584 if(m_WSABufferArray == null || m_WSABufferArray.Length != tempList.Length) {
9585 m_WSABufferArray = new WSABuffer[tempList.Length];
9588 // Pin buffers and fill in WSABuffer descriptor pointers and lengths
9589 #if SOCKETTHREADPOOL
9590 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9591 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_ObjectsToPin));
9593 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_ObjectsToPin));
9595 for(int i = 0; i < tempList.Length; i++) {
9596 ArraySegment<byte> localCopy = tempList[i];
9597 ValidationHelper.ValidateSegment(localCopy);
9598 m_WSABufferArray[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(localCopy.Array, localCopy.Offset);
9599 m_WSABufferArray[i].Length = localCopy.Count;
9601 m_PinState = PinState.MultipleBuffer;
9604 // Method to setup an Overlapped object for SendPacketsAsync.
9605 unsafe private void SetupOverlappedSendPackets() {
9609 // Alloc new Overlapped.
9610 m_Overlapped = new Overlapped();
9612 // Alloc native descriptor.
9613 m_SendPacketsDescriptor =
9614 new UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElement[m_SendPacketsElementsFileCount + m_SendPacketsElementsBufferCount];
9616 // Number of things to pin is number of buffers + 1 (native descriptor).
9617 // Ensure we have properly sized object array.
9618 if(m_ObjectsToPin == null || (m_ObjectsToPin.Length != m_SendPacketsElementsBufferCount + 1)) {
9619 m_ObjectsToPin = new object[m_SendPacketsElementsBufferCount + 1];
9622 // Fill in objects to pin array. Native descriptor buffer first and then user specified buffers.
9623 m_ObjectsToPin[0] = m_SendPacketsDescriptor;
9625 foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
9626 if(spe != null && spe.m_Buffer != null && spe.m_Count > 0) {
9627 m_ObjectsToPin[index] = spe.m_Buffer;
9633 #if SOCKETTHREADPOOL
9634 m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback);
9635 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_ObjectsToPin));
9637 m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_ObjectsToPin));
9640 // Get pointer to native descriptor.
9641 m_PtrSendPacketsDescriptor = Marshal.UnsafeAddrOfPinnedArrayElement(m_SendPacketsDescriptor, 0);
9643 // Fill in native descriptor.
9644 int descriptorIndex = 0;
9646 foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
9648 if(spe.m_Buffer != null && spe.m_Count > 0) {
9650 m_SendPacketsDescriptor[descriptorIndex].buffer = Marshal.UnsafeAddrOfPinnedArrayElement(spe.m_Buffer, spe.m_Offset);
9651 m_SendPacketsDescriptor[descriptorIndex].length = (uint)spe.m_Count;
9652 m_SendPacketsDescriptor[descriptorIndex].flags = spe.m_Flags;
9654 } else if (spe.m_FilePath != null) {
9656 m_SendPacketsDescriptor[descriptorIndex].fileHandle = m_SendPacketsFileHandles[fileIndex].DangerousGetHandle();
9657 m_SendPacketsDescriptor[descriptorIndex].fileOffset = spe.m_Offset;
9658 m_SendPacketsDescriptor[descriptorIndex].length = (uint)spe.m_Count;
9659 m_SendPacketsDescriptor[descriptorIndex].flags = spe.m_Flags;
9666 m_PinState = PinState.SendPackets;
9669 internal void LogBuffer(int size) {
9670 switch(m_PinState) {
9671 case PinState.SingleAcceptBuffer:
9672 Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", m_AcceptBuffer, 0, size);
9674 case PinState.SingleBuffer:
9675 Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", m_Buffer, m_Offset, size);
9677 case PinState.MultipleBuffer:
9678 foreach(WSABuffer wsaBuffer in m_WSABufferArray) {
9679 Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", wsaBuffer.Pointer, Math.Min(wsaBuffer.Length, size));
9680 if((size -= wsaBuffer.Length) <= 0)
9689 internal void LogSendPacketsBuffers(int size) {
9690 foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) {
9692 if(spe.m_Buffer != null && spe.m_Count > 0) {
9694 Logging.Dump(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)Buffer", spe.m_Buffer, spe.m_Offset, Math.Min(spe.m_Count, size));
9695 } else if(spe.m_FilePath != null) {
9697 Logging.PrintInfo(Logging.Sockets, m_CurrentSocket, "FinishOperation(" + m_CompletedOperation + "Async)", SR.GetString(SR.net_log_socket_not_logged_file, spe.m_FilePath));
9703 internal void UpdatePerfCounters(int size, bool sendOp) {
9704 #if !FEATURE_PAL // perfcounter
9706 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesSent, size);
9707 if(m_CurrentSocket.Transport == TransportType.Udp) {
9708 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsSent);
9711 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketBytesReceived, size);
9712 if(m_CurrentSocket.Transport == TransportType.Udp) {
9713 NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.SocketDatagramsReceived);
9719 internal void FinishOperationSyncFailure(SocketError socketError, int bytesTransferred, SocketFlags flags) {
9720 SetResults(socketError, bytesTransferred, flags);
9722 // this will be null if we're doing a static ConnectAsync to a DnsEndPoint with AddressFamily.Unspecified;
9723 // the attempt socket will be closed anyways, so not updating the state is OK
9724 if (m_CurrentSocket != null) {
9725 m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
9731 internal void FinishConnectByNameSyncFailure(Exception exception, int bytesTransferred, SocketFlags flags) {
9732 SetResults(exception, bytesTransferred, flags);
9734 if (m_CurrentSocket != null) {
9735 m_CurrentSocket.UpdateStatusAfterSocketError(m_SocketError);
9741 internal void FinishOperationAsyncFailure(SocketError socketError, int bytesTransferred, SocketFlags flags) {
9742 SetResults(socketError, bytesTransferred, flags);
9744 // this will be null if we're doing a static ConnectAsync to a DnsEndPoint with AddressFamily.Unspecified;
9745 // the attempt socket will be closed anyways, so not updating the state is OK
9746 if (m_CurrentSocket != null) {
9747 m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
9751 if(m_Context == null) {
9754 ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
9758 internal void FinishOperationAsyncFailure(Exception exception, int bytesTransferred, SocketFlags flags) {
9759 SetResults(exception, bytesTransferred, flags);
9761 if (m_CurrentSocket != null) {
9762 m_CurrentSocket.UpdateStatusAfterSocketError(m_SocketError);
9765 if (m_Context == null) {
9768 ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
9772 internal void FinishWrapperConnectSuccess(Socket connectSocket, int bytesTransferred, SocketFlags flags) {
9774 SetResults(SocketError.Success, bytesTransferred, flags);
9775 m_CurrentSocket = connectSocket;
9776 m_ConnectSocket = connectSocket;
9778 // Complete the operation and raise the event
9780 if (m_ContextCopy == null) {
9783 ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
9787 internal void FinishOperationSuccess(SocketError socketError, int bytesTransferred, SocketFlags flags) {
9789 SetResults(socketError, bytesTransferred, flags);
9791 switch(m_CompletedOperation) {
9793 case SocketAsyncOperation.Accept:
9796 if (bytesTransferred > 0) {
9797 // Log and Perf counters.
9798 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9799 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
9802 // Get the endpoint.
9803 SocketAddress remoteSocketAddress = m_CurrentSocket.m_RightEndPoint.Serialize();
9806 int localAddrLength;
9810 m_CurrentSocket.GetAcceptExSockaddrs(
9811 m_PtrSingleBuffer != IntPtr.Zero ? m_PtrSingleBuffer : m_PtrAcceptBuffer,
9812 m_Count != 0 ? m_Count - m_AcceptAddressBufferCount : 0,
9813 m_AcceptAddressBufferCount / 2,
9814 m_AcceptAddressBufferCount / 2,
9816 out localAddrLength,
9818 out remoteSocketAddress.m_Size
9820 Marshal.Copy(remoteAddr, remoteSocketAddress.m_Buffer, 0, remoteSocketAddress.m_Size);
9822 // Set the socket context.
9823 IntPtr handle = m_CurrentSocket.SafeHandle.DangerousGetHandle();
9825 socketError = UnsafeNclNativeMethods.OSSOCK.setsockopt(
9826 m_AcceptSocket.SafeHandle,
9827 SocketOptionLevel.Socket,
9828 SocketOptionName.UpdateAcceptContext,
9830 Marshal.SizeOf(handle));
9832 if(socketError == SocketError.SocketError) {
9833 socketError = (SocketError)Marshal.GetLastWin32Error();
9836 catch(ObjectDisposedException) {
9837 socketError = SocketError.OperationAborted;
9840 if(socketError == SocketError.Success) {
9841 m_AcceptSocket = m_CurrentSocket.UpdateAcceptSocket(m_AcceptSocket, m_CurrentSocket.m_RightEndPoint.Create(remoteSocketAddress), false);
9843 if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, m_AcceptSocket,
9844 SR.GetString(SR.net_log_socket_accepted, m_AcceptSocket.RemoteEndPoint, m_AcceptSocket.LocalEndPoint));
9846 SetResults(socketError, bytesTransferred, SocketFlags.None);
9847 m_AcceptSocket = null;
9851 case SocketAsyncOperation.Connect:
9853 if (bytesTransferred > 0) {
9854 // Log and Perf counters.
9855 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9856 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
9859 // Update the socket context.
9861 socketError = UnsafeNclNativeMethods.OSSOCK.setsockopt(
9862 m_CurrentSocket.SafeHandle,
9863 SocketOptionLevel.Socket,
9864 SocketOptionName.UpdateConnectContext,
9867 if(socketError == SocketError.SocketError) {
9868 socketError = (SocketError)Marshal.GetLastWin32Error();
9871 catch(ObjectDisposedException) {
9872 socketError = SocketError.OperationAborted;
9875 // Mark socket connected.
9876 if(socketError == SocketError.Success) {
9877 if (s_LoggingEnabled) Logging.PrintInfo(Logging.Sockets, m_CurrentSocket,
9878 SR.GetString(SR.net_log_socket_connected, m_CurrentSocket.LocalEndPoint, m_CurrentSocket.RemoteEndPoint));
9880 m_CurrentSocket.SetToConnected();
9881 m_ConnectSocket = m_CurrentSocket;
9885 case SocketAsyncOperation.Disconnect:
9887 m_CurrentSocket.SetToDisconnected();
9888 m_CurrentSocket.m_RemoteEndPoint = null;
9892 case SocketAsyncOperation.Receive:
9894 if (bytesTransferred > 0) {
9895 // Log and Perf counters.
9896 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9897 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
9901 case SocketAsyncOperation.ReceiveFrom:
9903 if (bytesTransferred > 0) {
9904 // Log and Perf counters.
9905 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9906 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
9909 // Deal with incoming address.
9910 m_SocketAddress.SetSize(m_PtrSocketAddressBufferSize);
9911 SocketAddress socketAddressOriginal = m_RemoteEndPoint.Serialize();
9912 if(!socketAddressOriginal.Equals(m_SocketAddress)) {
9914 m_RemoteEndPoint = m_RemoteEndPoint.Create(m_SocketAddress);
9921 case SocketAsyncOperation.ReceiveMessageFrom:
9923 if (bytesTransferred > 0) {
9924 // Log and Perf counters.
9925 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9926 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, false);
9929 // Deal with incoming address.
9930 m_SocketAddress.SetSize(m_PtrSocketAddressBufferSize);
9931 socketAddressOriginal = m_RemoteEndPoint.Serialize();
9932 if(!socketAddressOriginal.Equals(m_SocketAddress)) {
9934 m_RemoteEndPoint = m_RemoteEndPoint.Create(m_SocketAddress);
9940 // Extract the packet information.
9942 IPAddress address = null;
9943 UnsafeNclNativeMethods.OSSOCK.WSAMsg* PtrMessage = (UnsafeNclNativeMethods.OSSOCK.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(m_WSAMessageBuffer, 0);
9946 if(m_ControlBuffer.Length == s_ControlDataSize) {
9947 UnsafeNclNativeMethods.OSSOCK.ControlData controlData = (UnsafeNclNativeMethods.OSSOCK.ControlData)Marshal.PtrToStructure(PtrMessage->controlBuffer.Pointer, typeof(UnsafeNclNativeMethods.OSSOCK.ControlData));
9948 if(controlData.length != UIntPtr.Zero) {
9949 address = new IPAddress((long)controlData.address);
9951 m_ReceiveMessageFromPacketInfo = new IPPacketInformation(((address != null) ? address : IPAddress.None), (int)controlData.index);
9954 else if(m_ControlBuffer.Length == s_ControlDataIPv6Size) {
9955 UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6 controlData = (UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6)Marshal.PtrToStructure(PtrMessage->controlBuffer.Pointer, typeof(UnsafeNclNativeMethods.OSSOCK.ControlDataIPv6));
9956 if(controlData.length != UIntPtr.Zero) {
9957 address = new IPAddress(controlData.address);
9959 m_ReceiveMessageFromPacketInfo = new IPPacketInformation(((address != null) ? address : IPAddress.IPv6None), (int)controlData.index);
9963 m_ReceiveMessageFromPacketInfo = new IPPacketInformation();
9968 case SocketAsyncOperation.Send:
9970 if (bytesTransferred > 0) {
9971 // Log and Perf counters.
9972 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
9973 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
9977 case SocketAsyncOperation.SendPackets:
9979 if(bytesTransferred > 0) {
9980 // Log and Perf counters.
9981 if(s_LoggingEnabled) LogSendPacketsBuffers(bytesTransferred);
9982 if(Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
9985 // Close the files if open
9986 if (m_SendPacketsFileStreams != null) {
9987 for(int i = 0; i < m_SendPacketsElementsFileCount; i++) {
9988 // Dereference handles
9989 m_SendPacketsFileHandles[i] = null;
9990 // Close any open streams
9991 if(m_SendPacketsFileStreams[i] != null) {
9992 m_SendPacketsFileStreams[i].Close();
9993 m_SendPacketsFileStreams[i] = null;
9997 m_SendPacketsFileStreams = null;
9998 m_SendPacketsFileHandles = null;
10002 case SocketAsyncOperation.SendTo:
10004 if (bytesTransferred > 0) {
10005 // Log and Perf counters.
10006 if (s_LoggingEnabled) LogBuffer(bytesTransferred);
10007 if (Socket.s_PerfCountersEnabled) UpdatePerfCounters(bytesTransferred, true);
10013 if(socketError != SocketError.Success) {
10014 // Asynchronous failure or something went wrong after async success.
10015 SetResults(socketError, bytesTransferred, flags);
10016 m_CurrentSocket.UpdateStatusAfterSocketError(socketError);
10019 // Complete the operation and raise completion event.
10021 if(m_ContextCopy == null) {
10024 ExecutionContext.Run(m_ContextCopy, m_ExecutionCallback, null);
10028 private unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) {
10030 GlobalLog.SetThreadSource(ThreadKinds.CompletionPort);
10031 using(GlobalLog.SetThreadKind(ThreadKinds.System)) {
10033 SocketFlags socketFlags = SocketFlags.None;
10034 SocketError socketError = (SocketError)errorCode;
10036 if(socketError == SocketError.Success) {
10037 FinishOperationSuccess(socketError, (int)numBytes, socketFlags);
10039 if(socketError != SocketError.OperationAborted) {
10040 if(m_CurrentSocket.CleanedUp) {
10041 socketError = SocketError.OperationAborted;
10044 // This is the same NativeOverlapped* as we already have a SafeHandle for, re-use the orriginal.
10045 Debug.Assert((IntPtr)nativeOverlapped == m_PtrNativeOverlapped.DangerousGetHandle(), "Handle mismatch");
10047 // The Async IO completed with a failure.
10048 // here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error.
10049 bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult(
10050 m_CurrentSocket.SafeHandle,
10051 m_PtrNativeOverlapped,
10055 socketError = (SocketError)Marshal.GetLastWin32Error();
10058 // m_CurrentSocket.CleanedUp check above does not always work since this code is subject to race conditions
10059 socketError = SocketError.OperationAborted;
10063 FinishOperationAsyncFailure(socketError, (int)numBytes, socketFlags);
10069 } // class SocketAsyncContext
10071 #if SOCKETTHREADPOOL
10072 internal static class SocketThreadPool
10074 private static readonly int c_threadIOCPTimeout = 15000; // milliseconds
10075 private static readonly IntPtr c_InvalidHandleValue = new IntPtr(-1);
10076 private static readonly int m_maxThreadsAllowed = System.Int32.MaxValue; //Maybe (Environment.ProcessorCount * some_factor) ?
10077 private static int m_numThreadsInPool = 0;
10078 private static int m_maxThreadsEverInPool = 0;
10079 private static int m_numBusyThreads = 0;
10080 private static int m_numCallbacks = 0;
10081 private static int m_numBoundHandles = 0;
10082 private static object s_InternalSyncObject;
10083 private static bool initialized = false;
10084 private static IntPtr m_hIOCP = c_InvalidHandleValue;
10086 public static bool BindHandle(SafeHandle osHandle)
10088 // ensure initialized
10092 // bind to completion port
10094 IntPtr handle = UnsafeNclNativeMethods.OSSOCK.CreateIoCompletionPort(osHandle, m_hIOCP, 1111, 0);
10095 if (handle == IntPtr.Zero)
10097 throw new Exception(string.Format("CreateIoCompletionPort failed with Win32 error {0}.", Marshal.GetLastWin32Error()));
10102 Interlocked.Increment(ref m_numBoundHandles);
10104 if (m_numThreadsInPool == 0)
10106 // add thread to pool if none
10113 public static void UnBindHandle(SafeHandle osHandle)
10115 // take count to zero
10117 Interlocked.Decrement(ref m_numBoundHandles);
10120 private static void Init()
10124 lock (InternalSyncObject)
10128 // Create completion port
10130 m_hIOCP = UnsafeNclNativeMethods.OSSOCK.CreateIoCompletionPort(c_InvalidHandleValue, IntPtr.Zero, 1111, 0);
10131 if (m_hIOCP == c_InvalidHandleValue)
10133 throw new Exception(string.Format("CreateIoCompletionPort failed with Win32 error {0}.", Marshal.GetLastWin32Error()));
10135 initialized = true;
10141 private static object InternalSyncObject
10145 if (s_InternalSyncObject == null)
10147 object o = new object();
10148 Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
10150 return s_InternalSyncObject;
10154 private unsafe static void ThreadPoolFunc()
10158 for (Boolean fStayInPool = true; fStayInPool; /*empty*/ )
10162 uint bytesTransferred;
10164 NativeOverlapped* nativeOverlappedPtr;
10166 // Thread no longer busy.
10168 Interlocked.Decrement(ref m_numBusyThreads);
10170 // Read the completion port queue.
10172 result = UnsafeNclNativeMethods.OSSOCK.GetQueuedCompletionStatus(
10174 out bytesTransferred,
10176 out nativeOverlappedPtr,
10177 c_threadIOCPTimeout);
10179 // Thread woke up and might have something to do.
10181 Int32 busyThreads = Interlocked.Increment(ref m_numBusyThreads);
10183 // Get win32 status only if GQCS returned false.
10188 status = (uint)Marshal.GetLastWin32Error();
10191 // Handle the case where GQCS itself fails without dequeueing a completion packet.
10193 if (nativeOverlappedPtr == null)
10195 // Could be a timeout.
10197 if (status == (uint)258) // WAIT_TIMEOUT
10199 // On timeout let thread go away
10201 fStayInPool = false;
10202 break; // Leave the loop
10205 // Some other win32 failure - try GQCS again.
10210 // Heuristic to add another thread to pool.
10212 if ((busyThreads == m_numThreadsInPool) && (busyThreads < m_maxThreadsAllowed))
10217 // Unpack the native overlapped structure into managed Overlapped object
10219 Overlapped overlapped = Overlapped.Unpack(nativeOverlappedPtr);
10221 // See if we have a SocketOperationAsyncResult.
10222 // Otherwise we have something derived from BaseOverlappedAsyncResult.
10224 DummyAsyncResult ar = overlapped.AsyncResult as DummyAsyncResult;
10227 // Is child of BaseOverlappedAsyncResult. Callback is static function in BaseOverlappedAsyncResult.
10229 // call the callback
10230 BaseOverlappedAsyncResult.s_IOCallback(status, bytesTransferred, nativeOverlappedPtr);
10234 // Must be SocAsyncResult. Callback is in the AsyncResult.
10236 // call the callback
10237 ar.IOCompletionCallBack(status, bytesTransferred, nativeOverlappedPtr);
10240 // count the completion
10242 Interlocked.Increment(ref m_numCallbacks);
10250 // Thread is leaving pool.
10252 Interlocked.Decrement(ref m_numBusyThreads);
10253 if (Interlocked.Decrement(ref m_numThreadsInPool) == 0)
10255 // No more threads in the pool.
10260 private static void AddThreadToPool()
10262 // suppress flow if not already
10264 if (!ExecutionContext.IsFlowSuppressed()) ExecutionContext.SuppressFlow();
10266 // Adding a thread to the thread pool
10268 Interlocked.Increment(ref m_numThreadsInPool);
10270 // Track max threads in pool
10272 InterlockedMax(ref m_maxThreadsEverInPool, m_numThreadsInPool);
10274 // Thread is busy until it blocks on GQCS
10276 Interlocked.Increment(ref m_numBusyThreads);
10280 Thread t = new Thread(new ThreadStart(ThreadPoolFunc));
10281 t.IsBackground = true;
10285 private static Int32 InterlockedMax(ref Int32 target, Int32 val)
10287 Int32 i, j = target;
10291 j = Interlocked.CompareExchange(ref target, Math.Max(i, val), i);
10297 // internal minimal IAsyncResult class to pass completion routine across native overlapped calls via Overlapped magic internals
10298 internal class DummyAsyncResult : IAsyncResult {
10299 IOCompletionCallback m_iocb;
10301 public DummyAsyncResult() : this(null) {
10303 public DummyAsyncResult(IOCompletionCallback iocb) {
10306 public IOCompletionCallback IOCompletionCallBack {
10307 get { return m_iocb; }
10309 public object AsyncObject {
10310 get { return null; }
10312 public object AsyncState {
10313 get { return null; }
10315 public bool IsCompleted {
10316 get { return false; }
10318 public WaitHandle AsyncWaitHandle {
10319 get { return null; }
10321 public bool CompletedSynchronously {
10322 get { return false; }
10325 #endif // SOCKETTHREADPOOL