﻿Option Strict On
Option Explicit On
Option Infer Off

Namespace Networking.RattleSnake.EventArgs

    'Connector

    ''' <summary>
    ''' Contains the arguments for when a RattleSnake Connector has connected successfully to a server.
    ''' </summary>
    ''' <remarks>A similar class is used for when a RattleSnake Client has connected successfully to a server.</remarks>
    Public Class RattleSnakeConnectorConnectedEventArgs
        Inherits System.EventArgs

        ''' <summary>
        ''' The resulting client that is created because of the newly established connection.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The newly created client that holds a connection to the server.</returns>
        ''' <remarks>The returned property always holds a client that has a connection to the server.</remarks>
        Public Property Client As RattleSnakeClient

        ''' <summary>
        ''' The remote IP address that the connection is located on.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>An IP address of the remote RattleSnake Server</returns>
        ''' <remarks></remarks>
        Public Property IP As String

        ''' <summary>
        ''' The remote port that the connection is located on.
        ''' </summary>
        ''' <value>Integer</value>
        ''' <returns>The port used while connecting to the server.</returns>
        ''' <remarks></remarks>
        Public Property Port As Integer

    End Class

    ''' <summary>
    ''' Contains the data to pass during an async connection routine.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeConnectorAsyncData

        ''' <summary>
        ''' The TcpClient that is performing the connection
        ''' </summary>
        ''' <value>TcpClient</value>
        ''' <returns>The TcpClient that now contains an active connection to the RattleSnake Server</returns>
        ''' <remarks></remarks>
        Public Property Client As Net.Sockets.TcpClient

        ''' <summary>
        ''' The remote IP address that the connection is located on.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>An IP address of the remote RattleSnake Server</returns>
        ''' <remarks></remarks>
        Public Property IP As String

        ''' <summary>
        ''' The remote port that the connection is located on.
        ''' </summary>
        ''' <value>Integer</value>
        ''' <returns>The port used while connecting to the server.</returns>
        ''' <remarks></remarks>
        Public Property Port As Integer

    End Class

    'Client

    ''' <summary>
    ''' Contains the necessary information for when a connection times out either when sending, receiving, or connecting.
    ''' </summary>
    ''' <remarks>These event arguments contain all the information for when a connection times out, such as if it was sending, receiving, or connecting and the server IP.</remarks>
    Public Class RattleSnakeConnectionTimedOutEventArgs

        ''' <summary>
        ''' The enumeration that provides quick access to the different types of timeouts that can occur.
        ''' </summary>
        ''' <remarks>This enum is simply a list of Integers for remembering the different types.</remarks>
        Public Enum TType

            ''' <summary>
            ''' The connection timed out while sending data across the stream.
            ''' </summary>
            ''' <remarks></remarks>
            Sending

            ''' <summary>
            ''' The connection timed out while receiving data from the stream.
            ''' </summary>
            ''' <remarks></remarks>
            Receiving

            ''' <summary>
            ''' The connection timed out while trying to connect to the server.
            ''' </summary>
            ''' <remarks></remarks>
            Connecting

        End Enum

        ''' <summary>
        ''' The server IP address that the timeout occurred on.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>The server that the RattleSnake Client or Connector is trying to work with.</returns>
        ''' <remarks>Just a plain-text string, IPv4</remarks>
        Public Property IP As String

        ''' <summary>
        ''' The remote port that the connection is located on.
        ''' </summary>
        ''' <value>Integer</value>
        ''' <returns>The port used while connecting to the server.</returns>
        ''' <remarks></remarks>
        Public Property Port As Integer

        ''' <summary>
        ''' Retrieves or sets the time of timeout that occurred.
        ''' </summary>
        ''' <value>TType</value>
        ''' <returns>A plain-text answer that spells out the type of timeout that occurred.</returns>
        ''' <remarks></remarks>
        Public Property TimeoutType As TType

        ''' <summary>
        ''' The specific exception data that travels up with the event arguments
        ''' </summary>
        ''' <value>Exception</value>
        ''' <returns>Specific exception data that is used during debugging</returns>
        ''' <remarks></remarks>
        Public Property Exception As Exception

    End Class

    ''' <summary>
    ''' Contains the data to pass up whenever data is received.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeClientIncomingDataEventArgs
        Inherits System.EventArgs

        ''' <summary>
        ''' The initial byte array that contains the raw data.
        ''' </summary>
        ''' <value>Byte()</value>
        ''' <returns>A byte array that is the raw data from the RattleSnake Server.</returns>
        ''' <remarks></remarks>
        Public Property Data As Byte()

        ''' <summary>
        ''' An object that represents a de-serialized version of the Data array.
        ''' </summary>
        ''' <value>Object</value>
        ''' <returns>This property could return any variety of objects if the byte array does in fact contain data that can be de-serialized.</returns>
        ''' <remarks>This will only return an object if and only if the data array can in fact be deserialized.</remarks>
        Public ReadOnly Property Obj As Object

            Get

                'Create the memory stream
                Dim _ms As New IO.MemoryStream(Data)

                'Create the deserializer
                Dim _deserializer As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

                'Try

                'Try deserializing
                Dim _obj As Object = _deserializer.Deserialize(_ms)

                'Close the memory stream
                _ms.Close()

                'Return the object
                Return _obj

                'Catch ex As System.Runtime.Serialization.SerializationException

                '    'The data cannot be deserialized, return nothing
                '    Return Nothing

                'End Try

            End Get

        End Property

        ''' <summary>
        ''' The originating client that received the data.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The Client that has received the information.</returns>
        ''' <remarks></remarks>
        Public Property Client As RattleSnakeClient

    End Class

    ''' <summary>
    ''' Contains the data of the connection that terminated.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeClientDisconnectionEventArgs
        Inherits System.EventArgs

        ''' <summary>
        ''' The server IP address that the connection was established on.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>The server that the RattleSnake Client disconnected from.</returns>
        ''' <remarks>Just a plain-text string, IPv4</remarks>
        Public Property IP As String

        ''' <summary>
        ''' The remote port that the connection is located on.
        ''' </summary>
        ''' <value>Integer</value>
        ''' <returns>The port used while connecting to the server.</returns>
        ''' <remarks></remarks>
        Public Property Port As Integer

        ''' <summary>
        ''' The originating client that received the data.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The Client that has received the information.</returns>
        ''' <remarks></remarks>
        Public Property Client As RattleSnakeClient

    End Class

    ''' <summary>
    ''' Contains the exception data that caused the client to crash.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeClientExceptionEventArgs
        Inherits System.EventArgs

        ''' <summary>
        ''' The originating client that the exception came from.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The client that the exception spawned from.</returns>
        ''' <remarks></remarks>
        Public Property Client As RattleSnakeClient

        ''' <summary>
        ''' The root exception that crashed out the client.
        ''' </summary>
        ''' <value>Exception</value>
        ''' <returns>Exception details about the crash.</returns>
        ''' <remarks></remarks>
        Public Property Data As Exception

    End Class

    'Server

    ''' <summary>
    ''' Contains the data that is passed when a RattleSnakeClient connects to the RattleSnakeServer.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeServerIncomingConnectionEventArgs
        Inherits System.EventArgs

        ''' <summary>
        ''' The client that has connected to the RattleSnakeServer.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The client that has connected to the server.</returns>
        ''' <remarks></remarks>
        Public Property Client As RattleSnakeClient

    End Class

    ''' <summary>
    ''' Contains the data that a server will pass up whenever a client receives incoming data.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeServerIncomingDataEventArgs
        Inherits System.EventArgs

        ''' <summary>
        ''' The source client that has received the data.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The RattleSnakeClient that has received the data.</returns>
        ''' <remarks></remarks>
        Public Property Client As RattleSnakeClient

        ''' <summary>
        ''' The actual data that the client has received.
        ''' </summary>
        ''' <value>RattleSnakeClientIncomingDataEventArgs</value>
        ''' <returns>The combined class that contains the physical data that the client has received.</returns>
        ''' <remarks></remarks>
        Public Property Data As RattleSnakeClientIncomingDataEventArgs

    End Class

    ''' <summary>
    ''' Contains the information from the client that has disconnected.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeServerClientDisconnectionEventArgs
        Inherits System.EventArgs

        ''' <summary>
        ''' The originating client that has disconnected from the system.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The RattleSnakeClient that has disconnected.</returns>
        ''' <remarks></remarks>
        Public Property Client As RattleSnakeClient

    End Class

    ''' <summary>
    ''' Contains the information from a client throwing an exception and crashing out.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeServerClientExceptionEventArgs

        ''' <summary>
        ''' The originating client that has disconnected from the system.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The RattleSnakeClient that has disconnected.</returns>
        ''' <remarks></remarks>
        Public Property Client As RattleSnakeClient

        ''' <summary>
        ''' The exception information which includes a reference to the client that has thrown an exception.
        ''' </summary>
        ''' <value>RattleSnakeClientExceptionEventArgs</value>
        ''' <returns>A class that contains the originating exception and the source client that crashed.</returns>
        ''' <remarks></remarks>
        Public Property Data As RattleSnakeClientExceptionEventArgs

    End Class

