﻿Imports System.Runtime.Serialization.Formatters
Imports System.IO
Imports System.Net
Imports System.Net.Sockets

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''' Networking Library - Developed by Shiny Jirachi/formlesstree4. 
''''''' Revision: 4
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''' Namespace Breakdown:
''''''' --------------------------------------------------------------------
''''''' Networking.P2P
'''''''     .Server:    Contains all the required systems and code to run a P2P server system. It's relatiavely straightforward on
'''''''                 how to actually run it. The system takes care a vast majority of the cleaning up and message handling for
'''''''                 disconnections and unexpected terminations on the connection and even corrupted data being sent over the
'''''''                 message stream.
'''''''
'''''''     .Client:    The other side of the P2P system. The client is just merely connecting to the server as a means of communication.
'''''''                 The only difference between the Client & Server is that the client cannot listen for connections. It merely connects
'''''''                 to an open Server.
''''''' --------------------------------------------------------------------
''''''' Networking.Exceptions
'''''''     .InvalidPortException:  This Exception is thrown when the programmer/user attempts to pass an invalid port number into the constrictor of any
'''''''                             class that utilizes the LowLevel system. Various other checks are built in to other systems but for the most part,
'''''''                             this exception will originate from the Networking.Generics.LowLevel system. It contains the stack trace, source call
'''''''                             and the port number that was attempted to be used. Programmers should pay close attention to the information the IPE
'''''''                             gives out.
''''''' --------------------------------------------------------------------
''''''' Networking.Generic
'''''''     .Server:    This Low level class is responsible for the actual listening that any server class should wrap around. It performs all connections using
'''''''                 Asynchronous methods in order to maximize speed and efficiency and keep all necessary threads unlocked. What this class doesn't do is keep
'''''''                 track of connections that have been established. That is not this classes job. It's job is to handle incoming connections accordingly and
'''''''                 pass up the connection to whatever system requires it.
'''''''     
'''''''     .Level:     Simple Enumeration that should be used to determine what should be logged in the systems. Mostly used in the lower level systems and can
'''''''                 be utilized by other systems that want to use it.
''''''' 
'''''''     .User:      This is the generic handler for clients that are submitted to the system. It handles the incoming TcpClient connections, disconnections, messages
'''''''                 and just about anything else that could be necessary, including disposing of the system entirely (since it implements IDisposable). You can wrap
'''''''                 other classes around this, but this usually is the base class for handling TcpClient communication.
''''''' --------------------------------------------------------------------
''''''' Networking.Structures.Generic
'''''''     .Message:       The general structure used in communicating a message. The Name property holds the name (if applicable) of the sender
'''''''                     and the Message property obviously holds the message data. Since it's most commonly used in the P2P portion of the code,
'''''''                     it does not need to keep track of the sender as it's pretty obvious who the sender actually is.
''''''' 
'''''''     .Disconnect:    This is almost never written by the programmer. It is used in the underlying Disconnect() routines to notify the system
'''''''                     that a disconnection is taking place and to immediately attempt an asynchronous attempt at closing the socket. Most times,
'''''''                     this executes without error (in fact, I haven't seen a time where it hasn't).
''''''' --------------------------------------------------------------------

#Region " P2P Client/Server Example "

