view level1/cmds/telnet.as @ 2808:6ad3087af262 lwtools-port

Fixed issue with telnet putting out junk data at first connect.
author Boisy Pitre <boisy.pitre@nuance.com>
date Fri, 01 Feb 2013 21:49:16 -0600
parents 3b7b5021f8bc
children d660d443fe5f
line wrap: on
line source

********************************************************************
* telnet - telnet client
*
* $Id$
*
* Notes:
* This utility works in similar fashion to telnet commands on other systems.
* The user can telnet to a location, and once there, press the TELESCAPE key
* to invoke telnet command mode. 
*
* Two sets of path options are kept for the standard input.  The first is an
* unmodified copy and the second is a modifable copy.  The second is set up
* for raw mode and is used when communicating with the host.  The first will
* be used when going into telnet command mode or exiting the telnet program.
*
* The signal handler catches the S$HUP signal and shuts down gracefully.  It
* also looks for the ABORT/QUIT characters and relays them to the session.
*
* Reference used: http://www.faqs.org/rfcs/rfc854.html
*
* Edt/Rev  YYYY/MM/DD  Modified by
* Comment
* ------------------------------------------------------------------
*   1      2010/01/02  Aaron Wolfe
* Most basic implementation using new DW utility API
*
*   2      2010/01/06  Boisy G. Pitre
* Reformatted and optimized source. Added SS.Opt support, added telnet
* command mode which can be entered by pressing the TELESCAPE key.
*
*   3      2010/01/07  Boisy G. Pitre
* Reworked buffer processing routine.
*
*   4      2010/01/12  Boisy G. Pitre
* We allow host to do echo if it wants, we also now advertise the
* escape character when a connection is successful.
*
*   5      2010/01/15  Boisy G. Pitre
* Modified to be an rma assembled module and use the netlib library.

* Set to 1 if you want to see telnet CTRL chars from host
DEBUG          set       0

               nam       telnet
               ttl       program module

               section   __os9
type           set       Prgrm
lang           set       Objct
attr           set       ReEnt
rev            set       $00
edition        set       1
stack          set       200
               endsect

               section   bss
connected      rmb       1
netdatardy     rmb       1
keydatardy     rmb       1
lastsig        rmb       1
port           rmb       2
hostname       rmb       2
pbuffer        rmb       256
pbufferl       equ       *
pbend          rmb       2
cbuffer        rmb       256
ccount         rmb       1
opts           rmb       32
orgopts        rmb       32
tcmdbufl       equ       32
tcmdbuf        rmb       tcmdbufl
portdev        rmb       10
netpath        rmb       1
outpath        rmb       1
numbyt         rmb       1
state          rmb       1
telctrlbuf     rmb       3
               endsect

               section   code

TELESCAPE      equ       'Y-$40              * CTRL-Y

NetSig         equ       32
KeySig         equ       33

SE             equ       240                 * end of subnegotiation parameters
NOP            equ       241                 * no operation
DataMark       equ       242                 * the data stream portion of a Synch. This should always be accompanied by a TCP Urgent notification.
Break          equ       243                 * NVT character BRK.
IntProc        equ       244                 * the function IP
AbortOut       equ       245                 * the function AO.
AreUThere      equ       246                 * the function AYT
EraseChar      equ       247                 * the function EC.
EraseLine      equ       248                 * the function EL.
GoAhead        equ       249                 * the GA signal.
SB             equ       250                 * indicates that what follows is subnegotiation of the indicated option.
WILL           equ       251                 * indicates the desire to begin performing, or confirmation that you are now performing, the indicated option.
WONT           equ       252                 * indicates the refusal to perform, or continue performing, the indicated option.
DO             equ       253                 * indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option.
DONT           equ       254                 * indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option.
IAC            equ       255                 * data byte 255.

* Telnet Options
TO_ECHO        equ       $01

escprompt      fcc       /Escape character is '^/
               fcb       TELESCAPE+$40
               fcc       /'./
crlf           fcb       C$CR,C$LF
escpromptl     equ       *-escprompt
tprompt        fcc       /telnet> /
tpromptl       equ       *-tprompt

trying         fcc       /Trying.../
               fcb       C$CR
tryingl        equ       *-trying

peerclosm      fcc       /Connection closed by foreign host./
               fcb       C$CR
peerclosml     equ       *-peerclosm

using          fcc       'Using port '
usingl         equ       *-using

defportstr     fcc       '23'
               fcb       0
               
