/mcs/class/referencesource/System/net/System/Net/Sockets/Socket.cs
C# | 10332 lines | 6761 code | 1552 blank | 2019 comment | 1643 complexity | f3cf07bc4700d0d7e8094627109d65a8 MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Unlicense, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- //------------------------------------------------------------------------------
- // <copyright file="Socket.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- //------------------------------------------------------------------------------
- #if MONO
- #undef FEATURE_PAL
- #endif
- namespace System.Net.Sockets {
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Globalization;
- using System.IO;
- using System.Net;
- using System.Net.Configuration;
- using System.Runtime.InteropServices;
- using System.Security.Permissions;
- using System.Threading;
- using System.Runtime.Versioning;
- using System.Diagnostics.Contracts;
- using System.ComponentModel;
- /// <devdoc>
- /// <para>The <see cref='Sockets.Socket'/> class implements the Berkeley sockets
- /// interface.</para>
- /// </devdoc>
- public partial class Socket : IDisposable
- {
- #if !MONO
- internal const int DefaultCloseTimeout = -1; // don't change for default, otherwise breaking change
- // AcceptQueue - queued list of accept requests for BeginAccept or async Result for Begin Connect
- private object m_AcceptQueueOrConnectResult;
- // the following 8 members represent the state of the socket
- private SafeCloseSocket m_Handle;
- // m_RightEndPoint is null if the socket has not been bound. Otherwise, it is any EndPoint of the
- // correct type (IPEndPoint, etc).
- internal EndPoint m_RightEndPoint;
- internal EndPoint m_RemoteEndPoint;
- // this flags monitor if the socket was ever connected at any time and if it still is.
- private bool m_IsConnected; // = false;
- private bool m_IsDisconnected; // = false;
- // when the socket is created it will be in blocking mode
- // we'll only be able to Accept or Connect, so we only need
- // to handle one of these cases at a time
- private bool willBlock = true; // desired state of the socket for the user
- private bool willBlockInternal = true; // actual win32 state of the socket
- private bool isListening = false;
- // Our internal state doesn't automatically get updated after a non-blocking connect
- // completes. Keep track of whether we're doing a non-blocking connect, and make sure
- // to poll for the real state until we're done connecting.
- private bool m_NonBlockingConnectInProgress;
- // Keep track of the kind of endpoint used to do a non-blocking connect, so we can set
- // it to m_RightEndPoint when we discover we're connected.
- private EndPoint m_NonBlockingConnectRightEndPoint;
- // These are constants initialized by constructor
- private AddressFamily addressFamily;
- private SocketType socketType;
- private ProtocolType protocolType;
- // These caches are one degree off of Socket since they're not used in the sync case/when disabled in config.
- private CacheSet m_Caches;
- private class CacheSet
- {
- internal CallbackClosure ConnectClosureCache;
- internal CallbackClosure AcceptClosureCache;
- internal CallbackClosure SendClosureCache;
- internal CallbackClosure ReceiveClosureCache;
- internal OverlappedCache SendOverlappedCache;
- internal OverlappedCache ReceiveOverlappedCache;
- }
- //
- // Overlapped constants.
- //
- #if !(FEATURE_PAL && !MONO) || CORIOLIS
- internal static volatile bool UseOverlappedIO;
- #else
- // Disable the I/O completion port for Rotor
- internal static volatile bool UseOverlappedIO = true;
- #endif // !(FEATURE_PAL && !MONO) || CORIOLIS
- private bool useOverlappedIO;
- // Bool marked true if the native socket m_Handle was bound to the ThreadPool
- private bool m_BoundToThreadPool; // = false;
- // Bool marked true if the native socket option IP_PKTINFO or IPV6_PKTINFO has been set
- private bool m_ReceivingPacketInformation;
- // Event used for async Connect/Accept calls
- private ManualResetEvent m_AsyncEvent;
- private RegisteredWaitHandle m_RegisteredWait;
- private AsyncEventBits m_BlockEventBits = AsyncEventBits.FdNone;
- //These members are to cache permission checks
- private SocketAddress m_PermittedRemoteAddress;
- private DynamicWinsockMethods m_DynamicWinsockMethods;
- #endif // !MONO
- private static object s_InternalSyncObject;
- #if !MONO
- private int m_CloseTimeout = Socket.DefaultCloseTimeout;
- private int m_IntCleanedUp; // 0 if not completed >0 otherwise.
- private const int microcnv = 1000000;
- private readonly static int protocolInformationSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
- #endif // !MONO
- internal static volatile bool s_SupportsIPv4;
- internal static volatile bool s_SupportsIPv6;
- internal static volatile bool s_OSSupportsIPv6;
- internal static volatile bool s_Initialized;
- #if !MONO
- private static volatile WaitOrTimerCallback s_RegisteredWaitCallback;
- #endif
- private static volatile bool s_LoggingEnabled;
- #if !FEATURE_PAL // perfcounter
- internal static volatile bool s_PerfCountersEnabled;
- #endif
- //************* constructors *************************
- //------------------------------------
- // Creates a Dual Mode socket for working with both IPv4 and IPv6
- public Socket(SocketType socketType, ProtocolType protocolType)
- : this(AddressFamily.InterNetworkV6, socketType, protocolType) {
- DualMode = true;
- }
- /// <devdoc>
- /// <para>
- /// Initializes a new instance of the <see cref='Sockets.Socket'/> class.
- /// </para>
- /// </devdoc>
- public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) {
- #if WASM
- throw new PlatformNotSupportedException ();
- #else
- s_LoggingEnabled = Logging.On;
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
- InitializeSockets();
- #if MONO
- int error;
- m_Handle = new SafeSocketHandle (Socket_icall (addressFamily, socketType, protocolType, out error), true);
- #else
- m_Handle = SafeCloseSocket.CreateWSASocket(
- addressFamily,
- socketType,
- protocolType);
- #endif
- if (m_Handle.IsInvalid) {
- //
- // failed to create the win32 socket, throw
- //
- throw new SocketException();
- }
- this.addressFamily = addressFamily;
- this.socketType = socketType;
- this.protocolType = protocolType;
- IPProtectionLevel defaultProtectionLevel = SettingsSectionInternal.Section.IPProtectionLevel;
- if (defaultProtectionLevel != IPProtectionLevel.Unspecified) {
- SetIPProtectionLevel(defaultProtectionLevel);
- }
- #if MONO
- SocketDefaults ();
- #endif
- if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
- #endif
- }
- #if !MONO
- public Socket(SocketInformation socketInformation) {
- s_LoggingEnabled = Logging.On;
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
- ExceptionHelper.UnrestrictedSocketPermission.Demand();
- InitializeSockets();
- if(socketInformation.ProtocolInformation == null || socketInformation.ProtocolInformation.Length < protocolInformationSize){
- throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation.ProtocolInformation");
- }
- unsafe{
- fixed(byte * pinnedBuffer = socketInformation.ProtocolInformation){
- m_Handle = SafeCloseSocket.CreateWSASocket(pinnedBuffer);
- UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO protocolInfo = (UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO)Marshal.PtrToStructure((IntPtr)pinnedBuffer, typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
- addressFamily = protocolInfo.iAddressFamily;
- socketType = (SocketType)protocolInfo.iSocketType;
- protocolType = (ProtocolType)protocolInfo.iProtocol;
- }
- }
- if (m_Handle.IsInvalid) {
- SocketException e = new SocketException();
- if(e.ErrorCode == (int)SocketError.InvalidArgument){
- throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation");
- }
- else {
- throw e;
- }
- }
- if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- m_IsConnected = socketInformation.IsConnected;
- willBlock = !socketInformation.IsNonBlocking;
- InternalSetBlocking(willBlock);
- isListening = socketInformation.IsListening;
- UseOnlyOverlappedIO = socketInformation.UseOnlyOverlappedIO;
- //are we bound? if so, what's the local endpoint?
- if (socketInformation.RemoteEndPoint != null) {
- m_RightEndPoint = socketInformation.RemoteEndPoint;
- m_RemoteEndPoint = socketInformation.RemoteEndPoint;
- }
- else {
- EndPoint ep = null;
- if (addressFamily == AddressFamily.InterNetwork ) {
- ep = IPEndPoint.Any;
- }
- else if(addressFamily == AddressFamily.InterNetworkV6) {
- ep = IPEndPoint.IPv6Any;
- }
- SocketAddress socketAddress = ep.Serialize();
- SocketError errorCode;
- try
- {
- errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
- m_Handle,
- socketAddress.m_Buffer,
- ref socketAddress.m_Size);
- }
- catch (ObjectDisposedException)
- {
- errorCode = SocketError.NotSocket;
- }
- if (errorCode == SocketError.Success) {
- try {
- //we're bound
- m_RightEndPoint = ep.Create(socketAddress);
- }
- catch {
- }
- }
- }
- if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
- }
- /// <devdoc>
- /// <para>
- /// Called by the class to create a socket to accept an
- /// incoming request.
- /// </para>
- /// </devdoc>
- private Socket(SafeCloseSocket fd) {
- s_LoggingEnabled = Logging.On;
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", null);
- InitializeSockets();
- // ExceptionHelper.UnmanagedPermission.Demand();
- //<
- //
- // this should never happen, let's check anyway
- //
- if (fd == null || fd.IsInvalid) {
- throw new ArgumentException(SR.GetString(SR.net_InvalidSocketHandle));
- }
- m_Handle = fd;
- addressFamily = Sockets.AddressFamily.Unknown;
- socketType = Sockets.SocketType.Unknown;
- protocolType = Sockets.ProtocolType.Unknown;
- if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
- }
- #endif
- //************* properties *************************
- /// <devdoc>
- /// <para>Indicates whether IPv4 support is available and enabled on this machine.</para>
- /// </devdoc>
- [Obsolete("SupportsIPv4 is obsoleted for this type, please use OSSupportsIPv4 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
- public static bool SupportsIPv4 {
- get {
- InitializeSockets();
- return s_SupportsIPv4;
- }
- }
- // Renamed to be consistent with OSSupportsIPv6
- public static bool OSSupportsIPv4 {
- get {
- InitializeSockets();
- return s_SupportsIPv4;
- }
- }
- /// <devdoc>
- /// <para>Indicates whether IPv6 support is available and enabled on this machine.</para>
- /// </devdoc>
- [Obsolete("SupportsIPv6 is obsoleted for this type, please use OSSupportsIPv6 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
- public static bool SupportsIPv6 {
- get {
- InitializeSockets();
- return s_SupportsIPv6;
- }
- }
- internal static bool LegacySupportsIPv6 {
- get {
- InitializeSockets();
- return s_SupportsIPv6;
- }
- }
- public static bool OSSupportsIPv6 {
- get {
- InitializeSockets();
- return s_OSSupportsIPv6;
- }
- }
- #if !MONO
- /// <devdoc>
- /// <para>
- /// Gets the amount of data pending in the network's input buffer that can be
- /// read from the socket.
- /// </para>
- /// </devdoc>
- public int Available {
- get {
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- int argp = 0;
- // This may throw ObjectDisposedException.
- SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
- m_Handle,
- IoctlSocketConstants.FIONREAD,
- ref argp);
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Available_get() UnsafeNclNativeMethods.OSSOCK.ioctlsocket returns errorCode:" + errorCode);
- //
- // if the native call fails we'll throw a SocketException
- //
- if (errorCode==SocketError.SocketError) {
- //
- // update our internal state after this socket error and throw
- //
- SocketException socketException = new SocketException();
- UpdateStatusAfterSocketError(socketException);
- if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Available", socketException);
- throw socketException;
- }
- return argp;
- }
- }
- /// <devdoc>
- /// <para>
- /// Gets the local end point.
- /// </para>
- /// </devdoc>
- public EndPoint LocalEndPoint {
- get {
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
- {
- // update the state if we've become connected after a non-blocking connect
- m_IsConnected = true;
- m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
- m_NonBlockingConnectInProgress = false;
- }
- if (m_RightEndPoint == null) {
- return null;
- }
- SocketAddress socketAddress = m_RightEndPoint.Serialize();
- // This may throw ObjectDisposedException.
- SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
- m_Handle,
- socketAddress.m_Buffer,
- ref socketAddress.m_Size);
- if (errorCode!=SocketError.Success) {
- //
- // update our internal state after this socket error and throw
- //
- SocketException socketException = new SocketException();
- UpdateStatusAfterSocketError(socketException);
- if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "LocalEndPoint", socketException);
- throw socketException;
- }
- return m_RightEndPoint.Create(socketAddress);
- }
- }
- /// <devdoc>
- /// <para>
- /// Gets the remote end point
- /// </para>
- /// </devdoc>
- public EndPoint RemoteEndPoint {
- get {
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- if (m_RemoteEndPoint==null) {
- if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
- {
- // update the state if we've become connected after a non-blocking connect
- m_IsConnected = true;
- m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
- m_NonBlockingConnectInProgress = false;
- }
- if (m_RightEndPoint==null) {
- return null;
- }
- SocketAddress socketAddress = m_RightEndPoint.Serialize();
- // This may throw ObjectDisposedException.
- SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getpeername(
- m_Handle,
- socketAddress.m_Buffer,
- ref socketAddress.m_Size);
- if (errorCode!=SocketError.Success) {
- //
- // update our internal state after this socket error and throw
- //
- SocketException socketException = new SocketException();
- UpdateStatusAfterSocketError(socketException);
- if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "RemoteEndPoint", socketException);
- throw socketException;
- }
- try {
- m_RemoteEndPoint = m_RightEndPoint.Create(socketAddress);
- }
- catch {
- }
- }
- return m_RemoteEndPoint;
- }
- }
- #endif // !MONO
- /// <devdoc>
- /// <para>
- /// Gets the operating system m_Handle for the socket.
- ///YUKON: should we cut this method off, who are the users?
- /// </para>
- /// </devdoc>
- public IntPtr Handle {
- get {
- #if !MONO
- ExceptionHelper.UnmanagedPermission.Demand();
- #endif
- return m_Handle.DangerousGetHandle();
- }
- }
- #if !MONO
- internal SafeCloseSocket SafeHandle {
- get {
- return m_Handle;
- }
- }
- // Non-blocking I/O control
- /// <devdoc>
- /// <para>
- /// Gets and sets the blocking mode of a socket.
- /// </para>
- /// </devdoc>
- public bool Blocking {
- get {
- //
- // return the user's desired blocking behaviour (not the actual win32 state)
- //
- return willBlock;
- }
- set {
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::set_Blocking() value:" + value.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
- bool current;
- SocketError errorCode = InternalSetBlocking(value, out current);
- if (errorCode!=SocketError.Success) {
- //
- // update our internal state after this socket error and throw
- SocketException socketException = new SocketException(errorCode);
- UpdateStatusAfterSocketError(socketException);
- if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Blocking", socketException);
- throw socketException;
- }
- //
- // win32 call succeeded, update desired state
- //
- willBlock = current;
- }
- }
- #endif // !MONO
- public bool UseOnlyOverlappedIO{
- get {
- //
- // return the user's desired blocking behaviour (not the actual win32 state)
- //
- return useOverlappedIO;
- }
- set {
- #if !MONO
- if (m_BoundToThreadPool) {
- throw new InvalidOperationException(SR.GetString(SR.net_io_completionportwasbound));
- }
- #endif
- useOverlappedIO = value;
- }
- }
- #if !MONO
- /// <devdoc>
- /// <para>
- /// Gets the connection state of the Socket. This property will return the latest
- /// known state of the Socket. When it returns false, the Socket was either never connected
- /// or it is not connected anymore. When it returns true, though, there's no guarantee that the Socket
- /// is still connected, but only that it was connected at the time of the last IO operation.
- /// </para>
- /// </devdoc>
- public bool Connected {
- get {
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connected() m_IsConnected:"+m_IsConnected);
- if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
- {
- // update the state if we've become connected after a non-blocking connect
- m_IsConnected = true;
- m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
- m_NonBlockingConnectInProgress = false;
- }
- return m_IsConnected;
- }
- }
- #endif // !MONO
- /// <devdoc>
- /// <para>
- /// Gets the socket's address family.
- /// </para>
- /// </devdoc>
- public AddressFamily AddressFamily {
- get {
- return addressFamily;
- }
- }
- /// <devdoc>
- /// <para>
- /// Gets the socket's socketType.
- /// </para>
- /// </devdoc>
- public SocketType SocketType {
- get {
- return socketType;
- }
- }
- /// <devdoc>
- /// <para>
- /// Gets the socket's protocol socketType.
- /// </para>
- /// </devdoc>
- public ProtocolType ProtocolType {
- get {
- return protocolType;
- }
- }
- #if !MONO
- public bool IsBound{
- get{
- return (m_RightEndPoint != null);
- }
- }
- #endif // !MONO
- public bool ExclusiveAddressUse{
- get {
- return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse) != 0 ? true : false;
- }
- set {
- if (IsBound) {
- throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotbebound));
- }
- SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
- }
- }
- public int ReceiveBufferSize {
- get {
- return (int)GetSocketOption(SocketOptionLevel.Socket,
- SocketOptionName.ReceiveBuffer);
- }
- set {
- if (value<0) {
- throw new ArgumentOutOfRangeException("value");
- }
- SetSocketOption(SocketOptionLevel.Socket,
- SocketOptionName.ReceiveBuffer, value);
- }
- }
- public int SendBufferSize {
- get {
- return (int)GetSocketOption(SocketOptionLevel.Socket,
- SocketOptionName.SendBuffer);
- }
- set {
- if (value<0) {
- throw new ArgumentOutOfRangeException("value");
- }
- SetSocketOption(SocketOptionLevel.Socket,
- SocketOptionName.SendBuffer, value);
- }
- }
- public int ReceiveTimeout {
- get {
- return (int)GetSocketOption(SocketOptionLevel.Socket,
- SocketOptionName.ReceiveTimeout);
- }
- set {
- if (value< -1) {
- throw new ArgumentOutOfRangeException("value");
- }
- if (value == -1) {
- value = 0;
- }
- SetSocketOption(SocketOptionLevel.Socket,
- SocketOptionName.ReceiveTimeout, value);
- }
- }
- public int SendTimeout {
- get {
- return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
- }
- set {
- if (value< -1) {
- throw new ArgumentOutOfRangeException("value");
- }
- if (value == -1) {
- value = 0;
- }
- SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
- }
- }
- public LingerOption LingerState {
- get {
- return (LingerOption)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
- }
- set {
- SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value);
- }
- }
- #if !MONO
- public bool NoDelay {
- get {
- return (int)GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) != 0 ? true : false;
- }
- set {
- SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
- }
- }
- #endif // !MONO
- public short Ttl{
- get {
- if (addressFamily == AddressFamily.InterNetwork) {
- return (short)(int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
- }
- else if (addressFamily == AddressFamily.InterNetworkV6) {
- return (short)(int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive);
- }
- else{
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- }
- set {
- // valid values are from 0 to 255 since Ttl is really just a byte value on the wire
- if (value < 0 || value > 255) {
- throw new ArgumentOutOfRangeException("value");
- }
- if (addressFamily == AddressFamily.InterNetwork) {
- SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
- }
- else if (addressFamily == AddressFamily.InterNetworkV6) {
- SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive, value);
- }
- else{
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- }
- }
- public bool DontFragment{
- get {
- if (addressFamily == AddressFamily.InterNetwork) {
- return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment) != 0 ? true : false;
- }
- else{
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- }
- set {
- if (addressFamily == AddressFamily.InterNetwork) {
- SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
- }
- else{
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- }
- }
- #if !MONO
- public bool MulticastLoopback{
- get {
- if (addressFamily == AddressFamily.InterNetwork) {
- return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback) != 0 ? true : false;
- }
- else if (addressFamily == AddressFamily.InterNetworkV6) {
- return (int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback) != 0 ? true : false;
- }
- else{
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- }
- set {
- if (addressFamily == AddressFamily.InterNetwork) {
- SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
- }
- else if (addressFamily == AddressFamily.InterNetworkV6) {
- SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
- }
- else{
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- }
- }
- public bool EnableBroadcast{
- get {
- return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast) != 0 ? true : false;
- }
- set {
- SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
- }
- }
- #endif // !MONO
- public bool DualMode {
- get {
- if (AddressFamily != AddressFamily.InterNetworkV6) {
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
- }
- set {
- if (AddressFamily != AddressFamily.InterNetworkV6) {
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
- }
- }
- private bool IsDualMode {
- get {
- return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
- }
- }
- internal bool CanTryAddressFamily(AddressFamily family) {
- return (family == addressFamily) || (family == AddressFamily.InterNetwork && IsDualMode);
- }
- //************* public methods *************************
- #if !MONO
- /// <devdoc>
- /// <para>Associates a socket with an end point.</para>
- /// </devdoc>
- public void Bind(EndPoint localEP) {
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Bind", localEP);
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- //
- // parameter validation
- //
- if (localEP==null) {
- throw new ArgumentNullException("localEP");
- }
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() localEP:" + localEP.ToString());
- EndPoint endPointSnapshot = localEP;
- IPEndPoint ipSnapshot = localEP as IPEndPoint;
- //
- // for now security is implemented only on IPEndPoint
- // If EndPoint is of other type - unmanaged code permisison is demanded
- //
- if (ipSnapshot != null)
- {
- // Take a snapshot that will make it immutable and not derived.
- ipSnapshot = ipSnapshot.Snapshot();
- // DualMode: Do the security check on the users IPv4 address, but map to IPv6 before binding.
- endPointSnapshot = RemapIPEndPoint(ipSnapshot);
- //
- // create the permissions the user would need for the call
- //
- SocketPermission socketPermission
- = new SocketPermission(
- NetworkAccess.Accept,
- Transport,
- ipSnapshot.Address.ToString(),
- ipSnapshot.Port);
- //
- // demand for them
- //
- socketPermission.Demand();
- // Here the permission check has succeded.
- // NB: if local port is 0, then winsock will assign some>1024,
- // so assuming that this is safe. We will not check the
- // NetworkAccess.Accept permissions in Receive.
- }
- else {
- //<
- ExceptionHelper.UnmanagedPermission.Demand();
- }
- //
- // ask the EndPoint to generate a SocketAddress that we
- // can pass down to winsock
- //
- SocketAddress socketAddress = CallSerializeCheckDnsEndPoint(endPointSnapshot);
- DoBind(endPointSnapshot, socketAddress);
- if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Bind", "");
- }
- internal void InternalBind(EndPoint localEP)
- {
- if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "InternalBind", localEP);
- if (CleanedUp)
- {
- throw new ObjectDisposedException(GetType().FullName);
- }
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalBind() localEP:" + localEP.ToString());
- GlobalLog.Assert(!(localEP is DnsEndPoint), "Calling InternalBind with a DnsEndPoint, about to get NotImplementedException");
- //
- // ask the EndPoint to generate a SocketAddress that we
- // can pass down to winsock
- //
- EndPoint endPointSnapshot = localEP;
- SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
- DoBind(endPointSnapshot, socketAddress);
- if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "InternalBind", "");
- }
- private void DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
- {
- // Mitigation for Blue Screen of Death (Win7, maybe others)
- IPEndPoint ipEndPoint = endPointSnapshot as IPEndPoint;
- if (!OSSupportsIPv4 && ipEndPoint != null && ipEndPoint.Address.IsIPv4MappedToIPv6)
- {
- SocketException socketException = new SocketException(SocketError.InvalidArgument);
- UpdateStatusAfterSocketError(socketException);
- if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
- throw socketException;
- }
- // This may throw ObjectDisposedException.
- SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.bind(
- m_Handle,
- socketAddress.m_Buffer,
- socketAddress.m_Size);
- #if TRAVE
- try
- {
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.bind returns errorCode:" + errorCode);
- }
- catch (ObjectDisposedException) { }
- #endif
- //
- // if the native call fails we'll throw a SocketException
- //
- if (errorCode != SocketError.Success)
- {
- //
- // update our internal state after this socket error and throw
- //
- SocketException socketException = new SocketException();
- UpdateStatusAfterSocketError(socketException);
- if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
- throw socketException;
- }
- if (m_RightEndPoint == null)
- {
- //
- // save a copy of the EndPoint so we can use it for Create()
- //
- m_RightEndPoint = endPointSnapshot;
- }
- }
- /// <devdoc>
- /// <para>Establishes a connection to a remote system.</para>
- /// </devdoc>
- public void Connect(EndPoint remoteEP) {
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- //
- // parameter validation
- //
- if (remoteEP==null) {
- throw new ArgumentNullException("remoteEP");
- }
- if(m_IsDisconnected){
- throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedConnect));
- }
- if (isListening)
- {
- throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
- }
- ValidateBlockingMode();
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connect() DST:" + ValidationHelper.ToString(remoteEP));
- DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
- if (dnsEP != null)
- {
- if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily))
- {
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- Connect(dnsEP.Host, dnsEP.Port);
- return;
- }
- //This will check the permissions for connect
- EndPoint endPointSnapshot = remoteEP;
- SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true);
- if (!Blocking)
- {
- m_NonBlockingConnectRightEndPoint = endPointSnapshot;
- m_NonBlockingConnectInProgress = true;
- }
- DoConnect(endPointSnapshot, socketAddress);
- }
- public void Connect(IPAddress address, int port){
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", address);
- if (CleanedUp){
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- //if address family isn't the socket address family throw
- if (address==null) {
- throw new ArgumentNullException("address");
- }
- if (!ValidationHelper.ValidateTcpPort(port)) {
- throw new ArgumentOutOfRangeException("port");
- }
- if (!CanTryAddressFamily(address.AddressFamily)) {
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- IPEndPoint remoteEP = new IPEndPoint(address, port);
- Connect(remoteEP);
- if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
- }
- public void Connect(string host, int port){
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", host);
- if (CleanedUp){
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- if (host==null) {
- throw new ArgumentNullException("host");
- }
- if (!ValidationHelper.ValidateTcpPort(port)){
- throw new ArgumentOutOfRangeException("port");
- }
- if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- IPAddress[] addresses = Dns.GetHostAddresses(host);
- Connect(addresses,port);
- if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
- }
- #endif // !MONO
- public void Connect(IPAddress[] addresses, int port){
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", addresses);
- if (CleanedUp){
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- if (addresses==null) {
- throw new ArgumentNullException("addresses");
- }
- if (addresses.Length == 0) {
- throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_ipaddress_length), "addresses");
- }
- if (!ValidationHelper.ValidateTcpPort(port)) {
- throw new ArgumentOutOfRangeException("port");
- }
- if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
- throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
- }
- Exception lastex = null;
- foreach ( IPAddress address in addresses ) {
- if (CanTryAddressFamily(address.AddressFamily)) {
- try
- {
- Connect(new IPEndPoint(address,port) );
- lastex = null;
- break;
- }
- catch ( Exception ex )
- {
- if (NclUtilities.IsFatal(ex)) throw;
- lastex = ex;
- }
- }
- }
- if ( lastex != null )
- throw lastex;
- //if we're not connected, then we didn't get a valid ipaddress in the list
- if (!Connected) {
- throw new ArgumentException(SR.GetString(SR.net_invalidAddressList), "addresses");
- }
- if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
- }
- #if !MONO
- /// <devdoc>
- /// <para>
- /// Forces a socket connection to close.
- /// </para>
- /// </devdoc>
- public void Close()
- {
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
- if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Close", null);
- ((IDisposable)this).Dispose();
- if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "Close", null);
- }
- public void Close(int timeout)
- {
- if (timeout < -1)
- {
- throw new ArgumentOutOfRangeException("timeout");
- }
- m_CloseTimeout = timeout;
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
- ((IDisposable)this).Dispose();
- }
- /// <devdoc>
- /// <para>
- /// Places a socket in a listening state.
- /// </para>
- /// </devdoc>
- public void Listen(int backlog) {
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Listen", backlog);
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() backlog:" + backlog.ToString());
- // No access permissions are necessary here because
- // the verification is done for Bind
- // This may throw ObjectDisposedException.
- SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.listen(
- m_Handle,
- backlog);
- #if TRAVE
- try
- {
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.listen returns errorCode:" + errorCode);
- }
- catch (ObjectDisposedException) { }
- #endif
- //
- // if the native call fails we'll throw a SocketException
- //
- if (errorCode!=SocketError.Success) {
- //
- // update our internal state after this socket error and throw
- //
- SocketException socketException = new SocketException();
- UpdateStatusAfterSocketError(socketException);
- if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Listen", socketException);
- throw socketException;
- }
- isListening = true;
- if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Listen", "");
- }
- /// <devdoc>
- /// <para>
- /// Creates a new <see cref='Sockets.Socket'/> instance to handle an incoming
- /// connection.
- /// </para>
- /// </devdoc>
- public Socket Accept() {
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Accept", "");
- //
- // parameter validation
- //
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- if (m_RightEndPoint==null) {
- throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
- }
- if(!isListening){
- throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
- }
- if(m_IsDisconnected){
- throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedAccept));
- }
- ValidateBlockingMode();
- GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Accept() SRC:" + ValidationHelper.ToString(LocalEndPoint));
- SocketAddress socketAddress = m_RightEndPoint.Serialize();
- // This may throw ObjectDisposedException.
- SafeCloseSocket acceptedSocketHandle = SafeCloseSocket.Accept(
- m_Handle,
- socketAddress.m_Buffer,
- ref socketAddress.m_Size);
- //
- // if the native call fails we'll throw a SocketException
- //
- if (acceptedSocketHandle.IsInvalid) {
- //
- // update our internal state after this socket error and throw
- //
- SocketException socketException = new SocketException();
- UpdateStatusAfterSocketError(socketException);
- if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Accept", socketException);
- throw socketException;
- }
- Socket socket = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress), false);
- if (s_LoggingEnabled) {
- Logging.PrintInfo(Logging.Sockets, socket, SR.GetString(SR.net_log_socket_accepted, socket.RemoteEndPoint, socket.LocalEndPoint));
- Logging.Exit(Logging.Sockets, this, "Accept", socket);
- }
- return socket;
- }
- #endif // !MONO
- /// <devdoc>
- /// <para>Sends a data buffer to a connected socket.</para>
- /// </devdoc>
- public int Send(byte[] buffer, int size, SocketFlags socketFlags) {
- return Send(buffer, 0, size, socketFlags);
- }
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public int Send(byte[] buffer, SocketFlags socketFlags) {
- return Send(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags);
- }
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public int Send(byte[] buffer) {
- return Send(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None);
- }
- #if !FEATURE_PAL
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public int Send(IList<ArraySegment<byte>> buffers) {
- return Send(buffers,SocketFlags.None);
- }
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) {
- SocketError errorCode;
- int bytesTransferred = Send(buffers, socketFlags, out errorCode);
- if(errorCode != SocketError.Success){
- throw new SocketException(errorCode);
- }
- return bytesTransferred;
- }
- #if !MONO
- public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode) {
- if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Send", "");
- if (CleanedUp) {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- if (buffers==null) {
- throw …
Large files files are truncated, but you can click here to view the full file