1!& ! This program demonstrates the use of Ethernet devices & ! for user programming purposes. It attempts to send a & ! file across the Ethernet to a receiving program. This & ! program has both the send and receive portions in it. & !& ! DISCLAIMER: & ! This program has a number of inherent flaws, and is NOT & ! meant to be used for purposes other than demonstration. & !& ! Note that the program always acknowledges everything it & ! gets sent. It also does not ensure the proper order of & ! messages, check for redunant or complete data, or even & ! verify that the sender remains the same throughout the & ! transfer. & !& ! There are other problems that I don't even want to get & ! into, so I won't. & !& ! Futhermore, no verify process (ECC, CRC, or other) is & ! implented to ensure data integrity. The resultant file & ! may be corrupt. & !& ! DECnet guarantees a lot of these things for you, so you & ! should use DECnet for transferring files instead. & ! (That's a plug. Where's Steve Allen when you need him?)& !& ! Final note: While you are not reading the comments, & ! they're in French. (Really!) & 900 DIM FQB%(30%) & 999 ON ERROR GOTO 19000 !Standard error trap & \ S$ = SYS(CHR$(6%)+CHR$(-7%)) !Trap CTRL/C's & 1000 CH.NI% = 1% !Channel to Ethernet & \ CH.NL% = 12% !Channel for NL: & \ CH.DK% = 2% !Channel for disk file & !& \ MSG.SEQ% = 0% !Sequence counter & \ MSG.ACK% = 1% & \ MSG.HELLO% = 2% & \ MSG.DATA% = 3% & \ MSG.EOF% = 4% & !& \ HEX.SET$ = "0123456789ABCDEF" & !& \ PRINT & !& \ OPEN "NL:" AS FILE CH.NL%, RECORDSIZE 30% & !& \ FIELD #CH.NL%, 30% AS FQB$ & !& \ FIELD #CH.NL%, 1% AS FQJOB$, !Map for FSS & 1% AS FQSIZM$, & 2% AS D$, & 2% AS FQPPN$, & 4% AS FQNAM1$, & 2% AS FQEXT$, & 2% AS FQSIZ$, & 2% AS FQCLUS$, & 2% AS FQMODE$, & 2% AS FQNENT$, & 1% AS FQPFLG$, & 1% AS FQPROT$, & 2% AS FQDEV$, & 1% AS FQDEVN$, & 1% AS FQDEVF$, & 2% AS FLAG1$, & 2% AS FLAG2$ & 1100 INPUT "Ethernet device ";DEV$ & \ PRINT & !& ! Parse the input and check for illegal things & !& \ LSET FQB$ = SYS(CHR$(6%)+CHR$(-10%)+DEV$) & \ CHANGE FQB$ TO FQB% & \ FLAG1% = SWAP%(CVT$%(FLAG1$)) & \ FLAG2% = SWAP%(CVT$%(FLAG2$)) & \ GOTO 1100 IF FLAG2% AND (1%+8%+128%+1024%+(1%+32767%)) & \ GOTO 1100 IF FLAG1% AND (1%+2%+4%+8%) & !& ! Reconstruct the file spec using the default if needed & !& \ DEV$ = FQDEV$ & \ DEV$ = "XE" UNLESS FLAG2% AND 8192% & \ DEV$ = DEV$ + NUM1$(FQB%(25%)) IF FQB%(26%) & \ DEV$ = DEV$ + ":/CL:10/PO:1632/MO:0" & 1200 OPEN DEV$ AS FILE CH.NI%, RECORDSIZE 534% & !& ! Its open. Make sure its an Ethernet device & !& \ IF (STATUS AND 255%) <> 40% & THEN PRINT "That device is not an Ethernet device." & \ PRINT & \ CLOSE CH.NI% & \ GOTO 1100 & 1210 FIELD #CH.NI%, 6% AS ADR.DEST$, & 6% AS ADR.SRC$, & 2% AS PROTOCOL$, & 2% AS MSG.LEN$, & 2% AS MSG.TYPE$, & 2% AS MSG.SEQ$, & 2% AS MSG.BNUM$, & 512% AS MSG.DATA$ & \ FIELD #CH.NI%, 20% AS D$, & 514% AS MSG.SAVE$ & 1300 INPUT "[S]end or [R]eceive a file, or xit";CMD$ & \ PRINT & \ CMD$ = LEFT(CVT$$(CMD$,2%+4%+32%),1%) & \ CMD$ = "E" UNLESS LEN(CMD$) & \ I% = INSTR(1%,"ESR",CMD$) & \ ON I% GOSUB 32000,2000,6000 IF I% & \ GOTO 1300 & 2000 CLOSE CH.DK% & \ PRINT "File to send"; & \ INPUT LINE FIL$ & \ PRINT & \ FIL$ = FNFSS$(FIL$) & \ GOTO 2000 UNLESS LEN(FIL$) & 2010 OPEN FIL$ FOR INPUT AS FILE CH.DK%, & RECORDSIZE 512%, MODE 4096% & !& \ FIELD #CH.DK%, 512% AS DK.DATA$ & 2100 INPUT "Address to send file to";TEMP$ & \ PRINT & \ TEMP$ = CVT$$(TEMP$,2%+4%+32%) & \ DEST$ = FNCVT.A2H$(TEMP$) & \ GOTO 2100 UNLESS LEN(DEST$) & 2200 IF FNACK%(MSG.HELLO%,"") ! Initialize connection & THEN PRINT "Connection not established" & \ PRINT & \ GOTO 2100 & 2300 FOR DK.REC% = 1% WHILE 1% & !& \ GET #CH.DK%, RECORD DK.REC% & 2310 IF FNACK%(MSG.DATA%,CVT%$(DK.REC%)+DK.DATA$) & THEN PRINT "Lost connection, retrying..." & \ GOTO 2310 & 2320 NEXT DK.REC% & 2400 IF FNACK%(MSG.EOF%,"") & THEN PRINT "Waiting for EOF acknowledgement..." & \ GOTO 2400 & 2410 CLOSE CH.DK% & \ PRINT "File transferred" & \ PRINT & 5999 RETURN & 6000 PRINT "File to receive"; & \ INPUT LINE FIL$ & \ PRINT & \ FIL$ = FNFSS$(FIL$) & \ GOTO 6000 UNLESS LEN(FIL$) & !& \ FIL$ = FIL$ + "/CL:" + NUM1$(SWAP%(CVT$%(FQCLUS$))) & IF FLAG1% AND 1% & \ M% = (SWAP%(CVT$%(FQMODE$)) AND 32767%) OR 32% & \ FIL$ = FIL$ + "/MO:" + NUM1$(M%) & \ S = FQB%(2%) * 65536. + FQB%(14%) * 256. + FQB%(13%) & \ FIL$ = FIL$ + "/SI:" + NUM1$(S) IF FLAG1% AND 4% & \ FIL$ = FIL$ + "/PO:" + NUM1$(SWAP%(CVT$%(FQNENT$))) & IF FLAG1% AND 8% & 6100 OPEN FIL$ FOR OUTPUT AS FILE CH.DK%, RECORDSIZE 512% & !& \ FIELD #CH.DK%, 512% AS DK.DATA$ & \ DK.EOF% = 0% & 6200 ON FNMSG% GOSUB 9999,9999,6300,6400 & \ RETURN IF DK.EOF% & \ GOTO 6200 & 6300 DK.REC% = CVT$%(MSG.BNUM$) & \ LSET DK.DATA$ = MSG.DATA$ & \ PUT #CH.DK%, BLOCK DK.REC% & \ PRINT "Data block #";NUM1$(DK.REC%);" received" IF DBG% & \ RETURN & 6400 DK.EOF% = -1% & \ CLOSE CH.DK% & \ PRINT "File transferred" & \ PRINT & \ RETURN & 9999 RETURN & 10000 DEF FNCVT.A2H$(ADR$) & !& ! This function converts a printable Ethernet address & ! into the internal format needed for command purposes. & !& ! Ethernet addresses are of the type 'A-B-C-D-E-F', where & ! each letter represents a pair of hexadecimal digits. & !& \ FNCVT.A2H$ = "" & \ GOTO 10010 UNLESS LEN(ADR$) = 17% & \ T.$ = "" & \ FOR I.% = 1% TO 6% & \ J.% = I.% * 3% - 2% & \ T1.$ = MID(ADR$, J.%, 1%) & \ T2.$ = MID(ADR$, J.%+1%, 1%) & \ I1.% = INSTR(1%, HEX.SET$, T1.$) - 1% & \ I2.% = INSTR(1%, HEX.SET$, T2.$) - 1% & \ GOTO 10010 & IF (I1.% < 0%) OR (I2.% < 0%) & \ T.$ = T.$ + CHR$(16% * I1.% + I2.%) & \ GOTO 10010 & IF MID(ADR$, J.%+2%, 1%) <> "-" & UNLESS I.% = 6% & \ NEXT I.% & \ FNCVT.A2H$ = T.$ & 10010 FNEND & 10100 DEF FNCVT.H2A$(ADDR$) & !& ! This function convert the internal Ethernet address & ! format to the printable format. & !& \ T.$ = "" & \ FOR I.% = 1% TO 6% & \ T.$ = T.$ + FNHEX$(ASCII(MID(ADDR$, I.%, 1%))) & \ T.$ = T.$ + "-" UNLESS I.% = 6% & \ NEXT I.% & \ FNCVT.H2A$ = T.$ & \ FNEND & 10200 DEF FNHEX$(J%) & !& ! Compute the hexadecimal equivalent of a byte. & !& \ I1.% = (J% / 16%) + 1% & \ I2.% = (J% AND 15%) + 1% & \ FNHEX$ = MID(HEX.SET$, I1.%, 1%) & + MID(HEX.SET$, I2.%, 1%) & \ FNEND & 10300 DEF FNACK%(MSG%,MSG$) & !& ! Send a message and wait for an acknowledgment & !& \ FNACK% = -1% & \ MSG.SEQ% = MSG.SEQ% + 1% & \ I1.% = 0% & 10310 I2.% = 0% & \ LSET ADR.DEST$ = DEST$ & \ LSET MSG.SEQ$ = CVT%$(MSG.SEQ%) & \ LSET MSG.TYPE$ = CVT%$(MSG%) & \ LSET MSG.SAVE$ = MSG$ & \ PUT #CH.NI%, COUNT 20% + LEN(MSG$) & 10320 GET #CH.NI% & \ GOTO 10320 IF RECOUNT <> 20% & OR CVT$%(MSG.TYPE$) <> MSG.ACK% & OR CVT$%(MSG.SEQ$) <> MSG.SEQ% & OR ADR.SRC$ <> DEST$ & \ FNACK% = 0% & \ GOTO 10350 & 10330 I2.% = I2.% + 1% & \ IF I2.% < 5% & THEN SLEEP 32767%+1%+2% & \ GOTO 10320 & 10340 I1.% = I1.% + 1% & \ IF I1.% < 5% & THEN SLEEP 32767%+1%+2% & \ GOTO 10310 & 10350 FNEND & 10400 DEF FNMSG% & !& 10410 I1.% = 0% & 10420 GET #CH.NI% & \ I2.% = CVT$%(MSG.TYPE$) & \ GOTO 10420 IF (I2.% < MSG.ACK%) & OR (I2.% > MSG.EOF%) & \ T.$ = MSG.SAVE$ + "" & \ LSET MSG.TYPE$ = CVT%$(MSG.ACK%) & \ LSET ADR.DEST$ = ADR.SRC$ & \ PUT #CH.NI%, COUNT 20% & \ FNMSG% = I2.% & \ LSET MSG.SAVE$ = T.$ & \ GOTO 10450 & 10430 I1.% = I1.% + 1% & \ IF I1.% < 10% & THEN SLEEP 32767%+1%+2% & \ GOTO 10420 & 10440 PRINT "No message received in timeout period" & \ PRINT & \ GOTO 10410 & 10450 FNEND & 10500 DEF FNFSS$(FIL$) & !& \ FNFSS$ = "" & 10510 FIL$ = CVT$$(FIL$, 2%+4%) & \ LSET FQB$ = SYS(CHR$(6%)+CHR$(-10%)+FIL$) & \ CHANGE FQB$ TO FQB% & \ FLAG1% = SWAP%(CVT$%(FLAG1$)) & \ FLAG2% = SWAP%(CVT$%(FLAG2$)) & \ GOTO 10520 IF FLAG1% < 0% & \ GOTO 10520 UNLESS FLAG1% AND 256% & !& \ FIL$ = FQDEV$ & \ FIL$ = "SY" UNLESS FLAG2% AND 8192% & \ FIL$ = FIL$ + NUM1$(FQB%(25%)) IF FQB%(26%) & \ FIL$ = FIL$ + ":[" & \ FIL$ = FIL$ + NUM1$(FQB%(6%)) & IF FQB%(6%) OR (FLAG1% AND 1024%) & \ FIL$ = FIL$ + "," & \ FIL$ = FIL$ + NUM1$(FQB%(5%)) & IF FQB%(5%) OR (FLAG1% AND 1024%) & \ FIL$ = FIL$ + "]" + RAD$(SWAP%(CVT$%(FQNAM1$))) & + RAD$(SWAP%(CVT$%(RIGHT(FQNAM1$,3%)))) + "." & \ FIL$ = FIL$ + RAD$(SWAP%(CVT$%(FQEXT$))) & IF FLAG1% AND 512% & \ FNFSS$ = FIL$ & 15020 FNEND & 19000 IF ERR = 28% !CTRL/C trap & THEN S$ = SYS(CHR$(6%) + CHR$(-7%)) & \ PRINT & \ RESUME 32000 & 19100 IF ERR = 11% & THEN RESUME 2400 IF ERL = 2300% !Real EOF & \ PRINT !CTRL/Z 'trap' & \ RESUME 32000 IF (ERL = 1100%) OR (ERL = 1300%) & \ RESUME 5999 IF ERL = 2000% & \ RESUME 9999 IF ERL = 6000% & \ RESUME 2000 IF ERL = 2100% & 19200 IF ERR = 5% !Failed receives & THEN RESUME 10330 IF ERL = 10320 & \ RESUME 10430 IF ERL = 10420 & 19600 RESUME 1100 IF ERL = 1100% !Trap any FSS errors & \ GOTO 19700 IF ERL <> 1200% !Errors on OPEN & \ IF ERR = 3% & THEN PRINT "Protocol in use on device" & ELSE IF ERR = 14% & THEN PRINT "Device disabled" & ELSE IF ERR = 32% & THEN PRINT "Not enough system buffers" & ELSE IF ERR = 6% & THEN PRINT "Not a valid device" & ELSE 19999 & 19610 PRINT & \ RESUME 1100 & 19700 RESUME 2000 IF ERL = 2000% !Error on FSS & \ IF (ERL = 2010%) OR (ERL = 6100%) !Error on OPEN & THEN RESUME 2000% IF ERR = 5% !Just not found & \ PRINT "Error #";NUM1$(ERR);" on OPEN" & \ PRINT & \ RESUME 9999 & 19999 ON ERROR GOTO 0 !Catch anything else & 32000 CLOSE CH.NL%, CH.NI%, -CH.DK% !All done & 32767 END !Good-bye cruel world.