Namespace Networking.P2P.Server

    ''' <summary>
    ''' Handles all server interactions.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class Server

        'Private variables.
        Private WithEvents _communications As New Networking.Generic.Server
        Private WithEvents _user As Generic.User
        Private _canListen As Boolean = True

        'Events
        Public Event Log(ByVal sender As Object, ByVal message As String)
        Public Event Message(ByVal receiver As Generic.User, ByVal data As Object)
        Public Event ConnectionEstablished()
        Public Event Disconnected()

        'Overridable Subs

        ''' <summary>
        ''' Called when the client disconnects.
        ''' </summary>
        ''' <remarks></remarks>
        Protected Overridable Sub OnDisconnect()
            RaiseEvent Disconnected()
        End Sub

        ''' <summary>
        ''' Called when we get a new connection.
        ''' </summary>
        ''' <remarks></remarks>
        Protected Overridable Sub OnConnectionEstablished()

            'OK RAISE THAT EVENT
            RaiseEvent ConnectionEstablished()

        End Sub

        ''' <summary>
        ''' Called when the system has logging information.
        ''' </summary>
        ''' <param name="sender">The object that performed the logging data.</param>
        ''' <param name="text">The message to log.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnLogging(ByVal sender As Object, ByVal text As String)

            'Raise the event
            RaiseEvent Log(sender, text)

        End Sub

        ''' <summary>
        ''' Called when a message arrives.
        ''' </summary>
        ''' <param name="sender">The source.</param>
        ''' <param name="text">The data.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnIncomingData(ByVal sender As Generic.User, ByVal text As Object)

            RaiseEvent Message(sender, text)

        End Sub

        'Properties

        ''' <summary>
        ''' Returns the User
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property User As Generic.User
            Get
                Return _user
            End Get
        End Property

        'Subroutines

        ''' <summary>
        ''' Starts the server
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Start()

            If _canListen Then _communications.Start() : _canListen = False

        End Sub

        ''' <summary>
        ''' Stops the server.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub [Stop]()

            Me.OnLogging(Me, "stopped")
            _communications.Stop()
            _canListen = True

        End Sub

        'Event Handlers

        Private Sub _communications_IncomingConnection(ByRef client As System.Net.Sockets.TcpClient) Handles _communications.IncomingConnection

            'We have an incoming connection; we can shut down the listener now after we create the new Client
            Dim _cli As New Generic.User(client)
            _communications.Stop()
            _user = _cli
            Me.OnConnectionEstablished()

        End Sub

        Private Sub _communications_Log(ByVal text As String) Handles _communications.Log

            'Pass it up
            Me.OnLogging(_communications, text)

        End Sub

        Private Sub _user_Disconnected(ByRef sender As Generic.User) Handles _user.Disconnected

            'Log about it.
            Me.OnLogging(sender, "User Disconnected")
            _canListen = True
            Me.OnDisconnect()

        End Sub

        Private Sub _user_Error(ByRef sender As Generic.User, ByVal e As System.Exception) Handles _user.Error

            'The user errored out.
            Me.OnLogging(sender, String.Format("There was a connection error: {0}{1}", Environment.NewLine, e.ToString))
            _canListen = True

        End Sub

        Private Sub _user_Message(ByRef sender As Generic.User, ByVal message As Object) Handles _user.Message

            'There was a message.
            Me.OnIncomingData(sender, message)

        End Sub

    End Class

End Namespace

