Skip to content

A Simple NetCat Program

Thomas Cherryhomes edited this page Oct 29, 2020 · 9 revisions

To help get started, we've provided a simple netcat 'nc' like program that echoes received data, and sends keypresses to the specified host.

Atari BASIC

The BASIC version uses the N: handler, and thus is very compact and easy to understand. It is described in detail in this video: https://www.youtube.com/watch?v=LxT6w9JHfKk

100 OPEN #1,12,3,"N1:TCP://BBS.FOZZTEXX.NET/":OPEN #2,4,0,"K:"
101 TRAP 140
110 IF PEEK(764)<>255 THEN GET #2,K:PUT #1,K:XIO 15,#1,12,3,"N:"
120 STATUS #1,A:BW=PEEK(747)*256+PEEK(746):IF BW=0 THEN 110
130 FOR M=1 TO BW:GET #1,C:PUT #16,C:NEXT M:GOTO 110
140 CLOSE #1:? "DISCONNECTED.":END 

You can load a copy of it by loading "D:DUMBTERM.BAS" from the atari-apps.irata.online/Networking/n-handler/n-handler.atr via TNFS.

Modifying:

  • Change the hostname on line 100.
  • You can set the translation on line 100, 3 = CR/LF, 2 = LF, 1 = CR, 0 = NONE. Also change it on line 110.

C

The C version can be found here: https://github.com/FujiNetWIFI/fujinet-apps/tree/master/netcat/src

It can be compiled with CC65: http://cc65.github.io/

It shows:

ACTION!

https://github.com/FujiNetWIFI/fujinet-apps/tree/master/netcat-action

NIO.ACT - Example Network I/O bindings

;
; #FujiNet Network I/O Library    
; For ACTION!
;
; Author: Thomas Cherryhomes
;  <thom.cherryhomes@gmail.com>
;
; These routines call the #Fujinet
; directly from SIO, and thus do
; not need the N: handler (NDEV)
;

MODULE

;
; PROCEED interrupt vars
;
CARD VPRCEDSAVE     ; Save vector for vprced
CARD VPRCED = $0202 ; Proceed vector
BYTE PACTL  = $D302 ; PIA Control for Proceed
BYTE trip           ; Trip FLAG.

;
; DVSTAT (Status)
;
BYTE DVSTAT = $02EA ; PTR TO DVSTAT
BYTE EXTERR = $02ED ; DVSTAT+3

;
; DEVICE CONTROL BLOCK (DCB)
;
BYTE DDEVIC = $0300 ; Device #
BYTE DUNIT  = $0301 ; Unit #
BYTE DCOMND = $0302 ; Command
BYTE DSTATS = $0303 ; <-> and error
CARD DBUF   = $0304 ; buffer
BYTE DTIMLO = $0306 ; timeout secs
BYTE DUNUSE = $0307 ; reserved
CARD DBYT   = $0308 ; pyld byte len
CARD DAUX   = $030A ; daux1/daux2
BYTE DAUX1  = $030A ; daux1
BYTE DAUX2  = $030B ; daux2

;
; Interrupt handler
;
; A9 01    LDA #$01
; 8D XX XX STA trip
; 68       PLA
; 40       RTI
; 
PROC ninterrupt_handler=*()
[$A9$01$8D trip $68$40]

;
; Enable Interrupt handler.
;
PROC nenableproc()

    trip=0
    VPRCEDSAVE=VPRCED
    VPRCED=ninterrupt_handler
    PACTL = PACTL % 1

RETURN

;
; Disable Interrupt handler.
;
PROC ndisableproc()

    trip=0
    VPRCED=VPRCEDSAVE

RETURN

;
; PROC to call SIO Vector (SIOV)
;
PROC siov=$E459()

;
; Get the unit number from devicespec
;
BYTE FUNC ngetunit(BYTE ARRAY ds)
    BYTE unit=1
                   
    IF ds(2)=': THEN
        unit=1
    ELSEIF ds(3)=': THEN
        unit=ds(2)-$30
    ELSE
        unit=1
    FI