End Namespace

Namespace Networking.RattleSnake.Exceptions

    ''' <summary>
    ''' The base exception for all RattleSnake Exceptions. All exceptions MUST INHERIT this class.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeException
        Inherits Exception

        ''' <summary>
        ''' The InnerException that contains additional information about a crash.
        ''' </summary>
        ''' <value>Exception</value>
        ''' <returns>Additional exception details about a crash.</returns>
        ''' <remarks></remarks>
        Public Shadows Property InnerException As Exception

        ''' <summary>
        ''' A plain-text error message that assists in debugging the exception.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>A complete error message that provides an overview of the exception.</returns>
        ''' <remarks></remarks>
        Public Shadows Property Message As String

    End Class

    ''' <summary>
    ''' An exception that is thrown whenever the RattleSnakeServer attempts to initialize itself but fails.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class RattleSnakeInitializationException
        Inherits RattleSnakeException

        ' ''' <summary>
        ' ''' The InnerException that contains additional information about a crash.
        ' ''' </summary>
        ' ''' <value>Exception</value>
        ' ''' <returns>Additional exception details about a crash.</returns>
        ' ''' <remarks></remarks>
        'Public Shadows Property InnerException As Exception

        ' ''' <summary>
        ' ''' A plain-text error message that assists in debugging the exception.
        ' ''' </summary>
        ' ''' <value>String</value>
        ' ''' <returns>A complete error message that provides an overview of the exception.</returns>
        ' ''' <remarks></remarks>
        'Public Shadows Property Message As String

    End Class

End Namespace

Namespace Networking.RattleSnake.Structures

    ''' <summary>
    ''' This structure is used to signal a disconnect from the system.
    ''' </summary>
    ''' <remarks></remarks>
    <Serializable()>
    Public Structure Disconnect
    End Structure

    ''' <summary>
    ''' A serializable structure that is used to transmit data across the Internet using RattleSnake.
    ''' </summary>
    ''' <remarks></remarks>
    <Serializable()> _
    Public Structure Message

        ''' <summary>
        ''' The name of the person sending the message.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>The name of the sender.</returns>
        ''' <remarks></remarks>
        Public Property Name As String

        ''' <summary>
        ''' The physical message that <paramref>Name</paramref> has sent.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>The message that was sent.</returns>
        ''' <remarks></remarks>
        Public Property Message As String

    End Structure

End Namespace