peerclosed
               clr       connected,u
               lda       #1
               leax      peerclosm,pcr
               ldy       #peerclosml
               os9       I$WritLn
               lbra      done

* signal intercept routine
sigint                   
               stb       lastsig,u           * save our signal received
               cmpb      #KeySig
               bne       netchk
               inc       keydatardy,u
               rti
netchk         cmpb      #NetSig
               bne       hupchk
               inc       netdatardy,u
               rti
hupchk         cmpb      #S$HUP              * disconnect from peer signal received?
               beq       peerclosed          * yep, exit nicely
               lda       #$03                * usual interrupt character
               cmpb      #S$Intrpt
               beq       chksig
               lda       #$05                * usual quit character
               cmpb      #S$Abort
               bne       sigex
chksig         tst       connected,u
               lbeq      done
               pshs      a
               leax      ,s
               ldy       #$0001
               lda       netpath,u
               os9       I$Write
               puls      a
sigex          rti       

* save initial parameters
__start        pshs      x
               clr       connected,u
               clr       netdatardy,u
               clr       keydatardy,u

* setup signal intercept
               leax      sigint,pcr
               os9       F$Icpt

* get path options (original and modifiable copy)
               leax      orgopts,u
               ldd       #SS.Opt
               os9       I$GetStt
               lbcs      errex2

               leax      opts,u
               ldd       #SS.Opt
               os9       I$GetStt
               lbcs      errex2

* set up our path to be raw (we will actually set it later)
               leax      PD.UPC-PD.OPT,x
               ldb       #PD.INT-PD.UPC
rawloop        clr       ,x+
               decb      
               bne       rawloop 

* set address as nul terminated string
addrloop
               ldx       ,s
addrloop2
               lda       ,x+
               cmpa      #C$SPAC
               beq       nilit
               cmpa      #C$CR
               beq       nilit
               bra       addrloop2

nilit          clr       -1,x     nil terminate previous param
               cmpa      #C$CR    are we at end of command line?
               beq       defaultport yep, set default port

skipspc        lda       ,x+
               cmpa      #C$CR
               beq       defaultport
               cmpa      #C$SPAC
               beq       skipspc
* if here, we have a second parameter... probably port number
               leay       -1,x
               bra        parsedone
defaultport    leay       defportstr,pcr
parsedone      puls       x

* X holds pointer to nul terminated address
* Y holds port number string (nil terminated)
* do the open and connect
               pshs       y
               std        port,u
               stx        hostname,u

* announce our attempt to try to connect
               lda        #1
               ldy        #tryingl
               leax       trying,pcr
               os9        I$WritLn
               
               lbsr       TCPOpen
               puls       y
               lbcs       errex1
               sta        netpath,u
               ldx        hostname,u
               lbsr       TCPConnectToHost
               lbcs       errex2
               lbsr       RawPath
               
* we're connected...
               lda       #1
               sta       connected,u
               leax      escprompt,pcr
               ldy       #escpromptl
               os9       I$WritLn

* make our stdin opts raw
               leax      opts,u
               ldd       #SS.Opt
               os9       I$SetStt
               lbcs      errex2

* setup data ready signal on stdin
               clra
               ldb       #SS.SSig
               ldx       #KeySig
               os9       I$SetStt
               lbcs      errex2

* setup data ready signal on netpath
               lda       netpath,u
               ldb       #SS.SSig
               ldx       #NetSig
               os9       I$SetStt
               lbcs      errex2

* response loop
* check for typed characters
rloop
               pshs      cc				save interrupt state
               orcc      #IntMasks      mask interrupts
               tst       netdatardy,u
               bne       GetNetData
               tst       keydatardy,u
               bne       GetKeyData
* sleep until signal
               ldx       #$0000
               os9       F$Sleep
               puls      cc              
               bra       rloop

GetKeyData     puls      cc
               dec       keydatardy,u
               bra       stdinc

GetNetData     puls      cc
               dec       netdatardy,u
               lda       netpath,u
               ldb       #SS.Ready
               os9       I$GetStt
               lbcc      serinc              read and print the byte
               bra       rloop

* telnet command interface
cmdint                   
* restore original opts for now
               leax      orgopts,u
               ldd       #SS.Opt
               os9       I$SetStt
               bcs       errex2

* write CR		  
               lda       #1
               leax      crlf,pcr
               ldy       #$02
               os9       I$Write

* show prompt
cmdloop                  
               lda       #1
               leax      tprompt,pcr
               ldy       #tpromptl
               os9       I$Write

