perm filename EFTP.FAI[S,NET] blob
sn#694899 filedate 1982-01-13 generic text, type C, neo UTF8
COMMENT ā VALID 00013 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 TITLE EFTP
C00010 00003 getsix tloop isalpn lcheck rjust rjloop
C00011 00004 rdfile rdppm errspc winxit errlf
C00013 00005 yesno gtmode imode amode iamode GTMOD1
C00016 00006 error dally dloop mtadr OCTOUT
C00018 00007 prthst getchk getck1 chkchk cpopj1 cpopj badchk putchk
C00022 00008 dskblk filopn outopn inopn filin filout sendak
C00027 00009 start getcmd quit
C00029 00010 receiv listen OLOOP oloop1 oldpup LISBAD enddat try0 try oset OLOOP done done1 timout rcvbad eftpgb eftgb1 eftgb2 eftgb3 eftgb4 eftgb5
C00037 00011 A=1
C00041 00012 REPWAT osend
C00043 00013 send octin octin1 inerr octdon fread iascii finlp finlp1 goon finfin sndout noffin finset finlp finlp1 fineof eftppb sndbad eftpb2
C00051 ENDMK
Cā;
TITLE EFTP
opdef call [pushj 17,]
opdef ret [popj 17,]
p=17
pup=12 ; to contain address of pup for byte pointer and routines
efsock==20 ;Well known socket for EFTP receive
enhadr==302 ;Our host number
.pteda==30 ;PUP type for EFTPData
.pteak==31 ;EFTPAck
.pteen==32 ;EFTPEnd
.pterr==4 ;PUP type for error
.pteab==33 ;EFTPAbort
pupch==1 ;channel for listener
diskch==2 ;channel for writing out data.
REPEAT 0,<
pupmsg: 0 ;byte(8)dest,source(16)1000
0 ;BYTE(16)PUPLENGTH(8)TCTL,PUPTYPE
0 ;byte(16)pupident1,pupident2
0 ;byte(8)destnet,desthost(16)destsoc1
0 ;byte(16)destsock2(8)srcnet,srchost
0 ;byte(16)srcsock1,srcsock2
block =134 ;rest of pup
pupout: 0 ;Ethernet header slot
block 1 ;fill in len,type
block 1 ;fill in ID here
block 1 ;fill in dest net,host, sock1
byte (16) 0 (8) 0,enhadr ;fill in destsock2,our net address
block 1 ;fill in our socket number
block =134 ;rest of pup
;Pointers to pup fields for LDB and DPB into pup pointed to by ac PUP
PUPLEN: POINT 16,1(pup),15 ; Pup length
PUPTRN: POINT 8,1(pup),23 ; transport control
PUPTYP: POINT 8,1(pup),31 ; Pup type
PUPID: POINT 32,2(pup),31 ; Pup identifier
PUPDHN: POINT 16,3(pup),15 ; destination network/host
PUPDNT: POINT 8,3(pup),7 ; destination network
PUPDHS: POINT 8,3(pup),15 ; destination host
PUPDS1: POINT 16,3(pup),31 ; destination socket (first part)
PUPDS2: POINT 16,4(pup),15 ; destination socket (second part)
PUPSHN: POINT 16,4(pup),31 ; source network/host
PUPSNT: POINT 8,4(pup),23 ; source network
PUPSHS: POINT 8,4(pup),31 ; source host
PUPSSK: POINT 32,5(pup),31 ; source socket
PUPDAT: POINT 8,6(pup) ;pointer to 8-bit bytes in data.
pupbdt: point 32,6(pup) ;pointer to 32-bit bytes.
>;REPEAT 0
tmode: 0 ;transfer mode for disk output. default = 0 = ASCII.
;idone: 0 ;flag to indicate last data pup being sent
fbuf: block 3
fblock: block 4 ;block for file name.
pdlen==30
pdlist: block pdlen
iniblk: 13 ;block for OPENs on PUP:, EFTP buffered mode
SIXBIT/PUP/
xwd eohdr,eihdr
eihdr: block 3
eohdr: block 3
ercvmb: 1 ;Opcode: Listen
0 ;Status
efsock ;Local socket (our socket)
0 ;Don't wait for connection?
8 ;Byte size irrelevant for PUP
0 ;Don't care what socket
0 ;or foreign host number
esndmb: 0 ;Opcode: Connect
0 ;Status
lsock: 0 ;Local socket (let system invent one)
0 ;Don't wait for connection?
8 ;Byte size irrelevant for PUP
fsock: efsock ;Their socket number = EFTP
host: 0 ;Foreign host number to connect to.
crlf: byte (7) 15,12
previd: block 1 ;remember ID to check sequencing
lookfl: block 1 ;If zero, we are listening link and need specific lookup
lfmode: block 1 ;if non-zero, add LF after CR.
rchar: block 1 ;prev. char on output, used to detect CRLF's
bitsh: block 1 ;NZ if using Lefthand 32 bits in word
;getsix tloop isalpn lcheck rjust rjloop
getsix: setz 1,
movei 2,6
move 3,[point 6,1]
tloop: inchwl 4
cail 4,"a"
caile 4,"z"
jrst lcheck
subi 4,"a"-"A"
isalpn: subi 4,"A"-'A'
sojl 2,tloop
idpb 4,3
jrst tloop
lcheck: caige 4,"0"
ret
caig 4,"9"
jrst isalpn
cail 4,"A"
caile 4,"Z"
ret
jrst isalpn
rjust: movei 2,6
rjloop: trnn 1,77
sojg 2,[
lsh 1,-6
jrst rjloop]
ret
;rdfile rdppm errspc winxit errlf
; Procedure to read file names
rdfile: setzm fblock
setzm fblock+1
setzm fblock+2
setzm fblock+3
call getsix
movem 1,fblock
cain 4,15
jrst winxit
caie 4,175
cain 4,12
jrst winxit
caie 4,"."
jrst rdppm
call getsix
movem 1,fblock+1
cain 4,15
jrst winxit
caie 4,175
cain 4,12
jrst winxit
rdppm: caie 4,"["
jrst [
errspc: outstr [asciz /Illegal File specification
/]
jrst errlf]
call getsix
call rjust
hrlzm 1,fblock+3
caie 4,"."
cain 4,","
caia
jrst errspc
call getsix
call rjust
hrrm 1,fblock+3
CAIN 4,15
JRST WINXIT ;Can omit right braket
CAIE 4,12
cain 4,"]"
JRST WINXIT
JRST ERRSPC
winxit: aos (p)
errlf: caie 4,12
cain 4,175
ret
inchwl 4
jrst errlf
;yesno gtmode imode amode iamode GTMOD1
;YESNO - wait for yes or no answer, ret +2 for yes, +1 for no
;Clobbers ac4
yesno: inchrw 4
caie 4,"y"
cain 4,"Y"
jrst cpopj1
caie 4,"n"
cain 4,"N"
jrst cpopj
outstr [asciz/
Y or N? /]
CLRBFI
jrst yesno
gtmode: setzm lfmode ;don't convert CRLF's (in case he says image)
setzm bitsh ;don't shift bits (in case he says ascii)
outstr [asciz/Mode: /]
inchrw 4
caie 4,"i" ;see if it is an "i".
cain 4,"I"
jrst imode ;we want image mode.
caie 4,"a"
cain 4,"A"
jrst amode
OUTSTR [ASCIZ/Legal modes are:
A ASCII Mode
I IMAGE Mode
/]
jrst gtmode
imode: outstr [asciz /MAGE mode
/]
movei 1,10
MOVSI 2,(<point =36,0>) ;point to 36 bit word)
rorl: outstr [asciz/Use Righthand or Lefthand 32 bits?/]
inchrw 4
caie 4,"r"
cain 4,"R"
jrst right
caie 4,"l"
cain 4,"L"
jrst left
outstr [asciz/
L is probably right for anything from MAXC or some random file;
R is what you want for .DVI files.
/]
CLRBFI
jrst rorl
left: setom bitsh ;if using left 32 bits, need to shift
jrst gtmod1 ;now ready to go on.
right: setzm bitsh ;if usring right 32 bits, then don't shift
jrst gtmod1
amode: outstr [asciz/SCII mode
/]
movei 1,0
MOVSI 2,(<point 7,0>) ;ASCII mode: 7-bit bytes
hrrz 3,dskblk+2 ;get output buffer spec (0 if input file)
jumpe 3,iamode ;jump if input file
outstr [asciz/Convert CRLF to CR (normal to send to Altos)?/]
skipa
iamode: outstr [asciz/Convert CR to CRLF (normal when receiving from Altos)?/]
setom lfmode ;assume YES - add in LF after CR.
call yesno ;skip if answer is yes
setzm lfmode ;NO - don't convert
gtmod1: outstr crlf
movem 1,tmode
MOVEM 2,fbuf+1 ;store byte size in buffer header
ret
;error dally dloop mtadr OCTOUT
;Misc routines
error: outstr [asciz/Something's wrong!
/]
EXIT 1,
ret
dally: acctim 6, ;get time and date
hrrz 6,6 ;time only
dloop: setz 5, ;sleep for 1/60 sec.
SLEEP 5,
mtape pupch,mtadr ;see if input waiting
skipa
jrst cpopj1 ;if pup received
acctim 7, ;get new time
hrrz 7,7
sub 7,6 ;subract old time
camge 7,10 ;see if greater than limit in ac 10
jrst dloop ;keep waiting
ret ;report failure
mtadr: 4
mtstat: block 1 ;status info returned here (not really)
; Routine to output numbers in octal
;accepts ( and clobbers ) number in ac1
OCTOUT: IDIVI 1,=8 ; extract a digit
PUSH P,2 ; save it on the stack
SKIPE 1 ; extracted all digits?
CALL OCTOUT ; no - call recursively to get next digit
POP P,1 ; get digit from stack
ADDI 1,"0" ; convert to ASCII
OUTCHR 1 ; output on the terminal
RET ; go for next digit or return
;prthst getchk getck1 chkchk cpopj1 cpopj badchk putchk
REPEAT 0,<
;Print source net#host# from PUP
prthst: ldb 1,pupsnt ;source net
call octout
outchr ["#"]
ldb 1,pupshs ;source host
call octout
outchr ["#"]
ret
;Generate checksum for PUP pointed to by ac PUP, return in ac1
;Checksum is generated by "ones-complement left add-and-cycle"
;Clobbers ac's 1-4
getchk: ldb 4,puplen ;get pup length to ac4
addi 4,1 ;round up for possible garbage byte
lsh 4,-1 ;divide by two for # 16bit words
subi 4,1 ;don't look at checksum word
move 3,[point 16,1(pup)] ;first word for checksum
setz 1, ;use to accumulate checksum
getck1: ildb 2,3 ;get a word
add 1,2 ;add it into ac2
trze 1,1b19 ;zero overflow bit, skip if it wasn't set
aoj 1, ;add in overflow bit to simulate 1's-complement
lsh 1,1 ;shift bits left
trze 1,1b19 ;skip if overflow bit not set, zero it
aoj 1, ;add it in on right
sojg 4,getck1 ;go until we are done
cain 1,177777 ;see if -0
setz 1, ;make into real 0
ret
;CHKCHK checks a checksum from ac PUP, returns +1 on failure, +2 on success.
chkchk: ldb 1,puplen ;get length
addi 1,1
lsh 1,-1 ;#16 bit words
addi 1,1 ;If odd then checksum is in left of next word
idivi 1,2 ;#32 bit words to ac1, ac2=0 if left, 1 if right
add 1,pup ;get word with checksum in it
hrli 1,(<point 16,0,15>) ;point to left half
skipe 2 ;skip if checksum is in left half
hrli 1,(<point 16,0,31>) ;otherwise point to right half
ldb 5,1 ;GET CHECKSUM (finally)
cain 5,177777 ;skip if no checksum
jrst cpopj1
call getchk ;compute data checksum to ac1
camn 1,5 ;skip if doesn't match
>;REPEAT 0
cpopj1: aos (p)
cpopj: ret
REPEAT 0,<
badchk: outstr [asciz/Bad checksum, pup ignored
/]
jrst listen ;Ignore bad checksum
;PUTCHK computes checksum and enters it in pup in (PUP)
putchk: push p,2 ;save it
push p,3
call getchk ;get checksum to ac1
idpb 1,3 ;put it in place
pop p,3
pop p,2 ;restore it
ret
>;REPEAT 0
;dskblk filopn outopn inopn filin filout sendak
dskblk: 10 ;data mode 10
sixbit /DSK/
block 1 ;fill in dbuf or dbuf,,0
;GETNAM gets a good filename
filopn: outstr [asciz/Local file name:/]
call rdfile
jrst filopn
OPEN diskch,dskblk
call error
ret
;OUTOPN opens a file for output, getting name from user
outopn: movsi 1,fbuf
movem 1,dskblk+2
call filopn
ENTER diskch,fblock
jrst [outstr [asciz /ENTER failed. Re-type file specs!
/]
jrst outopn]
call gtmode ;set up mode correctly
OUTBUF diskch,
ret
;INOPN opens a file for input, getting name from user
inopn: movei 1,fbuf
movem 1,dskblk+2
call filopn
LOOKUP diskch,fblock
jrst [outstr [asciz/LOOKUP failed. re-type file specs!
/]
jrst inopn]
INBUF diskch,1
call gtmode ;set up mode correctly
ret
;FILIN input a byte from the file (diskch) to ac1
filin: sosg fbuf+2
IN diskch, ;do input, skip if eof
skipa
jrst cpopj ;+1 (error) return
ildb 1,fbuf+1
skipe bitsh ;skip if don't need to shift bits (reading left half or ascii mode)
lsh 1,-4 ;shift 4 bits right from left 32 bits of 36
jrst cpopj1 ;+2 success return
;FILOUT output a byte from ac1 to the file (DISKCH)
filout: sosg fbuf+2 ;decrement byte count
OUTPUT diskch, ;if no bytes, output buffer
skipe bitsh ;skip if don't need to shift bits (writing left half or ascii mode)
lsh 1,4 ;shift bits to left side
idpb 1,fbuf+1 ;put byte in buffer
ret
REPEAT 0,<
;get ready to acknowledge pups.
rlink: setom lookfl ;don't come here again
movei PUP,pupmsg
ldb 1,pupshn ;get source host/net to ac1
movem 1,host ;put it in lookup block
ldb 2,pupssk ;get foreign socket to ac2
movem 2,fsock ;put it in to lookup block
movei 4,efsock ;Well known socket number to ac4
movem 4,lsock ;is our local socket.
LOOKUP pupch,pupbl ;establish link
call error
movei PUP,pupout
dpb 4,pupssk ;source socket in new pup
dpb 1,pupdhn ;old source is new dest.
idivi 2,1b19 ;source socket word 1 in ac2, word 2 in ac3
dpb 2,pupds1 ;old source socket
dpb 3,pupds2 ;in two pieces into dest. socket.
setz 1,
dpb 1,puptrn ; zero transport control
movei PUP,pupmsg
ret
sendak: ldb 3,pupid ;get ID number
movei PUP,pupout ;REdefine current pup to be output one.
dpb 3,pupid ;put ID in new pup
movei 1,.pteak ;I'm an acknowledgement.
dpb 1,puptyp
movei 1,=22 ;length for ACK
dpb 1,puplen ;put it in
call putchk
OUT pupch,pupout ;send it out
ret
call error
>;REPEAT 0
;start getcmd quit
start: reset
move p,[iowd pdlen,pdlist]
OPEN pupch,iniblk
call error
getcmd: outchr ["*"] ;parse command from user
inchrw 4
caie 4,"s"
cain 4,"S"
jrst send
caie 4,"r"
cain 4,"R"
jrst receiv
caie 4,"q"
cain 4,"Q"
jrst quit ;If not valid then give help message
outstr [asciz/
S -- Send from SAIL to the Ether or VAX.
R -- Receive a file from the Ether or VAX.
Q -- Quit
/]
jrst getcmd ;and try again
quit: outstr [asciz/uit
/]
exit
;receiv listen OLOOP oloop1 oldpup LISBAD enddat try0 try oset OLOOP done done1 timout rcvbad eftpgb eftgb1 eftgb2 eftgb3 eftgb4 eftgb5
receiv: outstr [asciz/eceive
/]
; Start listening for PUPs to acknowledge.
setzm lookfl ;say no specific link
mtape pupch,ercvmb ;specify listen on socket 3 from anywhere.
hrrz 1,ercvmb+1 ;Get status
jumpn 1,[outstr [asciz/Someone is already using EFTP, try again later/]
jrst done]
setom previd ;No ID's yet, so previous is -1
call outopn ;open output file
OUTSTR [asciz/ Now go to your ALTO and type >EFTP <yourfilename> to SAIL <CR>
/]
;Now we should have everything set up to listen...
REPEAT 0,<
listen: IN pupch,pupmsg ;read it in
SKIPA
call error
movei PUP, pupmsg ;define current PUP for byte pointer, subrs
call chkchk ;check checksum
jrst badchk
outchr ["."]
skipn lookfl ;skip unless this is first rec'd pup
call rlink
ldb 1,puptyp ;get pup type
cain 1,.pteen ;if an end
jrst enddat ;go to enddat
caie 1,.pteda ;otherwise must be EFTPDATA
jrst LISBAD ;Pup other than data or end data
ldb 1,pupid
camg 1,previd ;Skip unless this is a duplicate pup
jrst oldpup ;If this is not next seq. number, ignore it.
movem 1,previd ;remember previous ID
ldb 2,puplen ;get length
subi 2, =22 ;get data length.
MOVE 3,PUPDAT ;Data byte pointer for ASCII mode
skipn tmode ;skip if image mode
jrst oloop ;jump if ascii mode
idivi 2,4 ;get # of 32 bit words
move 3,pupbdt ;binary (32-bit) data pointer
OLOOP: ILDB 1,3 ;get a data byte
call filout ;send it to the output file.
CAIN 1,15 ;skip if not CR?
skipn lfmode ;if zero, don't add LF
jrst oloop1 ;not a CR or not adding LF's
MOVEI 1,12 ;otherwise output the LF
CALL FILOUT
oloop1: SOJG 2,OLOOP ;go until done.
oldpup: call sendak ;send an acknowledgement.
jrst listen
;here when a pup other than data or end of data pup is seen.
LISBAD: CALL BADTYP ;process peculiar pups
JFCL
JRST LISTEN ;mustn't have been fatal error
enddat: outchr ["!"]
CLOSE diskch,
movei PUP,pupmsg ;pup is INPUT
ldb 1,pupid
movem 1,previd
try0: call sendak ;send out end reply.
try: movei 10,=10 ;wait 10 seconds
call dally
jrst done ;2nd end got lost, not to worry.
IN pupch,pupmsg ;read in end-reply-reply, or another end.
SKIPA
call error
movei PUP, pupmsg ;define current PUP for byte pointer, subrs
ldb 1,puptyp ;get pup type
caie 1,.pteen ;is it EFTPEND?
jrst try ;if not, ignore it.
ldb 1,pupid
camg 1,previd ;done if this is greater ID = 2nd end
jrst try0 ;old end: acknowledge it and go back to waiting
>;REPEAT 0
movei 1,=8
skipn tmode ;skip if image mode
jrst oset ;jump if ascii mode
movei 1,=32
oset: dpb 1,[point 6,eihdr+1,11]
OLOOP: call eftpgb ;get a data byte
jrst done ; EOF
call filout ;send it to the output file.
CAIN 1,15 ;skip if not CR?
skipn lfmode ;if zero, don't add LF
jrst oloop ;not a CR or not adding LF's
MOVEI 1,12 ;otherwise output the LF
CALL FILOUT
jrst oloop ;go until done.
done: CLOSE diskch,
outstr [asciz/
Data transfer completed./]
done1: RELEASE pupch,
outstr [asciz/
/]
CLRBFI
jrst start
timout: outstr [asciz/
time out/]
rcvbad: releas diskch,3
jrst done1
eftpgb: sosle eihdr+2 ;Any bytes left?
jrst eftgb5 ; Yes, use them
in pupch, ;Get another buffer from Ether
jrst eftgb2 ; No errors
stato pupch,20000 ;EOF?
jrst eftgb1 ; No, some other error
stato pupch,747600 ;Any other random bits?
popj p, ;
eftgb1: outstr [asciz/Error reading from Ethernet. Status = /]
getsts pupch,1
call octout
jrst rcvbad
eftgb2: move 1,eihdr ;get buffer header
add 1,1(1) ;Find last word in buffer
move 1,1(1) ;Get that word
andi 1,7 ;look at low order bits (faster than LDB)
jumpe 1,eftgb5 ;Last word contains no strays
trne 1,4
skipa 1,[4] ; 7 means 4-1 unused bytes
trne 1,2 ;3 means 3-1 unused bytes
subi 1,1
movn 1,1
skipn tmode ;Binary?
jrst eftgb4 ; No, don't worry
push p,1
ldb 1,[point 6,eihdr+1,11] ;Check byte size
cain 1,8 ;Is this OK?
jrst eftgb3 ; Yes, byte mode is correct.
outstr [asciz/We recieved a packet which didn't end on a word boundary.
/]
skipe bitsh ;Any hope?
jrst[ outstr[asciz/Cannot proceed in this mode./]
jrst rcvbad ]
outstr [asciz/Continue writing as 8-bit binary instead? /]
call yesno
jrst rcvbad
movei 1,8
dpb 1,eihdr+1
dpb 1,fbuf+1
movei 1,4
imulm 1,eihdr+2
imulm 1,fbuf+2
eftgb3: pop p,1 ;Restore offset to byte count
eftgb4: addm 1,eihdr+2 ;update count to account for fill bytes
eftgb5: ildb 1,eihdr+1 ;Get character
aos (p) ;and take a skip return
popj p,
A=1
B=2
C=3
D=4
repeat 0,<
;returns +1 for ignore this pup
;returns +2 for retransmit something
;doesn't return in case of fatal error
;
BADTYP: LDB B,PUPLEN ;get length
SUBI B,=22 ;get data length.
MOVE C,PUPDAT ;data byte pointer
LDB A,PUPTYP ;get the pup type again
CAIN A,.PTERR ;error Pup?
JRST ERRPUP
CAIN A,.PTEAB ;Abort?
JRST ABTPUP
OUTSTR [ASCIZ/?A pup of type /]
LDB A,PUPTYP
CALL OCTOUT
OUTSTR [ASCIZ/ from /]
CALL PRTHST
OUTSTR [ASCIZ/ has been received, and will be discarded.
/]
RET
ABTPUP: SUBI B,2
PUSH P,B ;the string length after the error word
ILDB A,C ;get the error byte
ILDB B,C
LSH A,8
ADD A,B
POP P,B
CAIGE A,ABTDTN ;abort dispatch table length
XCT ABTDSP(A) ;Don't come back, except to die.
PUSH P,B ;the string length after the error word
OUTSTR [ASCIZ/Abort code /]
CALL OCTOUT
OUTCHR [" "]
POP P,B ;error string count
BADT1: JUMPLE B,BADT2
BADLP: ILDB A,C ;get a data byte
OUTCHR A
SOJG B,BADLP ;go until done.
BADT2: OUTSTR CRLF
OUTSTR [ASCIZ/Transmission terminated unsucessfully
/]
EXIT ;lose
;here for an ERROR PUP (Pup type = 4). Read error code (data word =10 of packet)
ERRPUP: LDB A,[POINT 16,13(PUP),15] ;Get the error code.
CAIE A,1 ;Skip if it's a checksum error
CAIN A,3 ;Skip unless resource limit at destination
JRST CPOPJ1 ;retransmit this pup...
OUTSTR [ASCIZ/Error pup, error code = /]
CALL OCTOUT
OUTSTR [ASCIZ/ /]
ADDI C,6 ;skip 6 words of binary
SUBI B,=24 ;account this in byte count
JRST BADT1 ;go die
ABTDSP: JFCL ;Abort code 0: unknown
JFCL ;1: External Sender abort. Unk.
OUTSTR [ASCIZ/File rejected. Do not send it again. /]
JRST RBUSY ;3: receiver busy abort. try later
OUTSTR [ASCIZ/Out of sequence: try the whole transmission again. /]
JFCL ;5: unknown
OUTSTR [ASCIZ/Not ready to receive. Try much later. /]
JRST MDELAY ;7: medium wait delay
JRST SUPXMT ;8: suspend transmission
ABTDTN==.-ABTDSP
RBUSY: OUTSTR [ASCIZ/Receiver is busy with another request. I'll wait.
/]
MOVEI A,12
SLEEP A,
JRST CPOPJ1 ;try again
MDELAY: OUTSTR [ASCIZ/Server has requested a delay. I'll wait...
/]
MOVEI A,50
SLEEP A,
JRST CPOPJ1
SUPXMT: OUTSTR [ASCIZ/Server requests a suspension. I'll dally...
/]
MOVEI A,24
SLEEP A,
JRST CPOPJ1
>;repeat 0
;REPWAT osend
;wait for an ack matching id in previd, sends pup again on failure
REPEAT 0,<
osend: OUT pupch,pupout
skipa
call error
outchr ["."]
repwat: movei 10,2 ;wait 1 second
call dally
jrst osend
IN pupch,pupmsg ;read our pup
SKIPA
call error
movei PUP,pupmsg ;current pup is one just read
ldb 1,puptyp
caie 1,.pteak ;is it acknowledgement
jrst repwt1 ;no. must be an error or abort
ldb 1,pupid ;get the ID
came 1,previd
jrst repwat ;wrong ack, ignore it and go wait some more
outchr ["!"]
ret
repwt1: call badtyp ;non-fatal err maybe...maybenot.
JRST REPWAT ;wait again
jrst osend ;try it again.
>;REPEAT 0
;send octin octin1 inerr octdon fread iascii finlp finlp1 goon finfin sndout noffin finset finlp finlp1 fineof eftppb sndbad eftpb2
;Send a file to an alto
send: outstr [asciz/end
/]
call inopn ;open file for input
outstr [asciz/Host number (octal):/]
call octin
send2: cain 1,15 ;see if cr
jrst hstdon
caie 1,"#"
jrst badhst
jumpe 2,send2 ;Ignore leading #
push p,2 ;Save network number
call octin
exch 1,(p) ;Save terminator, get network number
lsh 1,8 ;Shift network number into position
add 2,1 ;add host number
pop p,1 ;Get back terminator
cain 1,15
jrst hstdon
caie 1,"#" ;Socket, perhaps
jrst badhst
push p,2 ;Save net/host number
call octin
cain 1,15
jrst[ move 1,2
pop p,2
jrst gotskt]
pop p,2
badhst: outstr [asciz/That's not a number, try again:/]
CLRBFI ;flush garbage
jrst send
octin: setz 2, ;prepare to accumulate digits
octin1: inchrw 1 ;char to 1
cail 1,"0" ;error if less than "0"
cail 1,"8" ;or if not less than "8"
popj p, ;not a digit
subi 1,"0"
lsh 2,3 ;shift over prev. digits
ior 2,1 ;add in new digit
jrst octin1
hstdon: movei 1,efsock ;well known socket number
gotskt: movem 2,host ;foreign host number
movem 1,fsock
REPEAT 0,<
movei pup,pupout ;use pup output block
dpb 2,pupdhn ;put in block
dpb 1,pupds2 ;low order socket number
setz 1,
dpb 1,pupds1 ;high order socket number = 0
timer 1, ;get real time in 1/60th sec
pjob 2, ;our job number
lsh 1,7 ;move over time
ior 1,2 ;OR in job number
movem 1,lsock ;our socket number
;This gives us a unique socket number to use for sending.
dpb 1,pupssk
LOOKUP pupch,pupbl ;set up link our socket to 0#host#20
call error
movei 1,.pteda ;EFTPData type pup
dpb 1,puptyp
setz 1,
dpb 1,puptrn ;zero transport ctl
setom 1,previd ;previous id = -1 to say none
fread: movei PUP,pupout ;use output pup
MOVE 2,PUPDAT ;Data byte pointer for ASCII mode
movei 5,=512 ;max number of 8-bit bytes
skipn tmode
jrst iascii ;jump if ascii mode
movei 5,=128 ;max number of 32-bit bytes
move 2,pupbdt ;binary (32-bit) data pointer
iascii: setz 3, ;count bytes written
setzm idone ;say not done yet
setzm rchar ;clear prev. char
finlp: call filin ;get a char
jrst [aos idone ;say we are done
jrst finfin]
move 4,rchar ;get prev. char. to ac4
movem 1,rchar ;save away this char.
cain 1,12 ;skip if not LF
skipn lfmode ;lfmode not 0 - special LF processing
jrst finlp1 ;not LF or no special: go on.
; Come here outputting a LF, if following a CR we will ignore it.
cain 4,15 ;skip unless CR
jrst finlp ;this LF follows a CR and we are converting CRLF to LF, so ignore it.
finlp1: idpb 1,2 ;put char just read in the pup
aoj 3, ;keep byte count
goon: came 3,5 ;skip if no space left in pup
jrst finlp
finfin: jumpe 3,noffin ;no data bytes in last pup
skipe tmode ;if in IMAGE mode
imuli 3,4 ;change word count to byte count
addi 3,=22 ;account overhead
dpb 3,puplen ;put in length
aos 1,previd ;increment ID for pup
dpb 1,pupid ;put it in pup
sndout: call putchk ;put in checksum
;Now pup is all ready to send
call osend ;send out pup and wait for reply
skipn idone ;skip if this pup was last
jrst fread ;no, so go send more data
noffin: CLOSE diskch,
movei PUP,pupout
movei 1,.pteen
dpb 1,puptyp
movei 1,=22
dpb 1,puplen ;EFTPEnd, no data
aos 1,previd
dpb 1,pupid ;next ID number
call putchk
call osend ;send out end and wait for reply
movei PUP,pupout
aos 1,previd
dpb 1,pupid ;2nd end has next id number, all else the same
OUT pupch,pupout ;send it out
jrst done ;all finished
call error
>;REPEAT 0
mtape pupch,esndmb
hrrz 1,esndmb+1 ;Get status
jumpe 1,finbeg
outstr [asciz/Failed to open connection; perhaps already in use? /]
jrst done1
finbeg: movei 1,8
skipn tmode
jrst finset
movei 1,=32
finset: dpb 1,[point 6,eohdr+1,11]
setzm rchar ;clear prev. char
finlp: call filin ;get a char
jrst fineof ;say we are done
move 4,rchar ;get prev. char. to ac4
movem 1,rchar ;save away this char.
cain 1,12 ;skip if not LF
skipn lfmode ;lfmode not 0 - special LF processing
jrst finlp1 ;not LF or no special: go on.
; Come here outputting a LF, if following a CR we will ignore it.
cain 4,15 ;skip unless CR
jrst finlp ;this LF follows a CR and we are converting CRLF to LF, so ignore it.
finlp1: call eftppb
jrst finlp
fineof: close pupch, ;no data bytes in last pup
CLOSE diskch,
jrst done
eftppb: sosle eohdr+2
jrst eftpb2
out pupch,
jrst eftpb2
outstr [asciz/Ethernet output error. Status = /]
getsts pupch,1
call octout
sndbad: releas pupch,3 ;blast the connection
jrst done1
eftpb2: idpb 1,eohdr+1
popj p,
end start