RETURN (unit)

;
; Get status of last NIO operation,
; Return in DVSTAT
; 
; @param devicespec N: devicespec
;
PROC nstatus(BYTE ARRAY ds)

  DDEVIC = $71
  DUNIT  = ngetunit(ds)
  DCOMND = 'S     ; STATUS
  DSTATS = $40    ; Payload to Atari
  DBUF   = $02EA  ; status buffer
  DTIMLO = $1F    ; 32 second timeout
  DBYT   = 4      ; 4 byte payload
  DAUX1  = 0      ; R/W
  DAUX2  = 0      ; translation
  siov()   

RETURN

;
; Return error of last NIO operation.
; If SIO error = 144, then a status
; is done, and the extended err is 
; returned.
;
; @param devicespec N: devicespec
; @return error 1=successful
;
BYTE FUNC geterror(BYTE ARRAY ds)
  BYTE errno

  IF DSTATS=144 THEN
    nstatus(ds)
    errno=EXTERR
  ELSE
    errno=DSTATS
  FI

RETURN (errno)

;
; Open the N: device pointed to by
; devicespec.
; 
; @param devicespec N: devicespec
; @param trans - translation mode
;   0=NONE, 1=CR, 2=LF, 3=CR/LF
; @return error, 1=successful.
;
BYTE FUNC nopen(BYTE ARRAY ds, BYTE t)

  DDEVIC = $71
  DUNIT  = ngetunit(ds)
  DCOMND = 'O    ; OPEN
  DSTATS = $80   ; Write to fujinet
  DBUF   = ds    ; send devicespec
  DTIMLO = $1F   ; 32 second timeout
  DBYT   = 256   ; 256 byte payload
  DAUX1  = 12    ; R/W
  DAUX2  = t     ; translation
  siov();  

  IF DSTATS=1 THEN
      nenableproc()
  FI

RETURN (geterror(ds))

;
; Close the N: device pointed to by
; devicespec.
; 
; @param devicespec N: devicespec
; @return error, 1=successful.
;
BYTE FUNC nclose(BYTE ARRAY ds)

  DDEVIC = $71
  DUNIT  = ngetunit(ds)
  DCOMND = 'C    ; CLOSE
  DSTATS = $00   ; No Payload
  DBUF   = 0     ; send devicespec
  DTIMLO = $1F   ; 32 second timeout
  DBYT   = 0     ; No payload
  DAUX1  = 0
  DAUX2  = 0
  siov();  

  ndisableproc()

RETURN (geterror(ds))

;
; Read len bytes from N: device 
; pointed to by devicespec.
;
; @param devicespec N: devicespec
; @param buf The dest buffer
; @param len # of bytes to read
; @return error 1=successful
;
BYTE FUNC nread(BYTE ARRAY ds, BYTE ARRAY buf, CARD len)

  DDEVIC = $71
  DUNIT  = ngetunit(ds)
  DCOMND = 'R    ; READ
  DSTATS = $40   ; Atari<-Payload
  DBUF   = buf   ; send devicespec
  DTIMLO = $1F   ; 32 second timeout
  DBYT   = len   ; No payload
  DAUX   = len
  siov();  

RETURN (geterror(ds))

;
; Write len bytes to N: device 
; pointed to by devicespec.
;
; @param devicespec N: devicespec
; @param buf The src buffer
; @param len # of bytes to read
; @return error 1=successful
;
BYTE FUNC nwrite(BYTE ARRAY ds, BYTE ARRAY buf, CARD len)

  DDEVIC = $71
  DUNIT  = ngetunit(ds)
  DCOMND = 'W    ; WRITE
  DSTATS = $80   ; Payload->FujiNet
  DBUF   = buf   ; send devicespec
  DTIMLO = $1F   ; 32 second timeout
  DBYT   = len   ; No payload
  DAUX   = len
  siov();  