* read command
               leax      tcmdbuf,u
               ldy       #tcmdbufl
               clra      
               os9       I$ReadLn
               bcs       errex2

* process command
               lda       ,x
               anda      #$5F                * make uppercase

               cmpa      #C$CR
               beq       ret2tel             * just CR... return to telnet session
               cmpa      #'Q
               beq       okex
               bra       cmdloop

* return to telnet session
ret2tel                  
               leax      opts,u
               ldd       #SS.Opt
               os9       I$SetStt
               bcs       errex2

* read one byte from stdin, send to server
stdinc         ldy       #$0001
               clra      
               leax      numbyt,u
               os9       I$Read
               bcs       errex2

* check if it is an escape character
               lda       ,x
               cmpa      #TELESCAPE
               beq       cmdint

outc           ldy       #$0001
               lda       netpath,u
               leax      numbyt,u
               os9       I$Write
               bcs       errex2

* setup data ready signal on stdin
               clra
               ldb       #SS.SSig
               ldx       #KeySig
               os9       I$SetStt
               lbcs      errex2

               lbra      rloop

done
okex           clrb                          *no errors here
* close port
errex2
               pshs      b,cc
               lda       netpath,u
               lbsr      TCPDisconnect
               clr       connected,u
               
               leax      orgopts,u
               ldd       #SS.Opt
               os9       I$SetStt            *restore original path options
               puls      b,cc
               
errex1         os9       F$Exit              *goodbye

* read B bytes from serial
serinc         clra      
               tfr       d,y
               lda       netpath,u
               leax      pbuffer,u
               os9       I$Read
               bcs       errex2

* set buffer
               tfr       y,d
               leax      pbuffer,u
               abx       
               stx       pbend,u             *set end addr
               clrb      
               leax      pbuffer,u
               leay      cbuffer,u
               clr       ccount,u

* call buffer processor
               bsr       procbuf

* print buffer
               ldb       ccount,u
               beq       serincex
               clra      
               tfr       d,y
               lda       #1
               leax      cbuffer,u
               os9       I$Write
               bcs       errex2

* return to loop
serincex
* setup data ready signal on netpath
               lda       netpath,u
               ldb       #SS.SSig
               ldx       #NetSig
               os9       I$SetStt
               lbcs      errex2

               lbra      rloop



* buffer processing routine
procbuf        cmpx      pbend,u
               beq       procbufex
* not at end of buffer, get next char
               lda       ,x+
* check state to see what we do with this byte
               tst       state,u
               bne       telctrl
               cmpa      #IAC
               beq       telstate
               sta       ,y+
               inc       ccount,u
               bra       procbuf
procbufex      rts       

conv           anda      #$0F
               cmpa      #$09
               bgt       alpha
               adda      #$30
               fcb       $8C
alpha          adda      #$41-$0A
               rts

               IFEQ      DEBUG-1
printhex       pshs      d,x,y
               bsr       conv
               pshs      a
               lda       1,s
               lsra
               lsra
               lsra
               lsra
               bsr       conv
               pshs      a
               lda       #'$
               pshs      a
               leax      ,s
               ldy       #$0003
               lda       #$01
               os9       I$Write
               leas      3,s
               puls      d,x,y,pc
               ENDC
       
telstate       sta       telctrlbuf,u
               IFEQ      DEBUG-1
               bsr       printhex
               ENDC
               inc       state,u
               bra       procbuf

clrngo         clr       state,u
               bra       procbuf
 
* handles telnet control sequence... A = byte
telctrl
               IFEQ      DEBUG-1
               bsr       printhex
               ENDC
               ldb       state,u
               cmpb      #1
               bne       telctrl2
               cmpa      #SB
               ble       clrngo
               sta       telctrlbuf+1,u
               inc       state,u
               bra       procbuf
telctrl2       sta       telctrlbuf+2,u
               clr       state,u
* here we have a complete telnet control sequence
               ldd       telctrlbuf+1,u
               cmpa      #DO
               beq       dowont
               cmpa      #WILL
               lbne      procbuf
               cmpb      #TO_ECHO
               bne       dodont
* allow host to echo
               lda       #DO
               fcb       $8C
dodont         lda       #DONT
               fcb       $8C
dowont         lda       #WONT
               sta       telctrlbuf+1,u
               pshs      x,y
               ldy       #3
               lda       netpath,u
               leax      telctrlbuf,u
               os9       I$Write
               puls      x,y
               lbra      procbuf

               endsect