'*************************************************** '* This code belongs to Terry R. Olsen '* You are free to use this code in whole or '* in part for your own programs. But you may '* not use this code in any way to create '* the same type of program for public release. '* My Email: tolsen64@hotmail.com '*************************************************** Imports System.Net Imports System.Net.Sockets Imports System.Windows.forms Imports System.Text.ASCIIEncoding Imports System.IO Imports System.IO.Ports Module Module1 #Region "Telnet Commands" ' Telnet main commands - list copied from somewhere on the net - thank you to them Const TN_IAC As Int32 = 255 ' Interpret as command escape sequence, Prefix to all telnet commands. 1, 2 or sometimes more commands normally follow this character Const TN_DONT As Int32 = 254 ' You are not to use this option Const TN_DO As Int32 = 253 ' Please, you use this option Const TN_WONT As Int32 = 252 ' I won't use option Const TN_WILL As Int32 = 251 ' I will use option Const TN_SB As Int32 = 250 ' Subnegotiate, X number of commands follow Const TN_GA As Int32 = 249 ' Go ahead Const TN_EL As Int32 = 248 ' Erase line Const TN_EC As Int32 = 247 ' Erase character Const TN_AYT As Int32 = 246 ' Are you there Const TN_AO As Int32 = 245 ' Abort output Const TN_IP As Int32 = 244 ' Interrupt process Const TN_BRK As Int32 = 243 ' Break[1]InternetModem Const TN_DM As Int32 = 242 ' Data mark Const TN_NOP As Int32 = 241 ' No operation. Const TN_SE As Int32 = 240 ' End of subnegotiation, from above Const TN_EOR As Int32 = 239 ' End of record Const TN_ABORT As Int32 = 238 ' About process Const TN_SUSP As Int32 = 237 ' Suspend process Const TO_EOF As Int32 = 236 ' End of file ' Telnet (option) mainly return commands from above Const TN_BIN As Int32 = 0 ' Binary transmission Const TN_ECHO As Int32 = 1 ' Echo Const TN_RECN As Int32 = 2 ' Reconnection Const TN_SUPP As Int32 = 3 ' Suppress go ahead Const TN_APRX As Int32 = 4 ' Approx message size negotiation Const TN_STAT As Int32 = 5 ' Status Const TN_TIM As Int32 = 6 ' Timing mark Const TN_REM As Int32 = 7 ' Remote controlled trans/echo Const TN_OLW As Int32 = 8 ' Output line width Const TN_OPS As Int32 = 9 ' Output page size Const TN_OCRD As Int32 = 10 ' Out carriage-return disposition Const TN_OHT As Int32 = 11 ' Output horizontal tabstops Const TN_OHTD As Int32 = 12 ' Out horizontal tab disposition Const TN_OFD As Int32 = 13 ' Output formfeed disposition Const TN_OVT As Int32 = 14 ' Output vertical tabstops Const TN_OVTD As Int32 = 15 ' Output vertical tab disposition Const TN_OLD As Int32 = 16 ' Output linefeed disposition Const TN_EXT As Int32 = 17 ' Extended ascii character set Const TN_LOGO As Int32 = 18 ' Logout Const TN_BYTE As Int32 = 19 ' Byte macro Const TN_DATA As Int32 = 20 ' Data entry terminal Const TN_SUP As Int32 = 21 ' supdup protocol Const TN_SUPO As Int32 = 22 ' supdup output Const TN_SNDL As Int32 = 23 ' Send location Const TN_TERM As Int32 = 24 ' Terminal type Const TO_EOR As Int32 = 25 ' End of record Const TN_TACACS As Int32 = 26 ' Tacacs user identification Const TN_OM As Int32 = 27 ' Output marking Const TN_TLN As Int32 = 28 ' Terminal location number Const TN_3270 As Int32 = 29 ' Telnet 3270 regime Const TN_X3 As Int32 = 30 ' X.3 PAD Const TN_NAWS As Int32 = 31 ' Negotiate about window size Const TN_TS As Int32 = 32 ' Terminal speed Const TN_RFC As Int32 = 33 ' Remote flow control Const TN_LINE As Int32 = 34 ' Linemode Const TN_XDL As Int32 = 35 ' X display location Const TN_ENVIR As Int32 = 36 ' Telnet environment option Const TN_AUTH As Int32 = 37 ' Telnet authentication option Const TN_NENVIR As Int32 = 39 ' Telnet environment option Const TN_EXTOP As Int32 = 25 ' Extended-options-list #End Region 'Serial Port Stuff Dim WithEvents Ser As New SerialPort 'Telnet Stuff Dim LineSize As Integer Dim TcpPort As Integer = 23 Dim TcpSvr As Socket 'TCP Listener Socket, listens for incoming calls Dim TcpClt As Socket 'TCP Client Socket, handles incoming calls Dim TcpMsg As Socket 'Tells Clients that we're busy right now... 'Send & Receive Buffers Dim RcvBuf() As Byte 'In from TCP/Out to Serial Dim XmtBuf() As Byte 'In from Serial/Out to TCP Dim SerByt As Integer 'Bytes to read from serial port Dim Throttle As Integer 'Some slower terminals may need to slow it down 'BBS not available message Dim msg() As Byte = ASCII.GetBytes("The line is busy. Please try again later.") 'Stopwatch for measuring +++ Guard Time Dim swGuardTimer As New System.Timers.Timer 'Application variables Dim logFile As String Dim iniFile As String Dim keepLog As Boolean = False Dim ver As String = "6.7.29.1" 'Modem Emulator Stuff Enum ModemEcho EchoOff = 0 EchoOn = 1 End Enum Enum ModemResultCodeFormat Numeric = 0 Text = 1 End Enum Enum ModemResultCodes Enabled = 0 Disabled = 1 End Enum Enum ModemRingMode SendRing = 0 SendConnect = 1 End Enum Enum ModemHookState OnHook = 0 OffHook = 1 End Enum Const OK As Integer = 0 Const CONNECT As Integer = 1 Const RING As Integer = 2 Const NO_CARRIER As Integer = 3 Const ERR As Integer = 4 Const NO_DIAL_TONE As Integer = 6 Const BUSY As Integer = 7 Const NO_ANSWER As Integer = 8 Dim MdmErr As Integer Dim MdmErrorCode() As String = {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR", "", "NO DIAL TONE", "BUSY", "NO ANSWER"} Dim MdmCmdMode As Boolean = True 'Are we in command mode? Dim MdmCmdStr As String Dim MdmResultCodeFormat As ModemResultCodeFormat = ModemResultCodeFormat.Numeric Dim MdmEcho As ModemEcho = ModemEcho.EchoOn Dim MdmResultCodes As ModemResultCodes = ModemResultCodes.Enabled Dim MdmRingMode As ModemRingMode = ModemRingMode.SendConnect Dim MdmHookState As ModemHookState = ModemHookState.OnHook Dim MdmBaud As String Sub Main() 'Display Program & Author Information Console.WriteLine("Internet Modem v" & ver & " by Terry R. Olsen") Console.WriteLine("Call The BoycoT BBS: telnet://boycot.no-ip.com:9999") Console.WriteLine("Get the latest version of this program: http://boycot.no-ip.com/InternetModem") Console.WriteLine("Email: tolsen64@hotmail.com") Console.WriteLine("=============================================================================") 'Load the INI file. This defines our variables. WriteStatus("Loading Initialization Data") Dim tmpPth As String = My.Application.Info.DirectoryPath If Right(tmpPth, 1) <> "\" Then tmpPth += "\" iniFile = tmpPth + "InternetModem.ini" logFile = tmpPth + "InternetModem.log" Dim r As New StreamReader(iniFile) Dim tmp() As String While r.Peek > 0 tmp = Split(r.ReadLine, "=") Select Case tmp(0) Case "TcpPort" TcpPort = CInt(tmp(1)) Case "SerPort" Ser.PortName = "COM" & Trim(tmp(1)) Case "SerBaud" Ser.BaudRate = CInt(tmp(1)) MdmBaud = Trim(tmp(1)) Case "SerDataBits" Ser.DataBits = CInt(tmp(1)) Case "SerParity" If tmp(1) = "None" Then Ser.Parity = Parity.None If tmp(1) = "Odd" Then Ser.Parity = Parity.Odd If tmp(1) = "Even" Then Ser.Parity = Parity.Even If tmp(1) = "Mark" Then Ser.Parity = Parity.Mark If tmp(1) = "Space" Then Ser.Parity = Parity.Space Case "SerStopBits" If tmp(1) = 1 Then Ser.StopBits = StopBits.One If tmp(1) = 1.5 Then Ser.StopBits = StopBits.OnePointFive If tmp(1) = 2 Then Ser.StopBits = StopBits.Two Case "Handshake" If tmp(1) = "None" Then Ser.Handshake = Handshake.None If tmp(1) = "RTS" Then Ser.Handshake = Handshake.RequestToSend If tmp(1) = "RTS/XonXoff" Then Ser.Handshake = Handshake.RequestToSendXOnXOff If tmp(1) = "XonXoff" Then Ser.Handshake = Handshake.XOnXOff Case "RcvBuf" Ser.WriteBufferSize = CInt(tmp(1)) ReDim RcvBuf(CInt(tmp(1))) Case "XmtBuf" Ser.ReadBufferSize = CInt(tmp(1)) ReDim XmtBuf(CInt(tmp(1))) Case "KeepLog" keepLog = CBool(tmp(1)) Case "BBSName" msg = ASCII.GetBytes(tmp(1) & " is currently in use." & vbCrLf & vbCrLf & _ "Please try again soon!" & vbCrLf & vbCrLf & _ "While you're waiting...give The BoycoT BBS a call..." & vbCrLf & _ "telnet://boycot.no-ip.com:9999") Case "Throttle" Throttle = CInt(tmp(1)) Case "LineSize" LineSize = CInt(tmp(1)) End Select End While r.Close() Ser.ReceivedBytesThreshold = 1 'Raise an event for each character received 'Open the serial port WriteStatus("Opening " & Ser.PortName & "," & Ser.BaudRate & "," & Ser.DataBits & _ "," & Ser.Parity.ToString & "," & Ser.StopBits & "," & Ser.Handshake.ToString) Try Ser.Open() Ser.DtrEnable = True Ser.RtsEnable = True Catch ex As Exception WriteStatus(ex.Message) WriteStatus("Failed!") Console.WriteLine("Press ENTER to exit.") Console.ReadLine() Exit Sub End Try StartTCPServer() AddHandler swGuardTimer.Elapsed, AddressOf swGuardTimerFired swGuardTimer.Interval = 1000 'swGuardTimer.Enabled = True swGuardTimer.Stop() Application.Run() 'Keeps us running... End Sub '==================================================================== 'Our TCP Server Routines. Private Sub StartTCPServer() Dim addr As IPAddress = IPAddress.Parse("0.0.0.0") Dim ep As New IPEndPoint(addr, TcpPort) TcpSvr = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) TcpSvr.Bind(ep) TcpSvr.Listen(2) TcpSvr.BeginAccept(AddressOf AcceptCallback, TcpSvr) WriteStatus("Listening for calls on TCP Port " & TcpPort) End Sub Private Sub AcceptCallback(ByVal ar As IAsyncResult) System.Threading.Thread.CurrentThread.Name = "AcceptCallback" Debug.WriteLine(Now.ToLongTimeString & " AcceptCallback") If TcpClt Is Nothing And MdmHookState = ModemHookState.OnHook Then Debug.WriteLine("TcpClt=Nothing, MdmHookState=" & MdmHookState.ToString) TcpClt = TcpSvr.EndAccept(ar) WriteStatus("Connected to " & CType(TcpClt.RemoteEndPoint, IPEndPoint).ToString) TcpClt.BeginReceive(RcvBuf, 0, RcvBuf.Length, SocketFlags.None, AddressOf ReceiveCallback, RcvBuf) MdmCmdMode = False MdmHookState = ModemHookState.OffHook ModemError(1) Else Debug.WriteLine(Now.ToLongTimeString & " TcpMsg started") TcpMsg = TcpSvr.EndAccept(ar) TcpMsg.Send(msg) WriteStatus("Sent busy message to " & CType(TcpMsg.RemoteEndPoint, IPEndPoint).ToString) TcpMsg.Shutdown(SocketShutdown.Both) TcpMsg.Close() TcpMsg = Nothing End If TcpSvr.BeginAccept(AddressOf AcceptCallback, TcpSvr) WriteStatus("Listening for calls on TCP Port " & TcpPort) End Sub Private Sub ReceiveCallback(ByVal ar As IAsyncResult) System.Threading.Thread.CurrentThread.Name = "ReceiveCallback" RcvBuf = CType(ar.AsyncState, Byte()) Dim numbytes As Int32 Try numbytes = TcpClt.EndReceive(ar) Catch Exit Sub End Try If numbytes = 0 Then 'client has disconnected. Ser.DtrEnable = False Ser.RtsEnable = False HangUp(False) 'False = Remote initiated disconnect MdmHookState = ModemHookState.OnHook Ser.DtrEnable = True Ser.RtsEnable = True ModemError(NO_CARRIER) Exit Sub End If If MdmCmdMode = False Then ProcessIncoming(numbytes) TcpClt.BeginReceive(RcvBuf, 0, RcvBuf.Length, SocketFlags.None, AddressOf ReceiveCallback, RcvBuf) End Sub Sub ProcessIncoming(ByVal numbytes As Int32) For i As Integer = 0 To numbytes - 1 Select Case RcvBuf(i) Case TN_IAC 'WriteStatus("Telnet Protocol in use.") Dim byt(0 To 2) As Byte byt(0) = TN_IAC i += 1 Select Case RcvBuf(i) Case TN_SB 'ToChatWindow(" TN_SB" & vbCrLf) WriteStatus("TN_SB Received! Subnegotiate Incomplete.") Do i += 1 Loop Until RcvBuf(i) = TN_SE Or i = numbytes - 1 Case TN_DO 'Server asking you to do something 'ToChatWindow(" TN_DO " & Str(buffer(i + 1)) & vbCrLf) i += 1 Select Case RcvBuf(i) Case TN_NAWS byt(1) = TN_WILL byt(2) = RcvBuf(i) SendBytesToHost(byt) SetLineSize() Case Else byt(1) = TN_WONT byt(2) = RcvBuf(i) SendBytesToHost(byt) End Select Case TN_DONT 'Server asking you to NOT do something 'ToChatWindow(" TN_DONT" & Str(buffer(i + 1)) & vbCrLf) byt(1) = TN_WONT i += 1 byt(2) = RcvBuf(i) SendBytesToHost(byt) Case TN_WILL 'Server telling you it will do something 'ToChatWindow(" TN_WILL" & Str(buffer(i + 1)) & vbCrLf) byt(1) = TN_DONT i += 1 byt(2) = RcvBuf(i) SendBytesToHost(byt) Case TN_WONT 'Server telling you it won't do someting 'ToChatWindow(" TN_WONT" & Str(buffer(i + 1)) & vbCrLf) byt(1) = TN_DONT i += 1 byt(2) = RcvBuf(i) SendBytesToHost(byt) End Select Case Else Try Threading.Thread.Sleep(Throttle) 'Debug.Write(ASCII.GetString(RcvBuf, i, 1)) Ser.Write(RcvBuf, i, 1) Catch ex As Exception WriteStatus("----------------------------") WriteStatus("Routine: ReceiveCallBack") WriteStatus("Exception: " & ex.Message) WriteStatus("Chat Msg: " & Chr(RcvBuf(i))) End Try End Select Next End Sub Private Sub SetLineSize() 'The syntax for the subnegotiation is: IAC SB NAWS WIDTH[1] WIDTH[0] HEIGHT[1] HEIGHT[0] IAC SE Dim byt() As Byte = {TN_IAC, TN_SB, TN_NAWS, LineSize \ 256, LineSize Mod 256, 0, 24, TN_IAC, TN_SE} SendBytesToHost(byt) End Sub Private Sub SendBytesToHost(ByVal byt() As Byte) TcpClt.Send(byt, byt.Length, SocketFlags.None) End Sub Private Sub HangUp(ByVal local As Boolean) MdmErr = OK If Not TcpClt Is Nothing Then Try TcpClt.Shutdown(SocketShutdown.Both) TcpClt.Close() TcpClt = Nothing MdmErr = NO_CARRIER If local = True Then WriteStatus("Locally initiated disconnect") Else WriteStatus("Remote initiated disconnect") End If Catch ex As Exception WriteStatus("Locally initiated disconnect, already offline") End Try Else WriteStatus("Locally initiated disconnect, already offline") End If MdmCmdMode = True Debug.WriteLine(MdmCmdMode.ToString) End Sub 'Routine to write status to console window... 'and to log file if set. Private Sub WriteStatus(ByVal msg As String) Dim dt As String = Date.Now.ToShortDateString & " " & Date.Now.ToShortTimeString msg = dt & " - " & msg Console.WriteLine(msg) Exit Sub If keepLog = True Then Dim sw As New StreamWriter(logFile, True) 'w = My.Computer.FileSystem.OpenTextFileWriter(logFile, True) sw.WriteLine(msg) sw.Close() End If End Sub Private Sub SerRcvEvent(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs) Handles Ser.DataReceived SerByt = Ser.BytesToRead Ser.Read(XmtBuf, 0, SerByt) Dim rcvString As String = ASCII.GetString(XmtBuf, 0, SerByt) Debug.Write(rcvString) ' --Did we get a Modem Esc Command? ' If so, start the 1 second timer. If InStr(rcvString, "+++") Then swGuardTimer.Start() End If ' --If we're in command mode, send characters received to be processed If MdmCmdMode = True Then ProcessMdmCmd(rcvString) Exit Sub End If ' --Otherwise, send it out to our connected user. If TcpClt Is Nothing Then Exit Sub Try TcpClt.Send(XmtBuf, SerByt, SocketFlags.None) Catch End Try End Sub Private Sub ProcessMdmCmd(ByVal CmdStr As String) MdmErr = OK MdmCmdStr += UCase(CmdStr) If MdmEcho = ModemEcho.EchoOn Then Ser.Write(CmdStr) '--Command is still coming in if we haven't received the CR If Right(MdmCmdStr, 1) <> Chr(13) Then Exit Sub '--CR only does not a command make... If MdmCmdStr.Equals(vbCr) Then MdmCmdStr = "" Exit Sub End If '--Get rid of the +'s from the ESC sequence, and trim off the CR MdmCmdStr = MdmCmdStr.Replace("+", "").Trim(Chr(13)) Debug.WriteLine("MdmCmdStr: " & MdmCmdStr) '--All good command strings begin with AT If Left(MdmCmdStr, 2) <> "AT" Then Debug.WriteLine("MdmCmdStr doesn't begin with AT") MdmCmdStr = "" ModemError(ERR) Exit Sub End If '--Sometimes they just type AT to see if the modem is responding. If MdmCmdStr = "AT" Then MdmCmdStr = "" ModemError(OK) Exit Sub End If '--Now start dealing with the command strings... Dim tmpCmd As String If InStr(MdmCmdStr, "ATA") Then MdmCmdStr = "" End If If InStr(MdmCmdStr, "ATD ") Or InStr(MdmCmdStr, "ATDT ") Then GoDialOut(MdmCmdStr) MdmCmdStr = "" Exit Sub End If If InStr(MdmCmdStr, "ATI") Then Ser.Write("Internet Modem Emulator v" & ver & " by Terry Olsen" & vbCr) MdmErr = OK MdmCmdStr = "" 'Exit Sub End If If InStr(MdmCmdStr, "AT&V") Then Ser.Write("This will be our &V display page." & vbCr) MdmErr = OK MdmCmdStr = "" 'Exit Sub End If If InStr(MdmCmdStr, "ATZ") Then HangUp(True) MdmCmdMode = True MdmHookState = ModemHookState.OnHook MdmCmdStr = "" End If If InStr(MdmCmdStr, "E") Then tmpCmd = Mid(MdmCmdStr, InStr(MdmCmdStr, "E") + 1, 1) Debug.Write("E" & tmpCmd & ":") If Val(tmpCmd) > 1 Then MdmErr = ERR Else MdmEcho = Val(tmpCmd) End If MdmCmdStr = "" End If If InStr(MdmCmdStr, "H") Then tmpCmd = Mid(MdmCmdStr, InStr(MdmCmdStr, "H") + 1, 1) Debug.Write("H" & tmpCmd & ":") If Val(tmpCmd) > 1 Then MdmErr = ERR Else MdmHookState = Val(tmpCmd) HangUp(True) 'True = Locally initiated disconnect End If MdmCmdStr = "" End If If InStr(MdmCmdStr, "Q") Then tmpCmd = Mid(MdmCmdStr, InStr(MdmCmdStr, "Q") + 1, 1) Debug.Write("Q" & tmpCmd & ":") If Val(tmpCmd) > 1 Then MdmErr = ERR Else MdmEcho = Val(tmpCmd) End If MdmCmdStr = "" End If If InStr(MdmCmdStr, "S0") Then tmpCmd = Mid(MdmCmdStr, InStr(MdmCmdStr, "S0=") + 3, 1) Debug.Write("S0=" & tmpCmd & ":") If Val(tmpCmd) > 1 Then MdmErr = ERR Else MdmRingMode = Val(tmpCmd) End If MdmCmdStr = "" End If If InStr(MdmCmdStr, "V") Then tmpCmd = Mid(MdmCmdStr, InStr(MdmCmdStr, "V") + 1, 1) Debug.Write("V" & tmpCmd & ":") If Val(tmpCmd) > 1 Then MdmErr = ERR Else MdmResultCodeFormat = Val(tmpCmd) End If MdmCmdStr = "" End If ModemError(MdmErr) End Sub Private Sub ModemError(ByVal code As Integer) If MdmResultCodes = ModemResultCodes.Enabled Then If MdmResultCodeFormat = ModemResultCodeFormat.Text Then Debug.WriteLine("MdmErrCode: " & MdmErrorCode(code)) Ser.Write(vbCr & MdmErrorCode(code)) If code = 1 Then Ser.Write(" " & MdmBaud) Ser.Write(vbCr) Else Ser.Write(vbCr & code & vbCr) Debug.WriteLine("MdmErrCode: " & code) End If End If End Sub Private Sub GoDialOut(ByVal cmd As String) Dim port As Integer Dim IP As IPAddress Dim host As String '--First, get rid of the AT command cmd = cmd.Replace("ATDT ", "").Trim cmd = cmd.Replace("ATD ", "").Trim cmd = cmd.Trim(Chr(13)) 'Debug.WriteLine("CMD=" & cmd) '--Next, see if a port is specified cmd = cmd.Replace(",", ":") 'Change comma separator to colon cmd = cmd.Replace(" ", ":") 'change space separator to colon 'Debug.WriteLine("CMD=" & cmd) '--Define the port we'll use to dial out If cmd.Contains(":") Then port = Val(Mid(cmd, InStr(cmd, ":") + 1)) cmd = cmd.Remove(cmd.IndexOf(":")) Else port = 23 End If 'Debug.WriteLine("CMD=" & cmd) 'Debug.WriteLine("PORT=" & port) 'Exit Sub '--Now we check what kind of address we have. It could be: ' hostname.com, xx.xxx.xx.x, or WWWXXXYYYZZZ Dim IpNoDots As Boolean = True If Not cmd.Contains(".") Then If cmd.Length = 12 Then For i As Integer = 1 To 12 If Not (Mid(cmd, i, 1) >= "0" And Mid(cmd, i, 1) <= "9") Then IpNoDots = False : Exit For End If Next If IpNoDots = True Then cmd = cmd.Insert(9, ".") cmd = cmd.Insert(6, ".") cmd = cmd.Insert(3, ".") End If End If End If 'Debug.WriteLine("CMD=" & cmd) 'Debug.WriteLine("PORT=" & port) 'Exit Sub '--By the time we get here, we should have either a hostname or ' an IP address in the form of xxx.xx.xx.x Try IP = Dns.GetHostEntry(cmd).AddressList(0) Try host = Dns.GetHostEntry(IP).HostName Catch host = cmd End Try WriteStatus("Dialing: " & host & " (" & IP.ToString & ") on port " & port.ToString) Catch ex As SocketException WriteStatus("Error dialing " & cmd & ":" & port.ToString) WriteStatus("Error message:" & ex.Message) ModemError(NO_DIAL_TONE) Exit Sub End Try MdmCmdMode = False Dim IPE As New IPEndPoint(IP, port) Try TcpClt = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) TcpClt.BeginConnect(IPE, AddressOf DialOutConnected, Nothing) Catch ex As SocketException ModemError(NO_DIAL_TONE) WriteStatus(ex.Message) End Try End Sub Private Sub DialOutConnected(ByVal ar As IAsyncResult) Try TcpClt.EndConnect(ar) Catch ex As SocketException WriteStatus(ex.Message) MdmCmdMode = True ModemError(NO_ANSWER) Exit Sub End Try WriteStatus("Connection established.") ModemError(CONNECT) TcpClt.BeginReceive(RcvBuf, 0, RcvBuf.Length, SocketFlags.None, AddressOf ReceiveCallback, RcvBuf) End Sub Private Sub swGuardTimerFired(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) swGuardTimer.Stop() If Ser.BytesToRead < 1 Then MdmCmdMode = True ModemError(OK) Else MdmCmdMode = False If TcpClt Is Nothing Then Exit Sub TcpClt.Send(XmtBuf, SerByt, SocketFlags.None) End If End Sub End Module References Visible links 1. http://icopiedyou.com/wp-content/uploads/2015/07/InternetModem.zip