Namespace Networking.P2P.Client

    ''' <summary>
    ''' Connects to the IAPL Server.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class Client

        'Variables
        Private _tcp As TcpClient
        Private WithEvents _client As New Generic.User
        Private _hasConnection As Boolean = False

        'Events

        ''' <summary>
        ''' This event is raised when the user errors out.
        ''' </summary>
        ''' <param name="client">The client that errored out.</param>
        ''' <param name="e">The exception data.</param>
        ''' <remarks></remarks>
        Public Event [Error](ByRef client As Generic.User, ByVal e As Exception)

        ''' <summary>
        ''' This event is raised when the user receives message data.
        ''' </summary>
        ''' <param name="client">The receiver.</param>
        ''' <param name="e">The data.</param>
        ''' <remarks></remarks>
        Public Event Message(ByRef client As Generic.User, ByVal e As Object)

        ''' <summary>
        ''' Raised when the client connects.
        ''' </summary>
        ''' <remarks></remarks>
        Public Event Connected()

        ''' <summary>
        ''' Raised when the client disconnects.
        ''' </summary>
        ''' <remarks></remarks>
        Public Event Disconnected()

        'Properties

        ''' <summary>
        ''' Returns the Base User class.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property User As Generic.User
            Get
                Return _client
            End Get
        End Property

        'Overridable Subs

        ''' <summary>
        ''' Called when the client receives data.
        ''' </summary>
        ''' <param name="receiver">The one that received the data.</param>
        ''' <param name="message">The message.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnMessageReceived(ByRef receiver As Generic.User, ByVal message As Object)

            'Raise the event
            RaiseEvent Message(receiver, message)

        End Sub

        ''' <summary>
        ''' Called when the connection is established.
        ''' </summary>
        ''' <param name="IA">The Async Result.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnConnectionEstablished(ByVal IA As IAsyncResult)

            'End the connection attempt; it's done.
            _tcp.Client.EndConnect(IA)

            'We're now connected
            _hasConnection = _tcp.Connected

            'Create the new Client
            _client = New Generic.User(_tcp)

            'raise the Event
            RaiseEvent Connected()

        End Sub

        ''' <summary>
        ''' Called when the Client Errors out.
        ''' </summary>
        ''' <param name="client">The client.</param>
        ''' <param name="e">The exception.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnClientError(ByRef client As Generic.User, ByVal e As Exception)

            'Raise the event.
            RaiseEvent Error(client, e)

            'No longer connected
            _hasConnection = False

        End Sub

        'Subroutines

        ''' <summary>
        ''' Initializes a connection to a listening IAPL server.
        ''' </summary>
        ''' <param name="ip">The IP address to connect to.</param>
        ''' <param name="port">The port to connect to.</param>
        ''' <remarks></remarks>
        Public Sub Connect(ByVal ip As String, ByVal port As Integer)

            'Make sure we're not already connected.
            If Not _hasConnection Then

                'Create the base client.
                _tcp = New TcpClient()

                'Start a connection
                _tcp.BeginConnect(ip, port, New AsyncCallback(AddressOf OnConnectionEstablished), Nothing)

            End If

        End Sub

        'Event Handlers

        Private Sub _client_Disconnected(ByRef sender As Generic.User) Handles _client.Disconnected

            'No longer connected
            _hasConnection = False

            'Raise the event up
            RaiseEvent Disconnected()

        End Sub

        Private Sub _client_Error(ByRef sender As Generic.User, ByVal e As System.Exception) Handles _client.Error

            'Error Message
            Me.OnClientError(sender, e)

        End Sub

        Private Sub _client_Message(ByRef sender As Generic.User, ByVal message As Object) Handles _client.Message

            'Message data.
            Me.OnMessageReceived(sender, message)

        End Sub

    End Class

End Namespace

#End Region

#Region " Generics, Structures and Exceptions "

Namespace Networking.Exceptions

    ''' <summary>
    ''' Thrown when an invalid port is loaded into the system and used in a connection.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class InvalidPortException
        Inherits Exception

        Private _msg As String
        Private _stk As String
        Private _src As String
        Private _prt As Integer

        ''' <summary>
        ''' Gets the Error Message of the IPE.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>String</returns>
        ''' <remarks>This is customizable for programmer feedback or just general debugging.</remarks>
        Public Shadows ReadOnly Property Message As String
            Get
                Return _msg
            End Get
        End Property

        ''' <summary>
        ''' Gets the Stack Trace where the exception was thrown.
        ''' It will give you a vague idea where the exception was thrown, the real details should be
        ''' found in the "Source" Property.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>String</returns>
        ''' <remarks>Highly recommended to pass this in.</remarks>
        Public Shadows ReadOnly Property Stack As String
            Get
                Return _stk
            End Get
        End Property

        ''' <summary>
        ''' Gets the originating function or routine that threw the exception.
        ''' This class will only return something if the programmer actually passed
        ''' in the routine/function that threw the exception otherwise this property
        ''' will just give an empty string.
        ''' </summary>
        ''' <value>String</value>
        ''' <returns>String</returns>
        ''' <remarks>This is an optional, but highly recommended parameter to pass into the IPE Class. It gives more debugging information for the
        ''' programmers to work from and better bug reports in general.</remarks>
        Public Shadows ReadOnly Property Source As String
            Get
                Return _src
            End Get
        End Property

        ''' <summary>
        ''' Throws a new InvalidPortException which passes a message upward for the system to handle.
        ''' </summary>
        ''' <param name="Message">A customized error message to pass up.</param>
        ''' <param name="Stack">The stacktrace of the exception.</param>
        ''' <param name="Source">(Optional): Originating Source Call.</param>
        ''' <param name="port">The invalid port number.</param>
        ''' <remarks>Basically fills in all the private data that will be read by the ReadOnly Properties.</remarks>
        Public Sub New(ByVal Message As String, ByVal Stack As String, ByVal Source As String, ByVal port As Integer)
            _msg = Message
            _stk = Stack
            _src = Source
            _prt = port
        End Sub

    End Class

