/*
* 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;
namespace Org.Mentalis.Security.Ssl {
///
/// Provides secure client connections for TCP network services.
///
public class SecureTcpClient {
///
/// Initializes a new instance of the class.
///
///
/// The default constructor initializes a new SecureTcpClient. You must call the Connect method to establish a remote host connection.
///
public SecureTcpClient() : this(new SecurityOptions(SecureProtocol.None)) {}
///
/// Initializes a new instance of bound to the specified local endpoint.
///
/// The IPEndPoint to which you bind the TCP Socket.
/// is null (Nothing in Visual Basic).
/// An operating system error occurs while accessing the Socket.
public SecureTcpClient(IPEndPoint localEP) : this(localEP, new SecurityOptions(SecureProtocol.None)) {}
///
/// Initializes a new instance of the class and connects to the specified port on the specified host.
///
/// DNS name of the remote host to which you intend to connect.
/// Port number of the remote host to which you intend to connect.
/// is null (Nothing in Visual Basic).
/// is less than MinPort -or- is greater than MaxPort.
/// An error is encountered when resolving
-or-
an error occurred while connecting to the remote host.
/// The security negotiation failed.
public SecureTcpClient(string hostname, int port) : this(hostname, port, new SecurityOptions(SecureProtocol.None)) {}
///
/// Initializes a new instance of the class.
///
/// The security options to use.
public SecureTcpClient(SecurityOptions options) {
m_Client = new SecureSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp, options);
}
///
/// Initializes a new instance of bound to the specified local endpoint.
///
/// The IPEndPoint to which you bind the TCP Socket.
/// The security options to use.
/// is null (Nothing in Visual Basic).
/// An operating system error occurs while accessing the Socket.
public SecureTcpClient(IPEndPoint localEP, SecurityOptions options) : this(options) {
m_Client.Bind(localEP);
}
///
/// Initializes a new instance of the class and connects to the specified port on the specified host.
///
/// DNS name of the remote host to which you intend to connect.
/// Port number of the remote host to which you intend to connect.
/// The security options to use.
/// is null (Nothing in Visual Basic).
/// is less than MinPort -or- is greater than MaxPort.
/// An error is encountered when resolving -or- an error occurred while connecting to the remote host.
/// The security negotiation failed.
public SecureTcpClient(string hostname, int port, SecurityOptions options) : this(options) {
if (hostname == null)
throw new ArgumentNullException();
Connect(hostname, port);
}
///
/// Initializes a new instance of .
///
/// The accepted socket.
/// This constructor is used by the SecureTcpListener class.
internal SecureTcpClient(SecureSocket socket) : base() {
m_Client = socket;
m_Active = true;
}
///
/// Connects the client to a remote TCP host using the specified remote network endpoint.
///
/// The IP endpoint to which you intend to connect.
/// The parameter is a null reference (Nothing in Visual Basic).
/// An operating system error occurs while accessing the Socket.
/// The has been closed.
/// The security negotiation failed.
public virtual void Connect(IPEndPoint remoteEP) {
Client.Connect(remoteEP);
Active = true;
}
///
/// Connects the client to a remote TCP host using the specified IP address and port number.
///
/// The IP address of the host to which you intend to connect.
/// The port number to which you intend to connect.
/// The parameter is a null reference (Nothing in Visual Basic).
/// is less than MinPort -or- is greater than MaxPort.
/// An operating system error occurs while accessing the Socket.
/// The has been closed.
/// The security negotiation failed.
public virtual void Connect(IPAddress address, int port) {
if (address == null)
throw new ArgumentNullException();
Connect(new IPEndPoint(address, port));
}
///
/// Connects the client to the specified port on the specified host.
///
/// The DNS name of the remote host to which you intend to connect.
/// The port number of the remote host to which you intend to connect.
/// The parameter is a null reference (Nothing in Visual Basic).
/// is less than MinPort -or- is greater than MaxPort.
/// An operating system error occurs while accessing the Socket.
/// The has been closed.
/// The security negotiation failed.
public virtual void Connect(string hostname, int port) {
if (hostname == null)
throw new ArgumentNullException();
Connect(Dns.Resolve(hostname).AddressList[0], port);
}
///
/// Returns the stream used to send and receive data.
///
/// The underlying .
/// The has been closed.
/// The SecureTcpClient is not connected to a remote host.
public virtual SecureNetworkStream GetStream() {
if (CleanedUp)
throw new ObjectDisposedException(this.GetType().FullName);
if (!Client.Connected)
throw new InvalidOperationException();
if (DataStream == null) {
DataStream = new SecureNetworkStream(Client, false);
}
return DataStream;
}
///
/// Closes the TCP connection.
///
/// An error occurs while closing the Socket.
public void Close() {
Dispose();
}
///
/// Releases the unmanaged resources used by the and optionally releases the managed resources.
///
protected virtual void Dispose() {
if (!CleanedUp) {
CleanedUp = true;
Active = false;
if (DataStream != null) {
DataStream.Close();
DataStream = null;
}
if (Client.Connected) {
try {
Client.Shutdown(SocketShutdown.Both);
} catch {}
}
Client.Close();
}
}
///
/// Gets or sets information about the sockets linger time.
///
/// A LingerOption.
/// This property controls the length of time that the underlying Socket will remain open after a call to Close, when data remains to be sent. If the Enabled property of the LingerOption is true, then data will continue to be sent to the network with a time out of LingerOption.LingerTime seconds. Once the data is sent, or if the time-out expires, the connection is closed and any unsent data is lost. If the Enabled property of the LingerOption is false , then the connection will close, even if data remains to be sent.
public LingerOption LingerState {
get {
return (LingerOption)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
}
set{
Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value);
}
}
///
/// Gets or sets a value that enables a delay when send or receive buffers are not full.
///
/// true to disable a delay, otherwise false.
/// When NoDelay is false, TCP does not send a packet over the network until it has collected a significant amount of outgoing data. Because of the amount of overhead in a TCP segment, sending small amounts of data would be very inefficient. However, situations do exist where you might want to send very small amounts of data or expect immediate responses from each packet you send. Your decision should weigh the relative importance of network efficiency versus application requirements.
public bool NoDelay {
get {
return !((int)Client.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) == 0);
}
set{
Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
}
}
///
/// Gets or sets the size of the receive buffer.
///
/// The size of the receive buffer, in bytes.
/// The ReceiveBufferSize property gets or sets the number of bytes that you are expecting to store in the receive buffer for each read operation.
public int ReceiveBufferSize {
get {
return (int)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
}
set{
Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
}
}
///
/// Gets or sets the amount of time a will wait to receive data once initiated.
///
/// The time-out value of the connection in milliseconds.
/// The ReceiveTimeout property determines the amount of time a SecureTcpClient will wait to receive data after a read is initiated. This time is measured in milliseconds. The underlying Socket will throw a SocketException if a read is initiated, and the ReceiveTimeout expires.
public int ReceiveTimeout {
get {
return (int)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
}
set{
Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
}
}
///
/// Gets or sets the size of the send buffer.
///
/// The size of the send buffer, in bytes.
/// The SendBufferSize property gets or sets the number of bytes to store in the send buffer for each send operation.
public int SendBufferSize {
get {
return (int)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
}
set{
Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
}
}
///
/// Gets or sets the amount of time a SecureTcpClient will wait to receive confirmation after you initiate a send.
///
/// The send time-out value, in milliseconds.
/// After you initiate a send, the underlying returns the number of bytes actually sent to the host. The SendTimeout property determines the amount of time a TcpClient will wait before receiving the number of bytes returned by the SecureSocket class. The underlying SecureSocket will throw a SocketException if a send is initiated and the SendTimeout expires.
public int SendTimeout {
get {
return (int)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
}
set{
Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
}
}
///
/// Gets or sets the underlying .
///
/// The underlying Network Socket.
/// SecureTcpClient creates a SecureSocket to send and receive data over a network. Classes deriving from SecureTcpClient can use this property to get or set this SecureSocket. Use the underlying SecureSocket returned from Client, if you require access beyond that which SecureTcpClient provides. You can also use Client to set the underlying SecureSocket to an existing SecureSocket. This might be useful if you want to take advantage of the simplicity of SecureTcpClient using a pre-existing SecureSocket.
protected SecureSocket Client {
get {
return m_Client;
}
set {
m_Client = value;
}
}
///
/// Gets or set a value that indicates whether a connection has been made.
///
/// true if the connection has been made; otherwise, false.
/// Classes deriving from SecureTcpClient can use this property to keep track of the underlying connection state.
protected bool Active {
get {
return m_Active;
}
set {
m_Active = value;
}
}
///
/// Gets or sets a value that indicates whether the underlying SecureSocket has been closed or not.
///
/// true if the underlying has been closed, false otherwise.
protected bool CleanedUp{
get {
return m_CleanedUp;
}
set {
m_CleanedUp = value;
}
}
///
/// Gets or sets the underlying associated with this SecureTcpClient.
///
/// An instance of the SecureNetworkStream class.
protected SecureNetworkStream DataStream {
get {
return m_DataStream;
}
set {
m_DataStream = value;
}
}
/// Holds the value of the property.
private bool m_Active = false;
/// Holds the value of the property.
private bool m_CleanedUp = false;
/// Holds the value of the property.
private SecureSocket m_Client;
/// Holds the value of the property.
private SecureNetworkStream m_DataStream = null;
}
}