Option Strict On
Option Explicit On
Imports System
Imports System.Net
Imports System.Net.Sockets
Public Class SocketClients
Inherits ArrayList
Protected Shared RequestPort As Int32
Private _PortRange(0) As Port
Private _ReqListener As Net.Sockets.TcpListener
Private _LocalEP As Net.IPEndPoint
Private _thrdPend As New Threading.Thread(AddressOf WaitForPending)
Public Event NewClient(ByVal obj As Client)
Private Structure Port
Public PortNum As Int32
Public avaliable As Boolean
Public Sub New(ByVal num As Int32, ByVal avail As Boolean)
PortNum = num
avaliable = avail
End Sub
End Structure
Public Sub New(ByVal RequestPortIn As Int32, ByVal PortStart As Int32, ByVal PortEnd As Int32)
MyBase.New()
If RequestPort >= PortStart And RequestPort <= PortEnd Then
Throw New ArgumentException("Request port cannot be in the Port pool", "RequestPort")
ElseIf PortStart > PortEnd Then
Throw New ArgumentException("PortStart cannot be prior to PortEnd", "PortStart")
ElseIf PortStart < 49152 Then
Throw New ArgumentException("""Well-Known"" and ""DCCP Well-Known"" ports cannot be used dynamically.", "PortStart")
ElseIf PortEnd > 65535 Then
Throw New ArgumentException("Requested Range is out of scope.", "PortEnd")
Else
Try
For i As Int32 = PortStart To PortEnd
_PortRange(UBound(_PortRange)) = New Port(i, True)
If Not i = PortEnd Then
ReDim Preserve _PortRange(_PortRange.Length)
End If
Next i
RequestPort = RequestPortIn
_LocalEP = New Net.IPEndPoint(Dns.Resolve(Dns.GetHostName).AddressList(0), RequestPort)
_ReqListener = New Net.Sockets.TcpListener(_LocalEP)
Catch ex As Exception
Stop 'XXX DEBUG XXX
End Try
End If
End Sub
Public Sub StartListen()
_ReqListener.Start()
Select Case _thrdPend.ThreadState
Case Threading.ThreadState.Unstarted
_thrdPend.Start()
Case Threading.ThreadState.Running
'Do nothing, already running
Case Threading.ThreadState.Suspended
_thrdPend.Resume()
Case Threading.ThreadState.SuspendRequested
_thrdPend.Resume()
End Select
End Sub
Public Sub StopListen()
_ReqListener.Stop()
_thrdPend.Abort()
End Sub
Private Sub WaitForPending()
While Threading.Thread.CurrentThread.ThreadState <> Threading.ThreadState.StopRequested Or _
Threading.Thread.CurrentThread.ThreadState <> Threading.ThreadState.AbortRequested
If Threading.Thread.CurrentThread.ThreadState = Threading.ThreadState.SuspendRequested Then
Threading.Thread.CurrentThread.Suspend()
Else
If _ReqListener.Pending Then
SyncLock Threading.Thread.CurrentThread 'Begin Negotiation
Dim socTemp As Net.Sockets.Socket = _ReqListener.AcceptSocket
Dim holdPort As Port
Dim buffer() As Byte
For i As Int32 = 0 To UBound(_PortRange, 1) - 1
If _PortRange(i).avaliable = True Then 'According to our system, it's free
If validateport(_PortRange(i).PortNum) Then
holdPort = _PortRange(i)
_PortRange(i).avaliable = False
i = UBound(_PortRange, 1) - 1 'Seems more clever then an "Exit For"
Else 'Some other program must have it, reflect in our array and continue
_PortRange(i).avaliable = False
End If
End If
Next i
If holdPort.PortNum = 0 Then
buffer = Text.Encoding.ASCII.GetBytes("NOAVAIL")
Else
Dim client As New Client(socTemp.RemoteEndPoint.Serialize.Item(4) & "." & _
socTemp.RemoteEndPoint.Serialize.Item(5) & "." & _
socTemp.RemoteEndPoint.Serialize.Item(6) & "." & _
socTemp.RemoteEndPoint.Serialize.Item(7), holdPort.PortNum)
buffer = Text.Encoding.ASCII.GetBytes("S:" & holdPort.PortNum)
Me.Add(client, True)
End If
socTemp.Send(buffer, buffer.Length, SocketFlags.None)
socTemp.Shutdown(SocketShutdown.Receive)
End SyncLock
End If
End If
End While
Select Case Threading.Thread.CurrentThread.ThreadState
Case Threading.ThreadState.AbortRequested
Threading.Thread.CurrentThread.Abort()
End Select
End Sub