/* * Mentalis.org Security Library * * Copyright © 2002-2005, The KPD-Team * All rights reserved. * http://www.mentalis.org/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Neither the name of the KPD-Team, nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Net; using System.Net.Sockets; using System.Collections; using Org.Mentalis.Security.Certificates; using Org.Mentalis.Security.Ssl.Shared; namespace Org.Mentalis.Security.Ssl { /// /// Implements the Berkeley sockets interface and optionally encrypts/decrypts transmitted data. /// /// Any public static (Shared in Visual Basic) members of this type are safe for multithreaded operations. Any instance members are not guaranteed to be thread safe. public class SecureSocket : VirtualSocket { /// /// Initializes a new instance of the SecureSocket class. /// /// One of the values. /// One of the values. /// One of the values. /// The combination of addressFamily, socketType, and protocolType results in an invalid socket. /// The SecureSocket will act like a normal Socket and will not use a secure transfer protocol. public SecureSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) : this(addressFamily, socketType, protocolType, new SecurityOptions(SecureProtocol.None)) {} /// /// Initializes a new instance of the SecureSocket class. /// /// One of the values. /// One of the values. /// One of the values. /// The to use. /// An error occurs while changing the security protocol. public SecureSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, SecurityOptions options) : base(addressFamily, socketType, protocolType) { m_SentShutdownNotification = false; ChangeSecurityProtocol(options); } /// /// Initializes a new instance of the SecureSocket class. /// /// The accepted instance. /// The to use. /// An error occurs while changing the security protocol. internal SecureSocket(Socket accepted, SecurityOptions options) : base(accepted) { m_SentShutdownNotification = false; ChangeSecurityProtocol(options); } /// /// Changes the security protocol. This method can only be used to 'upgrade' a connection from no-security to either SSL or TLS. /// /// The new parameters. /// An error occurs while changing the security protocol. /// /// Programs should only call this method if there is no active , , or ! /// public void ChangeSecurityProtocol(SecurityOptions options) { if (options == null) throw new ArgumentNullException(); if (m_Options != null && m_Options.Protocol != SecureProtocol.None) throw new ArgumentException("Only changing from a normal connection to a secure connection is supported."); if (base.ProtocolType != ProtocolType.Tcp && options.Protocol != SecureProtocol.None) throw new SecurityException("Security protocols require underlying TCP connections!"); // check SecurityOptions structure if (options.Protocol != SecureProtocol.None) { if (options.Entity == ConnectionEnd.Server && options.Certificate == null) throw new ArgumentException("The certificate cannot be set to a null reference when creating a server socket."); if (options.Certificate != null && !options.Certificate.HasPrivateKey()) throw new ArgumentException("If a certificate is specified, it must have a private key."); if (((int)options.AllowedAlgorithms & (int)SslAlgorithms.NULL_COMPRESSION) == 0) throw new ArgumentException("The allowed algorithms field must contain at least one compression algorithm."); if (((int)options.AllowedAlgorithms ^ (int)SslAlgorithms.NULL_COMPRESSION) == 0) throw new ArgumentException("The allowed algorithms field must contain at least one cipher suite."); if (options.VerificationType == CredentialVerification.Manual && options.Verifier == null) throw new ArgumentException("A CertVerifyEventHandler is required when using manual certificate verification."); } m_Options = (SecurityOptions)options.Clone(); if (options.Protocol != SecureProtocol.None) { if (this.Connected) m_Controller = new SocketController(this, base.InternalSocket, options); } } /// /// Establishes a connection to a remote device and optionally negotiates a secure transport protocol. /// /// An that represents the remote device. /// The remoteEP parameter is a null reference (Nothing in Visual Basic). /// An operating system error occurs while accessing the . /// The SecureSocket has been closed. /// The security negotiation failed. public override void Connect(EndPoint remoteEP) { if (SecureProtocol == SecureProtocol.None) { base.Connect(remoteEP); } else { this.EndConnect(this.BeginConnect(remoteEP, null, null)); } } /// /// Begins an asynchronous request for a connection to a network device. /// /// An that represents the remote device. /// The delegate. /// An object that contains state information for this request. /// An that references the asynchronous connection. /// is a null reference (Nothing in Visual Basic). /// An operating system error occurs while creating the SecureSocket. /// The SecureSocket has been closed. public override IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state) { if (SecureProtocol == SecureProtocol.None) return base.BeginConnect(remoteEP, callback, state); // secure BeginConnect if (remoteEP == null) throw new ArgumentNullException(); if (m_ConnectResult != null) throw new SocketException(); // BeginConnect already called AsyncResult ret = new AsyncResult(callback, state, null); m_ConnectResult = ret; base.BeginConnect(remoteEP, new AsyncCallback(OnConnect), null); return ret; } /// /// Called then the connects to the remote host. /// /// An instance. private void OnConnect(IAsyncResult ar) { try { base.EndConnect(ar); m_Controller = new SocketController(this, base.InternalSocket, m_Options); } catch (Exception e) { m_ConnectResult.AsyncException = e; } m_ConnectResult.Notify(); } /// /// Ends a pending asynchronous connection request. /// /// The result of the asynchronous operation. /// is a null reference (Nothing in Visual Basic). /// was not returned by a call to the method. /// was previously called for the asynchronous connection. /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// An error occurred while negotiating the security protocol. public override void EndConnect(IAsyncResult asyncResult) { if (SecureProtocol == SecureProtocol.None) { base.EndConnect(asyncResult); return; } // Make sure everything is in order if (asyncResult == null) throw new ArgumentNullException(); if (m_ConnectResult == null) throw new InvalidOperationException(); if (asyncResult != m_ConnectResult) throw new ArgumentException(); // Process the (secure) EndConnect // block if the operation hasn't ended yet AsyncResult ar = m_ConnectResult; if (!ar.IsCompleted) ar.AsyncWaitHandle.WaitOne(); m_ConnectResult = null; if (ar.AsyncException != null) throw ar.AsyncException; } /// /// Creates a new to handle an incoming connection request. /// /// A SecureSocket to handle an incoming connection request. /// The returned can be cast to a SecureSocket if necessary. /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// Unable to create the credentials. public override VirtualSocket Accept() { return EndAccept(BeginAccept(null, null)); } /// /// Begins an asynchronous request to create a new to accept an incoming connection request. /// /// The delegate. /// An object containing state information for this request. /// An that references the asynchronous SecureSocket creation. /// is a null reference (Nothing in Visual Basic). /// An operating system error occurs while creating the SecureSocket. /// The SecureSocket has been closed. public override IAsyncResult BeginAccept(AsyncCallback callback, object state) { if (m_AcceptResult != null) throw new SocketException(); AsyncAcceptResult ret = new AsyncAcceptResult(callback, state, null); m_AcceptResult = ret; base.BeginAccept(new AsyncCallback(this.OnAccept), null); return ret; } private void OnAccept(IAsyncResult ar) { try { m_AcceptResult.AcceptedSocket = new SecureSocket(base.InternalEndAccept(ar), m_Options); } catch (Exception e) { m_AcceptResult.AsyncException = e; } m_AcceptResult.Notify(); } /// /// Ends an asynchronous request to create a new to accept an incoming connection request. /// /// Stores state information for this asynchronous operation as well as any user defined data. /// A SecureSocket to handle the incoming connection. /// The returned can be cast to a SecureSocket if necessary. /// is a null reference (Nothing in Visual Basic). /// was not created by a call to . /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// Unable to create the credentials -or- client authentication error. public override VirtualSocket EndAccept(IAsyncResult asyncResult) { // Make sure everything is in order if (asyncResult == null) throw new ArgumentNullException(); if (m_AcceptResult == null) throw new InvalidOperationException(); if (m_AcceptResult != asyncResult) throw new ArgumentException(); AsyncAcceptResult ar = m_AcceptResult; // Process the (secure) EndAccept // block if the operation hasn't ended yet if (!ar.IsCompleted) ar.AsyncWaitHandle.WaitOne(); m_AcceptResult = null; if (ar.AsyncException != null) throw ar.AsyncException; return ar.AcceptedSocket; } /// /// Sends data to a connected , starting at the indicated location in the data. /// /// The data to be sent. /// The number of bytes sent to the SecureSocket. /// is a null reference (Nothing in Visual Basic). /// The specified size is zero. /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// Unable to encrypt the data. public override int Send(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(); return this.Send(buffer, 0, buffer.Length, SocketFlags.None); } /// /// Sends data to a connected , starting at the indicated location in the data. /// /// The data to be sent. /// A bitwise combination of the values. /// The number of bytes sent to the SecureSocket. /// is a null reference (Nothing in Visual Basic). /// The specified size is zero. /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// Unable to encrypt the data. public override int Send(byte[] buffer, SocketFlags socketFlags) { if (buffer == null) throw new ArgumentNullException(); return this.Send(buffer, 0, buffer.Length, socketFlags); } /// /// Sends data to a connected , starting at the indicated location in the data. /// /// The data to be sent. /// The number of bytes to send. /// A bitwise combination of the values. /// The number of bytes sent to the SecureSocket. /// is a null reference (Nothing in Visual Basic). /// An operating system error occurs while accessing the SecureSocket. /// The size parameter exceeds the size of buffer. /// The specified size is zero. /// The SecureSocket has been closed. /// Unable to encrypt the data. public override int Send(byte[] buffer, int size, SocketFlags socketFlags) { if (buffer == null) throw new ArgumentNullException(); return this.Send(buffer, 0, size, socketFlags); } /// /// Sends data to a connected , starting at the indicated location in the data. /// /// The data to be sent. /// The position in the data buffer to begin sending data. /// The number of bytes to send. /// A bitwise combination of the values. /// The number of bytes sent to the SecureSocket. /// is a null reference (Nothing in Visual Basic). /// An operating system error occurs while accessing the SecureSocket. /// The offset or size parameter exceeds the size of buffer. /// The specified size is zero. /// The SecureSocket has been closed. /// Unable to encrypt the data. public override int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) { if (SecureProtocol == SecureProtocol.None) return base.Send(buffer, offset, size, socketFlags); else return this.EndSend(this.BeginSend(buffer, offset, size, socketFlags, null, null)); } /// /// Sends data asynchronously to a connected . /// /// The data to send. /// The zero-based position in the buffer parameter at which to begin sending data. /// The number of bytes to send. /// A bitwise combination of the values. /// The delegate. /// An object containing state information for this request. /// An that references the asynchronous send. /// is a null reference (Nothing in Visual Basic). /// An operating system error occurs while accessing the SecureSocket. /// The specified offset or size exceeds the size of buffer. /// The specified size is zero. /// The SecureSocket has been closed. /// An error occurred while encrypting the data. public override IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state) { if (SecureProtocol == SecureProtocol.None) return base.BeginSend(buffer, offset, size, socketFlags, callback, state); if (!Connected) throw new SocketException(); if (buffer == null) throw new ArgumentNullException(); if (size == 0) throw new ArgumentException(); if (offset < 0 || offset >= buffer.Length || size > buffer.Length - offset || size < 0) throw new ArgumentOutOfRangeException(); // begin secure send return m_Controller.BeginSend(buffer, offset, size, callback, state); } /// /// Ends a pending asynchronous send. /// /// The result of the asynchronous operation. /// If successful, the number of bytes sent to the SecureSocket. /// is a null reference (Nothing in Visual Basic). /// was not returned by a call to the method. /// was previously called for the asynchronous read. /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// An error occurs while communicating with the remote host. public override int EndSend(IAsyncResult asyncResult) { if (SecureProtocol == SecureProtocol.None) return base.EndSend(asyncResult); if (asyncResult == null) throw new ArgumentNullException(); TransferItem ti = m_Controller.EndSend(asyncResult); if (ti == null) throw new ArgumentException(); if (!ti.AsyncResult.IsCompleted) ti.AsyncResult.AsyncWaitHandle.WaitOne(); if (ti.AsyncResult.AsyncException != null) throw new SecurityException("An error occurs while communicating with the remote host.", ti.AsyncResult.AsyncException); return ti.OriginalSize; } /// /// Receives data from a connected into a specific location of the receive buffer. /// /// The storage location for the received data. /// The number of bytes received. /// is a null reference (Nothing in Visual Basic). /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// An error occurred while decrypting the received data. public override int Receive(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(); return this.Receive(buffer, 0, buffer.Length, SocketFlags.None); } /// /// Receives data from a connected into a specific location of the receive buffer. /// /// The storage location for the received data. /// A bitwise combination of the values. /// The number of bytes received. /// is a null reference (Nothing in Visual Basic). /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// An error occurred while decrypting the received data. public override int Receive(byte[] buffer, SocketFlags socketFlags) { if (buffer == null) throw new ArgumentNullException(); return this.Receive(buffer, 0, buffer.Length, socketFlags); } /// /// Receives data from a connected into a specific location of the receive buffer. /// /// The storage location for the received data. /// The number of bytes to receive. /// A bitwise combination of the values. /// The number of bytes received. /// is a null reference (Nothing in Visual Basic). /// The size exceeds the size of buffer. /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// An error occurred while decrypting the received data. public override int Receive(byte[] buffer, int size, SocketFlags socketFlags) { if (buffer == null) throw new ArgumentNullException(); return this.Receive(buffer, 0, size, socketFlags); } /// /// Receives data from a connected into a specific location of the receive buffer. /// /// The storage location for the received data. /// The location in buffer to store the received data. /// The number of bytes to receive. /// A bitwise combination of the values. /// The number of bytes received. /// is a null reference (Nothing in Visual Basic). /// The size exceeds the size of buffer. /// An operating system error occurs while accessing the SecureSocket. /// The SecureSocket has been closed. /// An error occurred while decrypting the received data. public override int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags) { if (SecureProtocol == SecureProtocol.None) { return base.Receive(buffer, offset, size, socketFlags); } else { return this.EndReceive(this.BeginReceive(buffer, offset, size, socketFlags, null, null)); } } /// /// Begins to asynchronously receive data from a connected SecureSocket. /// /// The storage location for the received data. /// The zero-based position in the buffer parameter at which to store the received data. /// The number of bytes to receive. /// A bitwise combination of the values. /// The delegate. /// An object containing state information for this request. /// An that references the asynchronous read. /// is a null reference (Nothing in Visual Basic). /// An operating system error occurs while accessing the SecureSocket. /// SecureSocket has been closed. /// The offset parameter is outside the bounds of buffer or size is either smaller or larger than the buffer size. public override IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state) { if (SecureProtocol == SecureProtocol.None) return base.BeginReceive(buffer, offset, size, socketFlags, callback, state); if (!Connected && m_SentShutdownNotification) throw new SocketException(); if (buffer == null) throw new ArgumentNullException(); if (offset < 0 || (offset >= buffer.Length && size != 0) || size > buffer.Length - offset) throw new ArgumentOutOfRangeException(); return m_Controller.BeginReceive(buffer, offset, size, callback, state); } /// /// Ends a pending asynchronous read. /// /// Stores state information for this asynchronous operation as well as any user defined data. /// The number of bytes received. /// is a null reference (Nothing in Visual Basic). /// was not returned by a call to the method. /// was previously called for the asynchronous read. /// An operating system error occurs while accessing the socket. /// The has been closed. /// An error occurs while communicating with the remote host. public override int EndReceive(IAsyncResult asyncResult) { if (SecureProtocol == SecureProtocol.None) return base.EndReceive(asyncResult); // Make sure everything is in order if (asyncResult == null) throw new ArgumentNullException(); TransferItem ti = m_Controller.EndReceive(asyncResult); if (ti == null) throw new ArgumentException(); // Process the (secure) EndReceive // block if the operation hasn't ended yet if (!ti.AsyncResult.IsCompleted) ti.AsyncResult.AsyncWaitHandle.WaitOne(); if (ti.AsyncResult.AsyncException != null) throw new SecurityException("An error occurs while communicating with the remote host.\r\n" + ti.AsyncResult.AsyncException.ToString(), ti.AsyncResult.AsyncException); if (ti.Transferred == 0) m_SentShutdownNotification = true; return ti.Transferred; } /// /// Shuts down the secure connection. /// /// SecureSocket has been closed. /// An operating system error occurs while accessing the SecureSocket. /// An error occurs while shutting the secure connection down. public override void Shutdown(SocketShutdown how) { this.EndShutdown(this.BeginShutdown(null, null)); } /// /// Begins an asynchronous request to shut the connection down. /// /// The delegate. /// An object containing state information for this request. /// An that references the asynchronous shutdown. /// has already been called. // Thanks to Michael J. Moore and Stefan Bernbo for notifying us about a bug in this method. public IAsyncResult BeginShutdown(AsyncCallback callback, object state) { if (m_ShutdownResult != null) throw new InvalidOperationException(); AsyncResult ar = new AsyncResult(callback, state, null); m_ShutdownResult = ar; if (!this.Connected) { ar.Notify(null); } else if (SecureProtocol == SecureProtocol.None) { base.Shutdown(SocketShutdown.Both); ar.Notify(null); } else { m_Controller.BeginShutdown(new AsyncCallback(this.OnShutdown), null); } return ar; } /// /// Called when the shutdown data has been sent to the remote server. /// /// An instance. private void OnShutdown(IAsyncResult ar) { try { m_Controller.EndShutdown(ar); } catch { // eat exceptions; we don't throw them in Socket.EndShutdown [not really important] // m_ShutdownResult.AsyncException = e; } m_ShutdownResult.Notify(); } /// /// Ends an asynchronous request to shut the connection down. /// /// An that references the asynchronous shutdown. /// is a null reference (Nothing in Visual Basic). /// has not been called first. /// has not been returned by a call to . public void EndShutdown(IAsyncResult asyncResult) { if (asyncResult == null) throw new ArgumentNullException(); if (m_ShutdownResult == null) throw new InvalidOperationException(); if (asyncResult != m_ShutdownResult) throw new ArgumentException(); // Process the EndSecureShutdown // block if the operation hasn't ended yet AsyncResult ar = m_ShutdownResult; if (!ar.IsCompleted) ar.AsyncWaitHandle.WaitOne(); m_ShutdownResult = null; //if (ar.AsyncException != null) // eat exceptions; they're not really important // throw ar.AsyncException; } /// /// Gets the amount of data that has been received from the network and is available to be read. /// /// The number of bytes of data that has been received from the network and are available to be read. /// The SecureSocket has been closed. /// An operating system error occurs while accessing the SecureSocket. /// An error occurs while interpreting the security data. public override int Available { get { if (SecureProtocol == SecureProtocol.None) return base.Available; if (m_IsDisposed) throw new ObjectDisposedException(this.GetType().FullName); // if (!Connected) // closed socket doesn't mean there are no bytes in the decrypted buffer // throw new SocketException(); return m_Controller.Available; } } /// /// Queues a renegotiation request. /// /// An operating system error occurs while accessing the SecureSocket. /// /// Use the QueueRenegotiate function with caution. Some SSL/TLS clients or server do not support renegotiation. /// For instance, requesting a renegotiation in the middle of sending a HTTP request to a MS IIS server causes the connection to be shut down. /// Renegotiations should only be used when a small private key [512 bits] is used and the connection is active for a long period of time. /// public void QueueRenegotiate() { if (!Connected) throw new SocketException(); m_Controller.QueueRenegotiate(); } /// /// Forces a SecureSocket connection to close. /// public override void Close() { base.Close(); if (!m_IsDisposed) { if (m_Controller != null) m_Controller.Dispose(); m_IsDisposed = true; } } /// /// Frees resources used by the class. /// /// /// The SecureSocket class finalizer calls the Close method to close the SecureSocket and free resources associated with the SecureSocket. /// ~SecureSocket() { Close(); } /// /// Gets the local certificate. /// /// An instance of the class. public Certificate LocalCertificate { get { return m_Options.Certificate; } } /// /// Gets the remote certificate. /// /// An instance of the class -or- a null reference (Nothing in Visual Basic) if no certificate has been received. public Certificate RemoteCertificate { get { if (m_Controller == null) return null; return m_Controller.RemoteCertificate; } } /// /// Gets the security protocol in use. /// /// A bitwise combination of the values. public SecureProtocol SecureProtocol { get { return m_Options.Protocol; } } /// /// Gets the credential type. /// /// One of the values. public ConnectionEnd Entity { get { return m_Options.Entity; } } /// /// Gets the common name of the remote host. /// /// A string representing the common name of the remote host. /// /// The common name of the remote host is usually the domain name. /// public string CommonName { get { return m_Options.CommonName; } } /// /// Gets the credential verification type. /// /// One of the values. public CredentialVerification VerificationType { get { return m_Options.VerificationType; } } /// /// Gets the verify delegate. /// /// A instance. public CertVerifyEventHandler Verifier { get { return m_Options.Verifier; } } /// /// Gets the security flags of the connection. /// /// A bitwise combination of the values. public SecurityFlags SecurityFlags { get { return m_Options.Flags; } } /// /// Gets the active encryption cipher suite. /// /// One of the values. /// /// This value is properly initialized after the handshake of the SSL or TLS protocol. Currently, there's no way of knowing when a handshake is completed. However as soon as either a Send or a Receive returns, the handshake must be complete. ///

If SSL or TLS is not used, this property returns SslAlgorithms.NONE.

///
public SslAlgorithms ActiveEncryption { get { if (m_Controller == null) return SslAlgorithms.NONE; return m_Controller.ActiveEncryption; } } private SocketController m_Controller; private SecurityOptions m_Options; private AsyncAcceptResult m_AcceptResult; private AsyncResult m_ConnectResult; private AsyncResult m_ShutdownResult; private bool m_SentShutdownNotification; private bool m_IsDisposed; /// /// Gets or sets a value that indicates whether the VirtualSocket is in blocking mode. /// /// true if the VirtualSocket will block; otherwise, false. The default is true. /// This property is not supported for SSL/TLS sockets. It can only be used if the SecureProtocol is set to None. Asynchronous behavior in SSL or TLS mode can be achieved by calling the asynchronous methods. /// An operating system error occurs while accessing the VirtualSocket. /// The VirtualSocket has been closed. /// Non-blocking sockets are not supported in SSL or TLS mode. public override bool Blocking { get { return base.Blocking; } set { if (!value && SecureProtocol != SecureProtocol.None) throw new NotSupportedException("Non-blocking sockets are not supported in SSL or TLS mode. Use the asynchronous methods instead."); base.Blocking = value; } } /// /// Determines the status of the VirtualSocket. /// /// The time to wait for a response, in microseconds. /// One of the values. /// See the Socket documentation for the return values. /// This property is not supported for SSL/TLS sockets. It can only be used if the SecureProtocol is set to None. Asynchronous behavior in SSL or TLS mode can be achieved by calling the asynchronous methods. /// The mode parameter is not one of the SelectMode values -or- the socket is in SSL or TLS mode. /// An operating system error occurs while accessing the VirtualSocket. /// The VirtualSocket has been closed. /// Set microSeconds parameter to a negative integer if you would like to wait indefinitely for a response. public override bool Poll(int microSeconds, SelectMode mode) { if (SecureProtocol != SecureProtocol.None) throw new NotSupportedException("The Poll method is not supported in SSL or TLS mode. Use the asynchronous methods and the Available property instead."); return base.Poll(microSeconds, mode); } } }