! ! transport service interface transmitter ! copies file 1 to the TS interface ! !prompts the user for the destination names ! !The program uses a state table to control the actions, the state !table is included in symbolic and data form below ! copyright University of Kent at Canterbury 1982 ! stack=300, streams=1 ! %CONTROL 1 %BEGIN %RECORDFORMAT MEF(%RECORD (MEF) %NAME LINK, %BYTEINTEGER LEN, TYPE, %C ( (%BYTEINTEGERARRAY PARAMS(0:251)) %ORC (%INTEGER ADDRESS, PORT, %C ( (%INTEGER RCOMM,TCOMM,%BYTEINTEGERARRAY DATA(0:243)) %ORC (%INTEGER COMMAND, REPLY PORT, FUNCTION, BSP PARAM LEN, %C %INTEGERARRAY BSP PARAM(1:2), %C %BYTEINTEGERARRAY TSPARAMS(0:235) ) )))) %RECORDFORMAT PEF(%BYTEINTEGER SER, REPLY, %C ( (%INTEGER A,B,C ) %ORC (%BYTEINTEGER A1,A2,B1,B2,C1,C2) %ORC (%BYTEINTEGER FN, S1, %C ( (%RECORD (MEF) %NAME MES, %BYTEINTEGER GATEPORT,TASKPORT) %ORC (%STRING (3) FACILITY) ) ) ) ) %INCLUDE "TST_STTEXT" %INCLUDE "TST_STAB"; !state table declarations %INCLUDE "CUR051.TSBSP_TSCODES"; !codes for TS interface operations %INCLUDE "CUR051.TSBSP_DEIMOS" ! service numbers and DEIMOS specific values %CONSTRECORD (*) %NAME NIL==0 %CONSTINTEGER BSP SER=16 %CONSTINTEGER RING SER=10 %CONSTINTEGER BUFFER MANAGER=17 %CONSTINTEGER NAME SERVER=15 %CONSTINTEGER T3 SER=21 %CONSTBYTEINTEGERNAME INT==8_160060 %CONSTBYTEINTEGERNAME OWN ID==8_160030 %CONSTBYTEINTEGERNAME CHANGE OUT ZERO==8_160310 !function values to buffer manager %CONSTINTEGER REQUEST BUFFER=0 %CONSTINTEGER RELEASE BUFFER=1 %CONSTINTEGER LONG BLOCK=0 %OWNINTEGER GPORT=0 %OWNRECORD (MEF) %NAME BUF %OWNRECORD (PEF) P %OWNSTRING (16) S; !for destination name %OWNINTEGER STATE %OWNINTEGER NEOT, HOLDC, FIRST CALL; !for char input routine %CONSTINTEGER EOL=10 %CONSTINTEGER MAX DATA LEN=234; !max data per packet %CONSTINTEGER EOT=4 %INTEGERFN GETCHAR; !return -1 at true end of file (handles multiple EOTs) !------------------ %ONEVENT 9 %START HOLDC=-1; NEOT=-1; %RESULT=-1 %FINISH %IF NEOT>0 %THEN NEOT=NEOT-1 %ANDRESULT=EOT %IF NEOT=0 %THEN NEOT=-1 %ANDRESULT=HOLDC %IF FIRST CALL=0 %THEN READSYMBOL(HOLDC) FIRSTCALL=0 %IF HOLDC=EOT %START %WHILE HOLDC=EOT %CYCLE READSYMBOL(HOLDC) NEOT=NEOT+1 %REPEAT %IF HOLDC>=0 %THEN %RESULT=EOT %ELSE NEOT=-1 %AND %RESULT=-1 %FINISH %RESULT=HOLDC %END %ROUTINE GET BUFFER !------------------ P_FN=REQUEST BUFFER; P_C1=LONG BLOCK P_SER=BUFFER MANAGER; P_REPLY=OWN ID PONOFF(P) BUF==P_MES %END %ROUTINE FREE BUFFER(%RECORD (MEF) %NAME MES) !-------------------------------------------- P_FN=RELEASE BUFFER; P_SER=BUFFER MANAGER P_REPLY=OWN ID; P_MES==MES PON(P) %END %ROUTINE SEND TO TS(%INTEGER FN) !------------------------- P_SER=BSP SER; P_REPLY=OWN ID P_FN=FN; P_GATE PORT=GPORT; P_TASK PORT=1 PON(P) %END %ROUTINE SEND(%INTEGER FN) !------------------------- P_MES==NIL SEND TO TS(FN) %END %ROUTINE SEND BUFFER(%INTEGER FN) !-------------------------------- P_MES==BUF; BUF==NIL SEND TO TS(FN) %END %ROUTINE PP(%STRING (64) S) !------------------------------- ! Append TS parameter S to BUF, BUF_LEN gives current length %INTEGER L L=BUF_LEN STRING(ADDR(BUF_PARAMS(L)))=S BUF_LEN=L+LENGTH(S)+1 %END %STRING (*) %MAP SS(%INTEGER I) !------------------------------ ! Return I'th parameter from BUF %INTEGER P P=0 %WHILE I>1 %CYCLE; P=P+BUF_PARAMS(P)+1; I=I-1; %REPEAT %RESULT==STRING(ADDR(BUF_PARAMS(P))) %END %ROUTINE STATE TABLE(%INTEGER EVENT) !----------------------------------- %INTEGER I,J,K,L,C %SWITCH SW(NULL ACTION:ERROR ACTION) I=(EVENT-1)*MAX STATE + STATE STATE=STATES(I); !new state !PRINTSTRING("TST:") !WRITE(EVENT,3) !WRITE(STATE, 3) ! WRITE(STATES(I),3) ! WRITE(ACTS(I),3) !NEWLINE -> SW(ACTS(I)) SW(PROCESS ACC): GPORT=P_TASK PORT; !reversed port numbers %RETURN SW(OPEN FAILED): PRINTSTRING("Connect failed") WRITE(P_S1, 3) PRINTSTRING(SS(2)) NEWLINE %RETURN SW(SEND DISC): P_S1=42; !abandon code SEND(DISCONNECT) %RETURN SW(REPLY DISC OK): %IF P_S1#0 %START PRINTSTRING("Network abort") NEWLINE %FINISH P_S1=1 SEND(DISCONNECT) %RETURN SW(REPLY DISC AB): PRINTSTRING("Network abort") NEWLINE P_S1=1; !code for ack SEND(DISCONNECT) %RETURN SW(SEND DATA): K=P_S1; !K=no of enable outputs %FOR J=1,1,K %CYCLE C=GET CHAR GET BUFFER L=0 %WHILE C>=0 %CYCLE BUF_DATA(L)=C L=L+1 %IF L>=MAX DATA LEN %THEN %EXIT C=GET CHAR %REPEAT BUF_LEN=L %IF C<0 %START; !end of data- send a push P_S1=1 SEND BUFFER(PUT OUTPUT) STATE=WT FIN %RETURN %FINISH P_S1=0 SEND BUFFER(PUT OUTPUT) %REPEAT %RETURN SW(STOP): %STOP SW(NULL ACTION): %RETURN SW(*): PRINTSTRING("TST: state table error ") WRITE(EVENT, 3) WRITE(STATE, 3) NEWLINE %RETURN %END %ROUTINE FROM BELOW !------------------ %CONSTBYTEINTEGERARRAY EV TAB(CONNECT:DATAGRAM REPLY)=ERROR EVENT, ACC,DISC,EN OUT,ERROR EVENT,ERROR EVENT,RST,ERROR EVENT,ERROR EVENT %IF P_FN#ENABLE OUTPUT %THEN BUF==P_MES STATE TABLE(EV TAB(P_FN)) %END %ROUTINE FROM CLOCK !------------------ %IF INT='A' %START INT=0 STATE TABLE(INT A) %FINISH %ELSE STATE TABLE(TICK) ALARM(100) %END %ROUTINE READSTR(%STRING (*) %NAME S) !------------------------------------ %INTEGER C,L L=0 READSYMBOL(C) %WHILE C#EOL %CYCLE %IF L<16 %START L=L+1 CHARNO(S,L)=C %FINISH READSYMBOL(C) %REPEAT LENGTH(S)=L %END !----------------------------------------------------------------- ! ! Main Program MAP VIRT(BUFFER MANAGER, 5, 4) MAP VIRT(BUFFER MANAGER, 6, 5) !want to read the first character from the file to ensure it's there SELECTINPUT(1) READSYMBOL(HOLDC) !Now set global variables so that the getchar routine works ok NEOT=-1 FIRST CALL=1 SELECTINPUT(0) %CYCLE PROMPT("Destination:") READSTR( S ) %REPEATUNTIL LENGTH(S)#0 GETBUFFER; !For the connect BUF_LEN=0 PP(S."/TSR"); !called address PP("TST"); !calling address PP(" "); !null quality of service PP("Simple file transfer"); !explanatory text SEND BUFFER(CONNECT) STATE=WT ACCEPT SELECTINPUT(1) ALARM(50) %CYCLE %UNLESS BUF==NIL %THEN FREE BUFFER(BUF) %AND BUF==NIL P_SER=0; POFF(P) %IF P_REPLY=0 %THEN FROM CLOCK %AND %CONTINUE %IF P_REPLY=BSP SER %THEN FROM BELOW %AND %CONTINUE PRINTSTRING("Illegal message to TST") WRITE(P_REPLY,3); WRITE(P_A, 6); WRITE(P_B, 6); WRITE(P_C, 6) NEWLINE %REPEAT %ENDOFPROGRAM