End Namespace

Namespace Networking.Generic

    ''' <summary>
    ''' Handles all low level server side incoming connections.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class Server

        ''' <summary>
        ''' Returns the port the Class is listening on.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Port As Integer
            Get
                Return _port
            End Get
        End Property

        ''' <summary>
        ''' This sub is called whenever an Incoming Connection is established.
        ''' </summary>
        ''' <param name="ir">The IAsyncResult Data.</param>
        ''' <remarks></remarks>
        Public Overridable Sub OnIncomingConnection(ByVal ir As IAsyncResult)

            Me.Logging("SYSTEM: Connection established, passing TcpClient on.", Level.SystemMessages)

            Try

                'Grab the new client.
                Dim client As TcpClient = _listener.EndAcceptTcpClient(ir)

                'Client grabbed, raise event passing it back up.
                RaiseEvent IncomingConnection(client)

            Catch ex As ObjectDisposedException

                'Leave the sub.
                Return

            End Try

            Me.Logging("SYSTEM: Passed on, ready for another connection.", Level.SystemMessages)

            'Setup for the next connection.
            Try
                _listener.BeginAcceptTcpClient(New AsyncCallback(AddressOf Me.OnIncomingConnection), _listener)
            Catch ex As Exception
                RaiseEvent Log("Exception. No Longer accepting connections.")
                RaiseEvent Log(ex.ToString)
            End Try

        End Sub

        'Events
        Public Event IncomingConnection(ByRef client As TcpClient)
        Public Event Log(ByVal text As String)

        'Variable List
        Private _listener As TcpListener
        Private _port As Integer = 6110I
        Private _listening As Boolean = False
        Public _logging As Level = Level.Exceptions

        ''' <summary>
        ''' Creates a new Class with the default listener port.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
        End Sub

        ''' <summary>
        ''' Creates a new Class with the specified port.
        ''' </summary>
        ''' <param name="Port">The port to listen on.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal Port As Integer)

            'Check the port conditions
            If Port >= 1 AndAlso Port <= 65535 Then

                'If not listening, set the ports up and create the listener.
                If Not _listening Then
                    _port = Port
                End If

            Else

                'Throw an exception
                Throw New Networking.Exceptions.InvalidPortException("The specified port is not valid!", Environment.StackTrace, "Networking.Generic.Server.New()", Port)

            End If

        End Sub

        ''' <summary>
        ''' Starts the listener.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Start()

            'If we're not listening, we are allowed to start.
            If Not _listening Then

                'Say that we ARE listening.
                _listening = True

                'Create the listener
                _listener = New TcpListener(IPAddress.Any, Port)

                Me.Logging("SYSTEM: Listener created, activating...", Level.SystemMessages)

                'Start the actual listener.
                _listener.Start()

                'Get ready for the new Clients.
                _listener.BeginAcceptTcpClient(New AsyncCallback(AddressOf Me.OnIncomingConnection), Nothing)

                Me.Logging("SYSTEM: Waiting for incoming connections...", Level.SystemMessages)

            End If

        End Sub

        ''' <summary>
        ''' Stops the listener.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub [Stop]()

            'If we are in fact listening then go ahead and disable all the listening.
            If _listening Then

                Me.Logging("SYSTEM: Listener stopped.", Level.SystemMessages)

                _listening = False
                _listener.Stop()

            End If

        End Sub

        ''' <summary>
        ''' Raises events to logs.
        ''' </summary>
        ''' <param name="text">The text to log.</param>
        ''' <param name="level">The level of the log.</param>
        ''' <remarks></remarks>
        Private Sub Logging(ByVal text As String, ByVal level As Level)

            RaiseEvent Log(String.Format("LowLevel Log: {0}", text))

        End Sub

    End Class

    ''' <summary>
    ''' Logging Level enums
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum Level
        None = 0
        Normal = 1
        IncludeDebug = 2
        SystemMessages = 3
        Exceptions = 4
    End Enum

    ''' <summary>
    ''' The connected client.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class User
        Implements IDisposable

        'Variables
        Private _client As TcpClient = Nothing
        Private _thread As Threading.Thread = Nothing
        Private _disposed As Boolean = False
        Private _ip As String = String.Empty

        ''' <summary>
        ''' Returns the IP address of the Client.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IP As String
            Get

                'See if the IP hasn't been defined.
                If _ip.Equals(String.Empty) Then
                    Try

                        'Get it using IPEndPoint.
                        Dim ipend As Net.IPEndPoint = CType(_client.Client.RemoteEndPoint, Net.IPEndPoint)

                        'Make sure we got something.
                        If ipend IsNot Nothing Then _ip = ipend.Address.ToString

                        'Any exceptions will be ignored here.
                    Catch ex As System.ObjectDisposedException
                        _ip = String.Empty
                    Catch ex As SocketException
                        _ip = String.Empty
                    End Try
                End If

                Return _ip
            End Get
        End Property

        ''' <summary>
        ''' Returns if the Client is connected.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Connected As Boolean
            Get
                If _client IsNot Nothing Then Return _client.Connected Else Return False
            End Get
        End Property

        ''' <summary>
        ''' The event is raised when a message is successfully deserialized from the stream.
        ''' </summary>
        ''' <param name="sender">The source client.</param>
        ''' <param name="message">The actual data.</param>
        ''' <remarks></remarks>
        Public Event Message(ByRef sender As User, ByVal message As Object)

        ''' <summary>
        ''' This event is raised when the client throws an error that it cannot recover from.
        ''' </summary>
        ''' <param name="sender">The source client.</param>
        ''' <param name="e">The exception data.</param>
        ''' <remarks></remarks>
        Public Event [Error](ByRef sender As User, ByVal e As Exception)

        ''' <summary>
        ''' This event is raised when the client disconnects.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <remarks></remarks>
        Public Event Disconnected(ByRef sender As User)

        ''' <summary>
        ''' Called when a message arrives.
        ''' </summary>
        ''' <param name="message">The Message</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnIncomingMessage(ByVal message As Object)

            'Do nothing but raise the event.
            RaiseEvent Message(Me, message)

        End Sub

        ''' <summary>
        ''' Called when the Client throws an error.
        ''' </summary>
        ''' <param name="e">The exception data.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnError(ByVal e As Exception)

            'Pass the event up.
            RaiseEvent Error(Me, e)

        End Sub

        ''' <summary>
        ''' Called when the client successfully disconnects.
        ''' </summary>
        ''' <param name="IV">The Async Result.</param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnDisconnect(ByVal IV As IAsyncResult)

            'End
            _client.Client.EndDisconnect(IV)

            'Raise the event.
            RaiseEvent Disconnected(Me)

            'Alright, the client has been disconnected, dispose.
            Me.Dispose()

        End Sub

        ''' <summary>
        ''' Creates a new blank Client.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
        End Sub

        ''' <summary>
        ''' Creates a new Client handler.
        ''' </summary>
        ''' <param name="client">The client handler.</param>
        ''' <remarks></remarks>
        Public Sub New(ByRef client As TcpClient)

            'Get the client
            _client = client

            'Create the new thread
            _thread = New Threading.Thread(AddressOf Read) With {.IsBackground = True}

            'Run the thread.
            _thread.Start()

            'Snag the IP now.
            Debug.WriteLine(Me.IP)

        End Sub

        ''' <summary>
        ''' Infinite reader class.
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub Read()

            'Loop while connected
            Do While _client.Connected

                'Setup the catch
                Try

                    'Create the object to return from the stream.
                    Dim _obj As Object = New Binary.BinaryFormatter().Deserialize(_client.GetStream)

                    'See if it's a disconnection routine.
                    If _obj.GetType Is GetType(IAPL.Networking.Structures.Generic.Disconnect) Then

                        'Transfer out.
                        Me.Disconnect(False)

                    Else

                        'Transfer it out.
                        Me.OnIncomingMessage(_obj)

                    End If

                Catch ioe As IOException

                    'Input/Output Exception. Handle if we need to.
                    If Not _disposed Then Me.OnError(ioe)

                Catch se As Runtime.Serialization.SerializationException

                    'Serialization Exception. Handle if we need to.
                    If Not _disposed Then Me.OnError(se)

                Catch tae As Threading.ThreadAbortException

                    'Ignore this, just exit the do loop
                    Exit Do

                End Try

            Loop

        End Sub

        ''' <summary>
        ''' Sends data across the stream.
        ''' </summary>
        ''' <param name="data">The data to send.</param>
        ''' <remarks></remarks>
        Public Sub Write(ByVal data As Object)

            'Make sure we're not disposed.
            If Not _disposed Then

                'GOGOGO
                Dim _sender As New Binary.BinaryFormatter

                Try

                    'SEND IT
                    _sender.Serialize(_client.GetStream, data)

                Catch ioe As IOException

                    'IO Exception. Handle if we need to.
                    If Not _disposed Then Me.OnError(ioe)

                Catch se As Runtime.Serialization.SerializationException

                    'Serialization Exception. Handle if we need to.
                    If Not _disposed Then Me.OnError(se)

                End Try

            End If

        End Sub

        ''' <summary>
        ''' Safely disconnects the system.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Disconnect(ByVal sendDisconnect As Boolean)

            'Send the disconnection if we need to.
            If sendDisconnect Then Me.Write(New IAPL.Networking.Structures.Generic.Disconnect)

            'Now perform the disconnect.
            _client.Client.BeginDisconnect(False, New AsyncCallback(AddressOf OnDisconnect), Nothing)

            'Lastly, abort the thread.
            _thread.Abort()

        End Sub

        ''' <summary>
        ''' Overrided Dispose sub.
        ''' </summary>
        ''' <param name="disposing">Boolean</param>
        ''' <remarks></remarks>
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)


            If Not _disposed Then

                Me._disposed = True

                If disposing Then

                    'Stop the thread
                    If _thread.IsAlive Then _thread.Abort()

                    'Stop the client.
                    If _client.Connected Then _client.Client.Close()

                End If

            End If

        End Sub

        ''' <summary>
        ''' Dispose of the Client.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Dispose() Implements IDisposable.Dispose
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub

    End Class

End Namespace

Namespace Networking.Structures

    Namespace Generic

        ''' <summary>
        ''' Used to send messages across the data stream.
        ''' </summary>
        ''' <remarks></remarks>
        <Serializable()> _
        Public Structure Message

            ''' <summary>
            ''' The name of the sender.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Name As String

            ''' <summary>
            ''' The message being sent.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Message As String

            ''' <summary>
            ''' The name of the receiver.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Recipient As String

        End Structure

        ''' <summary>
        ''' Issues a disconnection command.
        ''' </summary>
        ''' <remarks></remarks>
        <Serializable()> _
        Public Structure Disconnect
        End Structure

    End Namespace

End Namespace

#End Region