Namespace Networking.RattleSnake

    ''' <summary>
    ''' The RattleSnake server. The RS server manages all the connected RS clients and keeps track of the data transmitted between them.
    ''' </summary>
    ''' <remarks>The server is fully multi-threaded and takes care of all the connection and disconnection routines.</remarks>
    Public Class RattleSnakeServer

        ''' <summary>
        ''' This routine is called whenever the system has an incoming connection.
        ''' </summary>
        ''' <param name="IR">The Async result of the client.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnIncomingConnection(ByVal IR As IAsyncResult)

            Try

                'Make sure the listener is still something
                If _listener IsNot Nothing Then

                    'End the connection
                    Dim _client As System.Net.Sockets.TcpClient = _listener.EndAcceptTcpClient(IR)

                    'Make sure the client is actually a client
                    If _client IsNot Nothing Then

                        'Create a new client
                        Dim _rsc As New RattleSnakeClient(_client, String.Empty, Me.Port)

                        'Lock
                        SyncLock _clients

                            'Add it to the system
                            _clients.Add(_rsc)

                        End SyncLock

                        'Raise the event
                        RaiseEvent ClientConnection(Me, New EventArgs.RattleSnakeServerIncomingConnectionEventArgs With {.Client = _rsc})

                    End If

                    'Begin listening again
                    _listener.BeginAcceptTcpClient(New AsyncCallback(AddressOf OnIncomingConnection), _listener)

                End If

            Catch ex As Exception

                'Generic RattleSnake error
                Throw New Exceptions.RattleSnakeException With {.InnerException = ex, .Message = ex.Message}

            End Try

        End Sub

        ''' <summary>
        ''' This routine is called whenever the system has an incoming message.
        ''' </summary>
        ''' <param name="sender">The source client that has received the incoming message.</param>
        ''' <param name="e">The event arguments that contain the received data.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnIncomingData(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientIncomingDataEventArgs)

            'Create the new event argument structure
            Dim _new As New EventArgs.RattleSnakeServerIncomingDataEventArgs With {.Data = e, .Client = CType(sender, RattleSnakeClient)}

            'Raise the event
            RaiseEvent IncomingData(Me, _new)

        End Sub

        ''' <summary>
        ''' This routine is called whenever the system has a client disconnect.
        ''' </summary>
        ''' <param name="sender">The client that has disconnected.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnClientDisconnection(ByVal sender As Object)

            'Raise an event
            RaiseEvent ClientDisconnection(Me, New EventArgs.RattleSnakeServerClientDisconnectionEventArgs With {.Client = CType(sender, RattleSnakeClient)})

        End Sub

        ''' <summary>
        ''' This routine is called whenever the system has a client that throws an exception.
        ''' </summary>
        ''' <param name="sender">The client that has thrown the exception.</param>
        ''' <param name="e">The originating exception data that traveled up with the client.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnClientException(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientExceptionEventArgs)

            'Raise the new event
            RaiseEvent ClientException(Me, New EventArgs.RattleSnakeServerClientExceptionEventArgs With {.Client = CType(sender, RattleSnakeClient), .Data = e})

        End Sub


        ''' <summary>
        ''' The port that the server will utilize.
        ''' </summary>
        ''' <remarks></remarks>
        Private _sP As Integer

        ''' <summary>
        ''' The TcpListener that will monitor for incoming connections.
        ''' </summary>
        ''' <remarks>The listener will keep an eye out for any incoming connections to port 6110.</remarks>
        Private _listener As Net.Sockets.TcpListener

        ''' <summary>
        ''' A complete list of all connected RattleSnake Clients.
        ''' </summary>
        ''' <remarks>The list should be kept in-sync with what is actually connected to the server.</remarks>
        Private _clients As List(Of RattleSnakeClient)


        ''' <summary>
        ''' This event is raised whenever the system has a client that receives incoming data.
        ''' </summary>
        ''' <param name="sender">The originating server that processed the incoming data request.</param>
        ''' <param name="e">The physical incoming data, including a reference to the client that accepted the data.</param>
        ''' <remarks></remarks>
        Public Event IncomingData(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeServerIncomingDataEventArgs)

        ''' <summary>
        ''' This event is raised whenever the system has a client that has disconnected.
        ''' </summary>
        ''' <param name="sender">The originating server that the client has disconnected from.</param>
        ''' <param name="e">The disconnection information event arguments</param>
        ''' <remarks></remarks>
        Public Event ClientDisconnection(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeServerClientDisconnectionEventArgs)

        ''' <summary>
        ''' This event is raised whenever the system has a client that throws an exception.
        ''' </summary>
        ''' <param name="sender">The originating server that the client has thrown an exception on.</param>
        ''' <param name="e">The exception data which includes a reference to the source client that has thrown the actual exception.</param>
        ''' <remarks></remarks>
        Public Event ClientException(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeServerClientExceptionEventArgs)

        ''' <summary>
        ''' This event is raised whenever the system has a client connect successfully.
        ''' </summary>
        ''' <param name="sender">The originating server that the client has connected on.</param>
        ''' <param name="e">The event arguments that contain a reference to the client that has connected successfully.</param>
        ''' <remarks></remarks>
        Public Event ClientConnection(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeServerIncomingConnectionEventArgs)


        ''' <summary>
        ''' Retrieves the IP addrss of this server.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared ReadOnly Property GetExternalIP As String

            Get

                Try

                    'Return a reader
                    Return New IO.StreamReader(System.Net.HttpWebRequest.Create("http://whatismyip.com/automation/n09230945.asp").GetResponse().GetResponseStream()).ReadToEnd

                Catch ex As Exception

                    'An error :(
                    Return String.Empty

                End Try

            End Get

        End Property

        ''' <summary>
        ''' Retrieves the port that the RattleSnakeServer will listen to for connections.
        ''' </summary>
        ''' <value>Integer</value>
        ''' <returns>The port that the underlying TcpListener is listening on</returns>
        ''' <remarks>This is a Read-Only field</remarks>
        Public ReadOnly Property Port As Integer

            Get

                'Return the port that was used during initialization
                Return _sP

            End Get

        End Property

        ''' <summary>
        ''' Retrieves the list of currently connected clients
        ''' </summary>
        ''' <value>List of RattleSnakeClients</value>
        ''' <returns>The list of connected clients</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Clients As List(Of RattleSnakeClient)

            Get
                Return _clients
            End Get

        End Property


        ''' <summary>
        ''' Initializes the RattleSnake Server
        ''' </summary>
        ''' <remarks>The RattleSnake Server is initialized using the default properties with the port being 6110 and will listen on all IP-Address ranges that it has access to.</remarks>
        Public Sub New()

            'Initialize
            Me.New(6110I)

        End Sub

        ''' <summary>
        ''' Initializes the RattleSnake Server
        ''' </summary>
        ''' <param name="_port">The port that the server will listen for incoming connections on.</param>
        ''' <remarks>The RattleSnake Server is initialized using the specified port and will listen on all IP-Address ranges that it has access to.</remarks>
        Public Sub New(ByVal _port As Integer)

            'Assign the variable
            _sP = _port

            'Initialize the listener
            _listener = New Net.Sockets.TcpListener(System.Net.IPAddress.Any, _sP)

            'Initailize the client list
            _clients = New List(Of RattleSnakeClient)

        End Sub


        ''' <summary>
        ''' Creates a new RattleSnakeServer that is ready to be started.
        ''' </summary>
        ''' <returns>RattleSnakeServer</returns>
        ''' <remarks>A simple function that makes the initialization process of a RattleSnakeServer simpler.</remarks>
        Public Shared Function CreateServer() As RattleSnakeServer

            'Return a new RattleSnakeServer
            Return RattleSnakeServer.CreateServer(6110)

        End Function

        ''' <summary>
        ''' Creates a new RattleSnakeServer that is ready to be started.
        ''' </summary>
        ''' <returns>RattleSnakeServer</returns>
        ''' <param name="_port">The port that the new server will listen on.</param>
        ''' <remarks>A simple function that makes the initialization process of a RattleSnakeServer simpler.</remarks>
        Public Shared Function CreateServer(ByVal _port As Integer) As RattleSnakeServer

            'Return a new server
            Return New RattleSnakeServer(_port)

        End Function


        ''' <summary>
        ''' Activates the underlying TcpListener
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub BeginListening()

            Try

                'Run the server
                _listener.Start(500I)

                'Now begin accepting incoming connections
                _listener.BeginAcceptTcpClient(New AsyncCallback(AddressOf OnIncomingConnection), _listener)

            Catch ex As Exception

                'Trap and throw another exception
                Throw New RattleSnake.Exceptions.RattleSnakeInitializationException With {.InnerException = ex, .Message = ex.Message}

            End Try

        End Sub

        ''' <summary>
        ''' De-activates the underlying TcpListener
        ''' </summary>
        ''' <remarks>Terminates the listener</remarks>
        Public Sub EndListening()

            'Disable the listener
            _listener.Stop()

        End Sub


        ''' <summary>
        ''' Activates or deactivates the handlers of a client
        ''' </summary>
        ''' <param name="reg">If true, the handles are registered. If false, the handles are removed.</param>
        ''' <param name="_cli">The RattleSnakeClient that will have its handles modified.</param>
        ''' <remarks></remarks>
        Private Sub [Handles](ByVal reg As Boolean, ByRef _cli As RattleSnakeClient)

            'Check
            If reg Then

                'Add
                AddHandler _cli.Crash, AddressOf _Crash
                AddHandler _cli.Disconnected, AddressOf _Disconnected
                AddHandler _cli.IncomingData, AddressOf _IncomingData

            Else

                'Remove
                RemoveHandler _cli.Crash, AddressOf _Crash
                RemoveHandler _cli.Disconnected, AddressOf _Disconnected
                RemoveHandler _cli.IncomingData, AddressOf _IncomingData

            End If

        End Sub


        Private Sub _Crash(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientExceptionEventArgs)

            'The client has crashed, remove its handlers
            [Handles](False, e.Client)

            'Raise the event
            Me.OnClientException(sender, e)

            'Now, remove it from the main list
            SyncLock _clients

                'Remove
                _clients.Remove(e.Client)

            End SyncLock

            'All done
            e.Client.Disconnect(RattleSnakeClient.DisconnectOptions.DoNotSend)

        End Sub

        Private Sub _Disconnected(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientDisconnectionEventArgs)

            'The client has crashed, remove its handlers
            [Handles](False, CType(sender, RattleSnakeClient))

            'Raise the event
            Me.OnClientDisconnection(sender)

            'Now, remove it from the main list
            SyncLock _clients

                'Remove
                _clients.Remove(CType(sender, RattleSnakeClient))

            End SyncLock

        End Sub

        Private Sub _IncomingData(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientIncomingDataEventArgs)

            'Raise the event
            Me.OnIncomingData(sender, e)

        End Sub

    End Class

    ''' <summary>
    ''' A Peer to Peer version of the RattleSnakeServer. This will keep track of one RattleSnakeClient to allow single communication between two people.
    ''' </summary>
    ''' <remarks>The server is fully multi-threaded and takes care of all the connection and disconnection routines.</remarks>
    Public Class RattleSnakeP2PServer

        ''' <summary>
        ''' The listener that is responsible for managing incoming connections.
        ''' </summary>
        ''' <remarks></remarks>
        Private _listener As Net.Sockets.TcpListener

        ''' <summary>
        ''' The connected RattleSnakeClient that the P2P Server is responsible for.
        ''' </summary>
        ''' <remarks></remarks>
        Private _client As RattleSnakeClient

        ''' <summary>
        ''' The port that the server will listen on.
        ''' </summary>
        ''' <remarks></remarks>
        Private _port As Integer


        ''' <summary>
        ''' Retrieves the port that the Peer to Peer server is listening on.
        ''' </summary>
        ''' <value>Integer</value>
        ''' <returns>An Integer that represents the port that the server is listening on.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Port As Integer

            Get
                Return _port
            End Get

        End Property

        ''' <summary>
        ''' Retrieves the currently connected client.
        ''' </summary>
        ''' <value>RattleSnakeClient</value>
        ''' <returns>The client that has an active connection with the server.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Client As RattleSnakeClient
            Get
                Return _client
            End Get
        End Property


        ''' <summary>
        ''' This routine is called whenever the system has an incoming connection.
        ''' </summary>
        ''' <param name="IR">The Async result of the client.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnIncomingConnection(ByVal IR As IAsyncResult)

            Try

                'Make sure the listener is still something
                If _listener IsNot Nothing Then

                    'End the connection
                    Dim _cli As System.Net.Sockets.TcpClient = _listener.EndAcceptTcpClient(IR)

                    'Make sure the client is actually a client
                    If _cli IsNot Nothing Then

                        'Create a new client
                        Dim _rsc As New RattleSnakeClient(_cli, String.Empty, Me.Port)

                        'Save it
                        _client = _rsc

                        'Add handlers
                        Me.Handlers(True, _rsc)

                        'Raise the event
                        RaiseEvent ClientConnection(Me, New EventArgs.RattleSnakeServerIncomingConnectionEventArgs With {.Client = _rsc})

                    End If

                    'Turn off the listener
                    Me.EndListening()

                End If

            Catch ex As Exception

                'Generic RattleSnake error
                Throw New Exceptions.RattleSnakeException With {.InnerException = ex, .Message = ex.Message}

            End Try

        End Sub

        ''' <summary>
        ''' This routine is called whenever the system has an incoming message.
        ''' </summary>
        ''' <param name="sender">The source client that has received the incoming message.</param>
        ''' <param name="e">The event arguments that contain the received data.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnIncomingData(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientIncomingDataEventArgs)

            'Create the new event argument structure
            Dim _new As New EventArgs.RattleSnakeServerIncomingDataEventArgs With {.Data = e, .Client = CType(sender, RattleSnakeClient)}

            'Check
            Try

                'Check to see if this is a disconnection attempt
                If _new.Data.Obj.GetType Is GetType(Structures.Disconnect) Then Me.Client.Disconnect(RattleSnakeClient.DisconnectOptions.DoNotSend) : Return

            Catch ex As System.Runtime.Serialization.SerializationException

                'Not a serializable message, oh well

            End Try

            'Raise the event
            RaiseEvent IncomingData(Me, _new)

        End Sub

        ''' <summary>
        ''' This routine is called whenever the system has a client disconnect.
        ''' </summary>
        ''' <param name="sender">The client that has disconnected.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnClientDisconnection(ByVal sender As Object)

            'Raise an event
            RaiseEvent ClientDisconnection(Me, New EventArgs.RattleSnakeServerClientDisconnectionEventArgs With {.Client = CType(sender, RattleSnakeClient)})

        End Sub

        ''' <summary>
        ''' This routine is called whenever the system has a client that throws an exception.
        ''' </summary>
        ''' <param name="sender">The client that has thrown the exception.</param>
        ''' <param name="e">The originating exception data that traveled up with the client.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnClientException(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientExceptionEventArgs)

            'Raise the new event
            RaiseEvent ClientException(Me, New EventArgs.RattleSnakeServerClientExceptionEventArgs With {.Client = CType(sender, RattleSnakeClient), .Data = e})

        End Sub


        ''' <summary>
        ''' This event is raised whenever the system has a client that receives incoming data.
        ''' </summary>
        ''' <param name="sender">The originating server that processed the incoming data request.</param>
        ''' <param name="e">The physical incoming data, including a reference to the client that accepted the data.</param>
        ''' <remarks></remarks>
        Public Event IncomingData(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeServerIncomingDataEventArgs)

        ''' <summary>
        ''' This event is raised whenever the system has a client that has disconnected.
        ''' </summary>
        ''' <param name="sender">The originating server that the client has disconnected from.</param>
        ''' <param name="e">The disconnection information event arguments</param>
        ''' <remarks></remarks>
        Public Event ClientDisconnection(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeServerClientDisconnectionEventArgs)

        ''' <summary>
        ''' This event is raised whenever the system has a client that throws an exception.
        ''' </summary>
        ''' <param name="sender">The originating server that the client has thrown an exception on.</param>
        ''' <param name="e">The exception data which includes a reference to the source client that has thrown the actual exception.</param>
        ''' <remarks></remarks>
        Public Event ClientException(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeServerClientExceptionEventArgs)

        ''' <summary>
        ''' This event is raised whenever the system has a client connect successfully.
        ''' </summary>
        ''' <param name="sender">The originating server that the client has connected on.</param>
        ''' <param name="e">The event arguments that contain a reference to the client that has connected successfully.</param>
        ''' <remarks></remarks>
        Public Event ClientConnection(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeServerIncomingConnectionEventArgs)


        ''' <summary>
        ''' Initializes a new RattleSnakeP2PServer for single party communication.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()

            'Create a server on the default port
            Me.New(6110)

        End Sub

        ''' <summary>
        ''' Initializes a new RattleSnakeP2PServer for single party communication.
        ''' </summary>
        ''' <param name="_p">The port to initialize the server on.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal _p As Integer)

            'Setup the listener
            _listener = New Net.Sockets.TcpListener(Net.IPAddress.Any, _p)

            'Store
            _port = _p

        End Sub


        ''' <summary>
        ''' Creates a new RattleSnakeServer that is ready to be started.
        ''' </summary>
        ''' <returns>RattleSnakeServer</returns>
        ''' <remarks>A simple function that makes the initialization process of a RattleSnakeServer simpler.</remarks>
        Public Shared Function CreateServer() As RattleSnakeP2PServer

            'Return a new RattleSnakeServer
            Return RattleSnakeP2PServer.CreateServer(6110)

        End Function

        ''' <summary>
        ''' Creates a new RattleSnakeServer that is ready to be started.
        ''' </summary>
        ''' <returns>RattleSnakeServer</returns>
        ''' <param name="_port">The port that the new server will listen on.</param>
        ''' <remarks>A simple function that makes the initialization process of a RattleSnakeServer simpler.</remarks>
        Public Shared Function CreateServer(ByVal _port As Integer) As RattleSnakeP2PServer

            'Return a new server
            Return New RattleSnakeP2PServer(_port)

        End Function


        ''' <summary>
        ''' Turns the server on to listen for an incoming connection.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub BeginListening()

            'Flip on the TcpListener
            _listener.Start(500I)

            'Start the async acceptance routine.
            _listener.BeginAcceptTcpClient(New AsyncCallback(AddressOf OnIncomingConnection), _listener)

        End Sub

        ''' <summary>
        ''' Turns off the server, rejecting any more incoming connections.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub EndListening()

            'Stop!
            _listener.Stop()

        End Sub


        ''' <summary>
        ''' Activates or deactivates the handlers of a client
        ''' </summary>
        ''' <param name="reg">If true, the handles are registered. If false, the handles are removed.</param>
        ''' <param name="_cli">The RattleSnakeClient that will have its handles modified.</param>
        ''' <remarks></remarks>
        Private Sub Handlers(ByVal reg As Boolean, ByRef _cli As RattleSnakeClient)

            'Check
            If reg Then

                'Add
                AddHandler _cli.Crash, AddressOf _Crash
                AddHandler _cli.Disconnected, AddressOf _Disconnected
                AddHandler _cli.IncomingData, AddressOf _IncomingData

            Else

                'Remove
                RemoveHandler _cli.Crash, AddressOf _Crash
                RemoveHandler _cli.Disconnected, AddressOf _Disconnected
                RemoveHandler _cli.IncomingData, AddressOf _IncomingData

            End If

        End Sub


        Private Sub _Crash(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientExceptionEventArgs)

            'Undo the handlers
            Me.Handlers(False, _client)

            'Looks like we're all out of connections.
            Me.OnClientException(Me, e)

        End Sub

        Private Sub _Disconnected(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientDisconnectionEventArgs)

            'Undo the handlers
            Me.Handlers(False, _client)

            'Looks like we're all out of connections.
            Me.OnClientDisconnection(_client)

        End Sub

        Private Sub _IncomingData(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientIncomingDataEventArgs)

            'Raise some data
            Me.OnIncomingData(_client, e)

        End Sub

    End Class

    ''' <summary>
    ''' The RattleSnake client. The client is responsible for transmitting and receiving data from a RattleSnake server.
    ''' </summary>
    ''' <remarks>The client is fully multi-threaded and takes care of cleaning up on a disconnection.</remarks>
    Public Class RattleSnakeClient

        ''' <summary>
        ''' The disconnection enum options
        ''' </summary>
        ''' <remarks></remarks>
        Public Enum DisconnectOptions

            ''' <summary>
            ''' Sends a disconnection request on the stream.
            ''' </summary>
            ''' <remarks></remarks>
            Send

            ''' <summary>
            ''' Does not send a disconnection request on the stream.
            ''' </summary>
            ''' <remarks></remarks>
            DoNotSend

        End Enum


        ''' <summary>
        ''' The client that holds the network stream
        ''' </summary>
        ''' <remarks></remarks>
        Private _connectedClient As Net.Sockets.TcpClient

        ''' <summary>
        ''' The server IP.
        ''' </summary>
        ''' <remarks></remarks>
        Private _serverIP As String = String.Empty

        ''' <summary>
        ''' The server Port.
        ''' </summary>
        ''' <remarks></remarks>
        Private _serverPort As Integer = 0I

        ''' <summary>
        ''' The IP address of this client.
        ''' </summary>
        ''' <remarks></remarks>
        Private _ip As String = String.Empty


        ''' <summary>
        ''' Retrieves the IP address of this connected client.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>A string that contains a valid IP address of the connected client.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IP As String

            Get
                Try

                    'Check to see if we haven't already done this
                    If Not _ip.Equals(String.Empty) Then Return _ip

                    'We have not, so get the IPEndPoint
                    Dim ipend As Net.IPEndPoint = CType(Me.Client.Client.RemoteEndPoint, Net.IPEndPoint)

                    'Make sure it's not nothing and assign the IP
                    If Not ipend Is Nothing Then _ip = ipend.Address.ToString Else _ip = (String.Empty)

                    'Return the IP
                    Return _ip

                Catch ex As System.ObjectDisposedException
                    Return String.Empty
                Catch ex As Net.Sockets.SocketException
                    Return String.Empty
                End Try

            End Get

        End Property

        ''' <summary>
        ''' The server IP address that this client is connected to.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ServerIP As String

            Get
                Return _serverIP
            End Get

        End Property

        ''' <summary>
        ''' The server Port that this client is connected to.
        ''' </summary>
        ''' <value>Integer</value>
        ''' <returns>The remote port that the RattleSnake Client is connected to.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ServerPort As Integer

            Get
                Return _serverPort
            End Get

        End Property

        ''' <summary>
        ''' The TcpClient that is connected to the remote server.
        ''' </summary>
        ''' <value>TcpClient</value>
        ''' <returns>Connected Client</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Client As Net.Sockets.TcpClient

            Get
                Return _connectedClient
            End Get

        End Property


        ''' <summary>
        ''' This event is raised whenever the system receives some incoming data from the connection stream.
        ''' </summary>
        ''' <param name="sender">The source RattleSnake Client</param>
        ''' <param name="e">An Event Arguments class that contains all the information from the data that was retrieved.</param>
        ''' <remarks></remarks>
        Public Event IncomingData(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientIncomingDataEventArgs)

        ''' <summary>
        ''' This event is raised whenever the client disconnects from the remote server.
        ''' </summary>
        ''' <param name="sender">The source RattleSnake Client</param>
        ''' <param name="e">The event arguments that detail the connection that was just disconnected.</param>
        ''' <remarks></remarks>
        Public Event Disconnected(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientDisconnectionEventArgs)

        ''' <summary>
        ''' This event is raised whenever the client experiences a crash it cannot recover from.
        ''' </summary>
        ''' <param name="sender">The source RattleSnake Client</param>
        ''' <param name="e">The Exception Arguments that contain the crash data.</param>
        ''' <remarks></remarks>
        Public Event Crash(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientExceptionEventArgs)


        ''' <summary>
        ''' This routine is called whenever the TcpClient begins to receive some data across the stream.
        ''' </summary>
        ''' <param name="IR">The Asynchronous result that contains the initial data received.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnIncomingData(ByVal IR As IAsyncResult)

            Try

                'End
                Dim _length As Integer = _connectedClient.Client.EndReceive(IR)

                'Check
                If Not _length.Equals(0) Then

                    'Get the data
                    Dim _data As Byte() = CType(IR.AsyncState, Byte())

                    'Resize
                    Array.Resize(_data, _length)

                    'Check
                    If _length.Equals(256) Then

                        'We have MORE
                        Do While Not _length.Equals(0)

                            'Create a new buffer
                            Dim _buffer(Byte.MaxValue) As Byte

                            'Get more data
                            _length = _connectedClient.Client.Receive(_buffer)

                            'Now, time to merge data
                            Dim _list As New List(Of Byte)(_data)

                            'Resize the buffer array
                            Array.Resize(_buffer, _length)

                            'Add the new data
                            _list.AddRange(_buffer)

                            'Reassign it back
                            _data = _list.ToArray

                        Loop

                    End If

                    'Create event args
                    Dim _rscidea As New EventArgs.RattleSnakeClientIncomingDataEventArgs With {.Data = _data, .Client = Me}

                    'Check
                    If _rscidea.Obj.GetType Is GetType(Structures.Disconnect) Then

                        Me.Disconnect(DisconnectOptions.DoNotSend)

                    Else

                        'Raise the event
                        RaiseEvent IncomingData(Me, New EventArgs.RattleSnakeClientIncomingDataEventArgs With {.Data = _data, .Client = Me})

                        'Restart reading for next time
                        Me.BeginReceive()

                    End If

                End If

            Catch ex As ObjectDisposedException

                Debug.WriteLine("OnIncomingData() ODE")

            End Try

        End Sub

        ''' <summary>
        ''' This routine is called whenever the TcpClient finishes disconnecting from the remote stream.
        ''' </summary>
        ''' <param name="IR">The AsyncResult that contains some infromation about the disconnection.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnDisconnection(ByVal IR As IAsyncResult)

            Try

                'End the disconnection attempt
                _connectedClient.Client.EndDisconnect(IR)

                'All finished
                _connectedClient.Client.Close()

                'Create our event arguments
                Dim _rscdea As New EventArgs.RattleSnakeClientDisconnectionEventArgs With {.IP = Me.ServerIP, .Port = Me.ServerPort, .Client = Me}

                'Raise the event
                RaiseEvent Disconnected(Me, _rscdea)

            Catch ex As ObjectDisposedException

                Debug.WriteLine("OnDisconnection() ODE")

            End Try

        End Sub

        ''' <summary>
        ''' This routine is called whenever the client finishes sending all the data across the stream.
        ''' </summary>
        ''' <param name="IR">The AsyncResult that contains some information about the data that was sent.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnDataSent(ByVal IR As IAsyncResult)

            Try

                'End the send
                Dim _length As Integer = _connectedClient.Client.EndSend(IR)

                'Now get the data array we sent
                Dim _data() As Byte = CType(IR.AsyncState, Byte())

                'Wrap in a try catch to see if it is a serialized routine.
                Try

                    'Create some new event arguments
                    Dim _rscdsea As New EventArgs.RattleSnakeClientIncomingDataEventArgs With {.Data = _data, .Client = Me}

                    'Test to see if it is a disconnection routine.
                    If _rscdsea.Obj.GetType Is GetType(Networking.RattleSnake.Structures.Disconnect) Then Me.Disconnect(DisconnectOptions.DoNotSend)

                Catch ex As System.Runtime.Serialization.SerializationException

                    'The data is not a serialized structure, do nothing else.

                End Try

            Catch ex As Exception

                'Raise
                Me.OnCrash(New RattleSnake.Exceptions.RattleSnakeException With {.InnerException = ex, .Message = ex.Message})

                'Leave
                Return

            End Try

        End Sub

        ''' <summary>
        ''' This routine is called whenever the client experiences a crash.
        ''' </summary>
        ''' <param name="e">The exception that contains the details of the crash.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnCrash(ByVal e As Exception)

            'Pass it up
            RaiseEvent Crash(Me, New EventArgs.RattleSnakeClientExceptionEventArgs With {.Data = e, .Client = Me})

        End Sub


        ''' <summary>
        ''' Creates a new RattleSnake Client that holds a connection to a RattleSnake Server.
        ''' </summary>
        ''' <param name="e">The event arguments that contain all the required information to startup the server.</param>
        ''' <remarks>This method uses the connector event arguments instead of spreading out the arguments across three variables.</remarks>
        Public Sub New(ByRef e As EventArgs.RattleSnakeConnectorConnectedEventArgs)

            'Assign
            Me.New(e.Client.Client, e.IP, e.Port)

        End Sub

        ''' <summary>
        ''' Creates a new RattleSnake Client that holds a connection to a RattleSnake Server.
        ''' </summary>
        ''' <param name="_cli">The TcpClient that holds the connection.</param>
        ''' <param name="_sIp">The Server IP address that the client is connected to.</param>
        ''' <param name="_sPo">The Server port that the client is connected to.</param>
        ''' <remarks>This method uses three parameters instead of one.</remarks>
        Public Sub New(ByRef _cli As Net.Sockets.TcpClient, ByVal _sIp As String, ByVal _sPo As Integer)

            'Assign
            _connectedClient = _cli
            _serverIP = _sIp
            _serverPort = _sPo

            'Try
            If _serverIP.Equals(Me.IP) Then Debug.WriteLine("same")

            'Begin listening
            Me.BeginReceive()

        End Sub


        ''' <summary>
        ''' Begins disconnecting from the remote server.
        ''' </summary>
        ''' <remarks>This method will send a disconnection warning.</remarks>
        Public Sub Disconnect()

            'We are sending a warning
            Me.Disconnect(DisconnectOptions.Send)

        End Sub

        ''' <summary>
        ''' Begins disconnecting from the remote server.
        ''' </summary>
        ''' <param name="send">The disconnection options to use.</param>
        ''' <remarks></remarks>
        Public Sub Disconnect(ByVal send As DisconnectOptions)

            'Determine
            If send.Equals(DisconnectOptions.Send) Then

                'Send the request
                Me.BeginSend(New RattleSnake.Structures.Disconnect)

            Else

                Try

                    'Disconnect
                    _connectedClient.Client.BeginDisconnect(False, New AsyncCallback(AddressOf OnDisconnection), Nothing)

                Catch ex As Exception

                    Debug.WriteLine("Disconnect() ODE")

                End Try

            End If

        End Sub


        ''' <summary>
        ''' Sends a serialized structure across the network stream.
        ''' </summary>
        ''' <param name="_data">The serializable structure to send.</param>
        ''' <remarks>This routine will take the serialized structure and convert it to a byte array that will actually be transmitted across the stream.</remarks>
        Public Sub BeginSend(ByVal _data As Object)

            'Create the temporary memory stream
            Dim _ms As New IO.MemoryStream

            'Create the serializer
            Dim _s As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

            'Serialize
            _s.Serialize(_ms, _data)

            'Get the byte array
            Dim _arr() As Byte = _ms.ToArray

            'Close the stream
            _ms.Close()

            'Call our other send
            Me.BeginSend(_arr)

        End Sub

        ''' <summary>
        ''' Sends a byte array across the network stream.
        ''' </summary>
        ''' <param name="_data">The byte array to send.</param>
        ''' <remarks>This routine directly sends the bytes across the stream.</remarks>
        Public Sub BeginSend(ByVal _data() As Byte)

            Try

                'Send!
                _connectedClient.Client.BeginSend(_data, 0, _data.Length, Net.Sockets.SocketFlags.None, New AsyncCallback(AddressOf OnDataSent), _data)

            Catch ex As ObjectDisposedException

                Debug.WriteLine("BeginSend() ODE.")

            End Try

        End Sub


        ''' <summary>
        ''' Begins receiving data across the stream.
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub BeginReceive()

            'The byte array will go from 0 To 255, which makes the byte array 256 in length
            Dim _bytes(Byte.MaxValue) As Byte

            'Start
            _connectedClient.Client.BeginReceive(_bytes, 0, _bytes.Length, Net.Sockets.SocketFlags.None, New AsyncCallback(AddressOf OnIncomingData), _bytes)

        End Sub

    End Class

    ''' <summary>
    ''' A simplified class designed to easily create a connection between a client and server.
    ''' </summary>
    ''' <remarks>The RS connector class is completely multi-threaded and returns a RS client that contains an active connection to a RS server.</remarks>
    Public Class RattleSnakeConnector

        ''' <summary>
        ''' This routine is raised whenever the client connects to a server.
        ''' </summary>
        ''' <param name="IR">The result of the connection.</param>
        ''' <remarks></remarks>
        Protected Shared Sub OnConnection(ByVal IR As IAsyncResult)

            Try

                'Get the leftover data
                Dim _arguments As EventArgs.RattleSnakeConnectorAsyncData = CType(IR.AsyncState, EventArgs.RattleSnakeConnectorAsyncData)

                'End the connection
                _arguments.Client.EndConnect(IR)

                'Create a new client
                Dim _client As New RattleSnakeClient(_arguments.Client, _arguments.IP, _arguments.Port)

                'Pass it all up
                RaiseEvent ConnectionEstablished(Nothing, New EventArgs.RattleSnakeConnectorConnectedEventArgs With {.Client = _client, .IP = _client.ServerIP, .Port = _client.ServerPort})

            Catch ex As Exception

                'We crashed out
                RaiseEvent ConnectionFailed(Nothing, New EventArgs.RattleSnakeClientExceptionEventArgs() With {.Client = Nothing, .Data = New RattleSnake.Exceptions.RattleSnakeException With {.InnerException = ex, .Message = ex.Message}})

            End Try

        End Sub


        ''' <summary>
        ''' This event is raised whenever the client has established a connection to a server.
        ''' </summary>
        ''' <param name="sender">The Connector Class</param>
        ''' <param name="e">The Event Arguments that contain the newly created client as a result of the connection.</param>
        ''' <remarks></remarks>
        Public Shared Event ConnectionEstablished(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeConnectorConnectedEventArgs)

        ''' <summary>
        ''' This event is raised whenever the client has crashed in the connection attempt.
        ''' </summary>
        ''' <param name="sender">The Connector Class</param>
        ''' <param name="e">The event arguments containing the crash.</param>
        ''' <remarks></remarks>
        Public Shared Event ConnectionFailed(ByVal sender As Object, ByVal e As EventArgs.RattleSnakeClientExceptionEventArgs)

        ''' <summary>
        ''' Launches a connection to a remote RattleSnake server.
        ''' </summary>
        ''' <param name="_ip">The RattleSnake Server IP address to connect to.</param>
        ''' <remarks></remarks>
        Public Shared Sub Connect(ByVal _ip As String)

            ''Create a client
            'Dim _client As New Net.Sockets.TcpClient()

            ''Start the connection
            '_client.BeginConnect(_ip, 6110I, New AsyncCallback(AddressOf OnConnection), _client)

            'Fire off a connection
            RattleSnakeConnector.Connect(_ip, 6110)

        End Sub

        ''' <summary>
        ''' Launches a connection to a remote RattleSnake server.
        ''' </summary>
        ''' <param name="_ip">The IP address to connect on.</param>
        ''' <param name="_port">The port to connect on.</param>
        ''' <remarks></remarks>
        Public Shared Sub Connect(ByVal _ip As String, ByVal _port As Integer)

            'Create a client
            Dim _client As New Net.Sockets.TcpClient()

            'Start the connection
            _client.BeginConnect(_ip, _port, New AsyncCallback(AddressOf RattleSnakeConnector.OnConnection), New EventArgs.RattleSnakeConnectorAsyncData With {.Client = _client, .IP = _ip, .Port = _port})

        End Sub

    End Class

End Namespace