RETURN (geterror(ds))

NC.ACT - Main Program

; 
; A simple netcat program
; to show how to do basic network
; input and output.
;
; Author: Thomas Cherryhomes
;  <thom.cherryhomes@gmail.com>
;

INCLUDE "D2:SYS.ACT" ; ACTION! Runtime!
INCLUDE "D2:NIO.ACT" ; NETWORK I/O

MODULE

CARD BYTESWAITING=$02EA     ; # of bytes waiting
BYTE KP=$02FC               ; Key pressed?
BYTE ARRAY devicespec(256)  ; DeviceSpec
BYTE trans                  ; translation mode
BYTE localEcho              ; local echo off/on?
BYTE running                ; is program running?
BYTE ARRAY rxbuf(8192)      ; receive buffer

DEFINE KEYBOARD_IOCB="2"
DEFINE TRUE="1"
DEFINE FALSE="0"

;
; Prompt for URL
;
PROC getURL()
       PrintE("NETCAT--ENTER DEVICE SPEC?")
       InputS(devicespec)
       PutE()
       
       PrintE("TRANS--0=NONE, 1=CR, 2=LF, 3=CR/LF?")
       trans=InputB()
       PutE()

       PrintE("LOCAL ECHO--0=NO, 1=YES?")
       localEcho=InputB()
       PutE()
RETURN

;
; Handle nc output
;
PROC ncoutput()
       BYTE ARRAY ch(1)
       BYTE err

       IF KP=$FF THEN
           RETURN
       FI

       ch(0)=GetD(KEYBOARD_IOCB)

       IF localEcho=1 THEN
           Put(ch(0))
       FI

       err=nwrite(devicespec,ch,1)

       IF err<>1 THEN
           Print("Write Error: ")
           PrintB(err)
           running=FALSE
       FI

RETURN

;
; Handle nc input
;
PROC ncinput()
       BYTE err
       CARD I

       IF trip=0 THEN
           RETURN
       FI

       nstatus()

       IF EXTERR=136 THEN
          PrintE("Disconnected.")
          running=FALSE
          RETURN
       FI

       IF BYTESWAITING=0 THEN
          RETURN 
       FI

       IF BYTESWAITING>8192 THEN
          BYTESWAITING=8192
       FI

       ; Do the network read.
       err=nread(devicespec,rxbuf,BYTESWAITING)

       IF err<>1 THEN
           Print("Read Error: ")
           PrintB(err)
           running=FALSE
           RETURN
       FI
       
       ; Drain/display rx buffer
       FOR I=0 TO BYTESWAITING-1
       DO
           Put(rxbuf(I))
       OD

       ; Done, reset interrupt
       trip=0
       PACTL=PACTL%1

RETURN

;
; The main Netcat function
;
PROC nc()
       BYTE err

       err=nopen(deviceSpec,trans)

       IF err<>1 THEN
           Print("Open Error: ")
           PrintB(err)
           RETURN
       FI

       ; flag program as running.
       running=1
               
       ; Open keyboard
       Open(KEYBOARD_IOCB,"K:",4,0)

       WHILE running = TRUE  
         DO
         ncoutput()
         ncinput()
         OD

       PrintE("Bye.")

       ; Clean up
       Close(KEYBOARD_IOCB) ; close kybd
       nclose(deviceSpec)

RETURN

;
; Main entrypoint
;
PROC main()
       getURL()
       nc()
RETURN

Example devicespecs:

N:TCP://BBS.FOZZTEXX.NET/ (trans 3, local echo N)
N:TCP://CAVEMUSH.COM:6116/ (trans 3 local echo Y)
N:TCP://SOUTHERNAMIS.COM/ (trans 0, local echo N)

Any not here?

Do you have an equivalent in other languages to put here, add it!

Clone this wiki locally