MODULE KMT_PH_MODULE; @ VME KERMIT PROTOCOL HANDLER @ @ GLOBAL VARIABLES @ @ PKT_TYPE : packet type of current packet @ @ KMT_PH_INPUT_PACKET_DATA : pointer to packet data buffer @ @ (translated to EBCDIC and decoded) @ @ PKT_SEQ : current packet number (expected) @ @ PKT_NO : current packet number (received) @ @ RETRY_COUNT : current retry count @ @ Mode declarations: @ MODE KMT_BUFFER IS (96)BYTE; MODE KMT_STRING IS REF()BYTE; MODE KMT_WORD IS REF()BYTE; MODE KMT_MTUP_VALUES IS ANY (LONG WORD LW_VALUE, LONG INT LI_VALUE, REF WORD RW_VALUE, REF INT RI_VALUE, REF LONG WORD RLW_VALUE, REF LONG INT RLI_VALUE, REF()BYTE RVB_VALUE, REF()REF()BYTE RVRVB_VALUE); MODE KMT_PP_PACKET_STATISTICS_S IS STRUCT (INT INPUT_TOTAL, OUTPUT_TOTAL); MODE KMT_TRACE_FLAGS_S IS WORD STRUCT (BIT PH_TRACING, PP_TRACING, FH_TRACING, DH_TRACING, 28-BIT SPARE); @ External procedures @ EXT PROC (INT,RESPONSE) KMT_MESSAGE; EXT PROC (RESPONSE) KMT_UI; EXT PROC (REF()BYTE,INT,RESPONSE) KMT_FH_OPEN_FILE, PROC (RESPONSE) KMT_FH_CLOSE_FILE, PROC (RESPONSE) KMT_FH_SAVE_FILE, PROC (REF()BYTE,REF INT,BOOL,RESPONSE) KMT_FH_GIVE_NAME; EXT PROC () KMT_PP_TRANSLATE_TO_EBCDIC, PROC (REF()BYTE,RESPONSE) KMT_PP_BUILD_STRING_PACKET_DATA, PROC (RESPONSE) KMT_PP_PROCESS_PARAM_PACKET_DATA, PROC () KMT_PP_BUILD_PARAM_PACKET_DATA, PROC (RESPONSE) KMT_PP_BUILD_FILE_RECORD, PROC (RESPONSE) KMT_PP_BUILD_FILE_PACKET_DATA, PROC (REF INT,REF INT,RESPONSE) KMT_PP_GET_PACKET, PROC (INT,INT,BOOL,RESPONSE) KMT_PP_SEND_PACKET; @ Any error returned by KMT_PP_SEND_PACKET is fatal and Kermit will exit; @ @ warnings will have been logged already and are ignored @ EXT PROC (REF KMT_STRING) KMT_WORD KMT_SP_GET_WORD, PROC (REF KMT_WORD,INT) KMT_SP_STANDARDISE_FILENAME, PROC (INT,REF()KMT_MTUP_VALUES) KMT_SP_LOG_TRACE_MESSAGE; EXT REF INT PKT_SEQ,PKT_NO,MAXTRY,RETRY_COUNT,RETRY_TOTAL,TIMEOUT_TOTAL, RC_IGNORED; EXT REF KMT_STRING KMT_PH_INPUT_PACKET_DATA; EXT REF KMT_BUFFER KMT_VME_FILE_BUF,KMT_REM_FILE_BUF; EXT REF KMT_WORD KMT_VME_FILE,KMT_REM_FILE; EXT INT ENTRY,BREAK_PKT,DATA_PKT,FILE_HDR_PKT,NAK_PKT,SEND_INIT_PKT,ACK_PKT, EOF_PKT; EXT INT VME_TERM,VME_STD,KMT_STD; @ forms of name standardisation @ EXT INT REC_SERVER_IDLE,REC_INIT,REC_FILE,REC_DATA,SEND_INIT,SEND_FILE, SEND_DATA,SEND_EOF,SEND_BREAK,COMPLETE,ABORT; EXT INT EXIT,LOGOUT,FATAL_ERROR; @ exit states @ EXT INT EOF; @ eof on file data @ EXT INT SERVER_MODE; EXT REF INT KMT_CURRENT_MODE; EXT BOOL READ_INT,NO_READ_INT; @ set/don't set read interest after send @ EXT REF INT FILE_OPTION; EXT REF BOOL DELAY_TIMER; EXT REF BOOL SAVE_INCOMPLETE_FILE; EXT REF INT EXIT_STATE; EXT REF()KMT_MTUP_VALUES KMT_MTM_AREA; EXT REF KMT_PP_PACKET_STATISTICS_S KMT_PP_PACKET_STATISTICS; EXT REF KMT_TRACE_FLAGS_S KMT_TRACE_FLAGS; STATIC REF KMT_STRING PKT_DATA IS KMT_PH_INPUT_PACKET_DATA; GLOBAL STATIC () PROC KMT_PH IS (REF INT STATE,INT EVENT,RESPONSE RESULT): BEGIN @ procedures for state entry @ SIM PROC KMT_PH_REC_SERVER_IDLE IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Server idle, waiting for message @ BEGIN RETRY_COUNT := 0; @ try for ever in Rec_Server_Idle state @ RETRY_TOTAL := TIMEOUT_TOTAL := 0; KMT_PP_PACKET_STATISTICS := (0,0); PKT_SEQ := 0; @ initialise packet sequence @ RESULT := 0 END ; @ KMT_PH_REC_SERVER_IDLE @ SIM PROC KMT_PH_REC_INIT IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Entry point for non-server RECEIVE command @ BEGIN PKT_SEQ := 0; @ initialise packet sequence @ RESULT := 0 END ; @ KMT_PH_REC_INIT @ SIM PROC KMT_PH_REC_FILE IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Look for a file header or EOT message @ RESULT := 0 @ nothing to do on entry to Rec_File state @ ; @ KMT_PH_REC_FILE @ SIM PROC KMT_PH_REC_DATA IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Receive data up to end of file @ RESULT := 0 @ nothing to do on entry to Rec_Data state @ ; @ KMT_PH_REC_DATA @ SIM PROC KMT_PH_SEND_INIT IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Server Send Init, also entry for non-server SEND command @ BEGIN PKT_SEQ := 0; @ initialise packet sequence @ IF KMT_CURRENT_MODE NE SERVER_MODE AND RETRY_COUNT LE 1 THEN @ wait for user to set up remote KERMIT @ INT KMT_EH_SOFTWARE_ERROR IS 80101; INT X_TYPE,X_NO; DELAY_TIMER := TRUE; @ set delay timer @ KMT_PP_GET_PACKET(X_TYPE,X_NO,RESULT);@ attempt to read packet @ @ if we get a packet then they're ready to receive @ @ if the timer expires then we send regardless @ DELAY_TIMER := FALSE; UNLESS RESULT = KMT_EH_SOFTWARE_ERROR DO RESULT := 0 FI ELSE RESULT := 0 FI; IF RESULT = 0 THEN KMT_PP_BUILD_PARAM_PACKET_DATA(); @ send S(0) with parameters @ KMT_PP_SEND_PACKET(SEND_INIT_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI FI END ; @ KMT_PH_SEND_INIT @ SIM PROC KMT_PH_SEND_FILE IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Send file or text header (we don't send text packets!) @ BEGIN @ send F(n) - packet made by KMT_PH_READY_FILE @ KMT_PP_SEND_PACKET(FILE_HDR_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI END ; @ KMT_PH_SEND_FILE @ SIM PROC KMT_PH_SEND_DATA IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Send contents of file or textual information @ @ (we don't send text packets!) @ BEGIN @ send D(n) with current buffer (pkt made by KMT_PH_READY_DATA) @ KMT_PP_SEND_PACKET(DATA_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI END ; @ KMT_PH_SEND_DATA @ SIM PROC KMT_PH_SEND_EOF IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Send end of file indicator (we don't do interrupts) @ BEGIN KMT_VME_FILE := NIL; @ file has been closed @ KMT_REM_FILE := NIL; @ send Z(n) - packet made by KMT_PH_READY_DATA @ KMT_PP_SEND_PACKET(EOF_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI END ; @ KMT_PH_SEND_EOF @ SIM PROC KMT_PH_SEND_BREAK IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ End of Transmission @ BEGIN @ send B(n) - packet made by KMT_PH_SENT_FILE @ KMT_PP_SEND_PACKET(BREAK_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI END ; @ KMT_PH_SEND_BREAK @ @ procedures for expected packets @ SIM PROC KMT_PH_INIT_PARAMS IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ A Send_Init or Init packet has arrived. If the packet sequence is @ @ correct, process their parameters and ack with our parameters. @ @ If it's a repeat of their last packet, ack it again with our @ @ parameters. Otherwise, report error and in non-Server modes, abort @ IF (STATE = REC_SERVER_IDLE OR STATE = REC_INIT) AND PKT_NO = 0 THEN @ got right packet, reset retry count @ RETRY_COUNT := 0; KMT_PP_PROCESS_PARAM_PACKET_DATA(RESULT); IF RESULT = 0 THEN KMT_PP_BUILD_PARAM_PACKET_DATA(); KMT_PP_SEND_PACKET(ACK_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI; IF RESULT = 0 AND EVENT = SEND_INIT_PKT THEN @ increment packet sequence @ PKT_SEQ := PKT_SEQ+1 MOD 64; STATE := REC_FILE FI ELSE @ their params unacceptable @ RESULT := 89070 FI ELSF STATE = REC_FILE AND PKT_NO+1 MOD 64 = PKT_SEQ @ i.e. P = N-1 @ THEN @ we've picked up their Send_init again, so send ack @ KMT_PP_BUILD_PARAM_PACKET_DATA(); KMT_PP_SEND_PACKET(ACK_PKT,PKT_NO,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI ELSE @ wrong packet sequence, error (abort if non-server) @ RESULT := 89000 FI ; @ KMT_PH_INIT_PARAMS @ SIM PROC KMT_PH_GEN_CMD IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Generic command received - some are implemented and will be @ @ executed and acknowledged - an error packet is sent for the rest @ IF PKT_NO = 0 THEN BYTE GEN_CMD; KMT_PP_TRANSLATE_TO_EBCDIC(); GEN_CMD := PKT_DATA(0); RETRY_COUNT := 0; @ got right packet, reset retry count @ @ check if Generic Command implemented @ IF GEN_CMD = "F" OR GEN_CMD = "L" THEN @ GF (Finish command): exit Server mode and terminate @ @ GL (Logout command): exit Server mode and log out @ EXIT_STATE := IF GEN_CMD = "F" THEN EXIT ELSE LOGOUT FI; STATE := COMPLETE; @ Generic Command successful, ack it @ KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_SEND_PACKET(ACK_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI ELSE @ this Generic Command not implemented (or doesn't exist) @ RESULT := 89011 FI ELSE @ wrong packet number, wait for their next try @ RESULT := 89000 FI ; @ KMT_PH_GEN_CMD @ SIM PROC KMT_PH_KMT_CMD IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Packet contains Kermit command, pass it to user interface (KMT_UI) @ @ for processing @ IF PKT_NO = 0 THEN RETRY_COUNT := 0; @ got right packet, reset retry count @ @ pass command (in packet) to KMT_UI @ KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_TRANSLATE_TO_EBCDIC(); KMT_UI(RESULT); IF RESULT = 0 THEN @ command has been executed successfully so ack it @ @ if there is a reply, KMT_UI has put it into packet @ KMT_PP_SEND_PACKET(ACK_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI FI ELSE @ wrong packet number, wait for their next try @ RESULT := 89000 FI ; @ KMT_PH_KMT_CMD @ SIM PROC KMT_PH_GOT_FILENAME IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Packet contains name of file to be sent @ IF PKT_NO = 0 THEN @ got right packet, reset retry count @ RETRY_COUNT := 0; KMT_PP_TRANSLATE_TO_EBCDIC(); KMT_VME_FILE := KMT_SP_GET_WORD(PKT_DATA); @ obtain filename @ IF NOT (KMT_VME_FILE REF NIL) @ must be present @ THEN KMT_VME_FILE := KMT_VME_FILE_BUF(SIZE LENGTH KMT_VME_FILE) := KMT_VME_FILE; STATE := SEND_INIT; RESULT := 0 ELSE @ no filename, error and abort @ RESULT := 89030 FI ELSE @ wrong packet number, wait for their next try @ RESULT := 89000 FI ; @ KMT_PH_GOT_FILENAME @ SIM PROC KMT_PH_BREAK IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ End of Transmission received @ IF PKT_NO = PKT_SEQ THEN @ correct sequence, ack it and complete @ KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_SEND_PACKET(ACK_PKT,PKT_SEQ,NO_READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI; STATE := COMPLETE ELSE @ wrong packet sequence, error abort @ RESULT := 89000 FI ; @ KMT_PH_BREAK @ SIM PROC KMT_PH_FILE_HDR IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Packet contains name of file to be received @ IF PKT_NO = PKT_SEQ THEN @ obtain filename (may have been specified in Receive command)@ KMT_PP_TRANSLATE_TO_EBCDIC(); IF KMT_VME_FILE REF NIL THEN @ not already set @ KMT_VME_FILE := KMT_SP_GET_WORD(PKT_DATA); IF KMT_VME_FILE REF NIL THEN RESULT := 80931 ELSE KMT_VME_FILE := KMT_VME_FILE_BUF(SIZE LENGTH KMT_VME_FILE) := KMT_VME_FILE; RESULT := 0 FI ELSE @ already set but verify packet contains filename @ KMT_REM_FILE := KMT_SP_GET_WORD(PKT_DATA); RESULT := IF KMT_REM_FILE REF NIL THEN 80931 ELSE 0 FI FI; IF RESULT = 0 THEN @ open file @ KMT_REM_FILE := @ save copy of VME filename @ KMT_REM_FILE_BUF(SIZE LENGTH KMT_VME_FILE) := KMT_VME_FILE; @ assume filename is name.type, remove type @ KMT_SP_STANDARDISE_FILENAME(KMT_VME_FILE,VME_STD); KMT_FH_OPEN_FILE(KMT_VME_FILE,FILE_OPTION,RESULT); IF RESULT <= 0 THEN @ file open, log full name @ INT NAME_LENGTH; RESULT := 0; KMT_FH_GIVE_NAME(KMT_VME_FILE_BUF,NAME_LENGTH,TRUE,RESULT); IF RESULT <= 0 THEN @ set VME filename to full name @ RESULT := 0; KMT_VME_FILE := KMT_VME_FILE_BUF(SIZE NAME_LENGTH); KMT_MTM_AREA(3) := KMT_REM_FILE AS KMT_MTUP_VALUES.RVB_VALUE; KMT_MTM_AREA(4) := KMT_VME_FILE AS KMT_MTUP_VALUES.RVB_VALUE; KMT_MESSAGE(-87002,RC_IGNORED); @ log filename @ @ ack file header including VME filename @ KMT_PP_BUILD_STRING_PACKET_DATA(KMT_VME_FILE, RC_IGNORED); KMT_PP_SEND_PACKET(ACK_PKT,PKT_SEQ,READ_INT,RESULT); IF RESULT <= 0 THEN PKT_SEQ := PKT_SEQ+1 MOD 64; RETRY_TOTAL := RETRY_TOTAL + (RETRY_COUNT - 1); RETRY_COUNT := 0; STATE := REC_DATA; RESULT := 0 ELSE RESULT := -89061 FI FI ELSE @ unable to open file, reset result and abort @ RESULT := 89040 FI FI ELSE @ wrong packet number, abort @ RESULT := 89000 FI ; @ KMT_PH_FILE_HDR @ SIM PROC KMT_PH_GOT_DATA IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Received data packet @ IF PKT_NO = PKT_SEQ THEN @ write data to file @ KMT_PP_BUILD_FILE_RECORD(RESULT); IF RESULT <= 0 THEN @ ack data packet @ RESULT := 0; KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_SEND_PACKET(ACK_PKT,PKT_SEQ,READ_INT,RESULT); IF RESULT <= 0 THEN PKT_SEQ := PKT_SEQ+1 MOD 64; RETRY_TOTAL := RETRY_TOTAL + (RETRY_COUNT - 1); RETRY_COUNT := 0; RESULT := 0 ELSE RESULT := -89061 FI ELSE @ error writing data to file, abort @ RESULT := 89046 FI ELSF PKT_NO+1 MOD 64 = PKT_SEQ @ i.e. P = N-1 @ THEN @ we've picked up their last data packet again, so ack it @ KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_SEND_PACKET(ACK_PKT,PKT_NO,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI ELSE @ wrong packet number, error abort @ RESULT := 89000 FI ; @ KMT_PH_GOT_DATA @ SIM PROC KMT_PH_GOT_FILE IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ End of file packet received @ IF PKT_NO = PKT_SEQ THEN KMT_PP_TRANSLATE_TO_EBCDIC(); KMT_FH_CLOSE_FILE(RESULT); @ close file we've just rec'd @ RESULT := IF RESULT <= 0 THEN 0 @ ignore -ve warning code @ ELSE 89042 @ error closing file, abort @ FI; IF (RESULT = 0 OR SAVE_INCOMPLETE_FILE) AND (LENGTH PKT_DATA = 0 OR PKT_DATA(0) NE "D") THEN @ no discard signal in packet so save file @ INT RC; KMT_FH_SAVE_FILE(RC); IF RC > 0 THEN RESULT := 89044 @ error saving file, abort @ FI FI; IF RESULT = 0 THEN KMT_VME_FILE := NIL; KMT_REM_FILE := NIL; @ no problems closing file, so ack eof @ KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_SEND_PACKET(ACK_PKT,PKT_SEQ,READ_INT,RESULT); IF RESULT <= 0 THEN PKT_SEQ := PKT_SEQ+1 MOD 64; RETRY_TOTAL := RETRY_TOTAL + (RETRY_COUNT - 1); RETRY_COUNT := 0; STATE := REC_FILE; RESULT := 0 ELSE RESULT := -89061 FI FI ELSE @ wrong packet number, abort @ RESULT := 89000 FI ; @ KMT_PH_GOT_FILE @ SIM PROC KMT_PH_READY_FILE IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Send Init has been acknowledged, open file for transfer @ IF PKT_NO = 0 THEN KMT_PP_PROCESS_PARAM_PACKET_DATA(RESULT); IF RESULT = 0 THEN @ open file in READ mode @ @ assume filename is name.type, remove type @ KMT_SP_STANDARDISE_FILENAME(KMT_VME_FILE,VME_STD); KMT_FH_OPEN_FILE(KMT_VME_FILE,0,RESULT); IF RESULT <= 0 THEN @ set up filename for file hdr packet @ INT NAME_LENGTH; RESULT := 0; KMT_FH_GIVE_NAME(KMT_VME_FILE_BUF,NAME_LENGTH,TRUE,RESULT); IF RESULT <= 0 THEN KMT_VME_FILE := KMT_VME_FILE_BUF(SIZE NAME_LENGTH); IF KMT_REM_FILE REF NIL THEN @ set remote filename to VME terminal name @ KMT_REM_FILE := KMT_REM_FILE_BUF(SIZE NAME_LENGTH) := KMT_VME_FILE; KMT_SP_STANDARDISE_FILENAME(KMT_REM_FILE,VME_TERM) ELSE @ set remote filename to Kermit Normal-Form @ KMT_SP_STANDARDISE_FILENAME(KMT_REM_FILE,KMT_STD) FI; @ log filenames @ KMT_MTM_AREA(3) := KMT_VME_FILE AS KMT_MTUP_VALUES.RVB_VALUE; KMT_MTM_AREA(4) := KMT_REM_FILE AS KMT_MTUP_VALUES.RVB_VALUE; KMT_MESSAGE(-87003,RC_IGNORED); @ put filename in file header packet @ KMT_PP_BUILD_STRING_PACKET_DATA(KMT_REM_FILE,RC_IGNORED); PKT_SEQ := PKT_SEQ+1 MOD 64; RETRY_TOTAL := RETRY_TOTAL + (RETRY_COUNT - 1); RETRY_COUNT := 0; STATE := SEND_FILE; RESULT := 0 FI ELSE @ unable to open file, reset result and abort @ RESULT := 89041 FI ELSE @ their params unacceptable @ RESULT := 89070 FI FI ; @ KMT_PH_READY_FILE @ SIM PROC KMT_PH_READY_DATA IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Get data ready for transfer @ IF (EVENT = ACK_PKT AND PKT_NO = PKT_SEQ) OR (EVENT = NAK_PKT AND PKT_NO = PKT_SEQ+1 MOD 64) THEN PKT_SEQ := PKT_SEQ+1 MOD 64; RETRY_TOTAL := RETRY_TOTAL + (RETRY_COUNT - 1); RETRY_COUNT := 0; KMT_PP_TRANSLATE_TO_EBCDIC(); IF (LENGTH PKT_DATA = 1 AND STATE = SEND_DATA) AND (PKT_DATA(0) = "X" OR PKT_DATA(0) = "Z") THEN @ their ack packet requested interrupt transfer @ KMT_FH_CLOSE_FILE(RESULT); @ closing file shouldn't fail @ RESULT := IF RESULT <= 0 THEN 0 ELSE 89043 FI; KMT_MESSAGE(-87000,RC_IGNORED); @ log cancellation of xfer @ @ set up eof packet data @ KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); STATE := SEND_EOF ELSE @ check for ack of file header, it may have filename @ IF STATE = SEND_FILE @ used by remote Kermit, if so log it @ THEN STATE := SEND_DATA; KMT_MTM_AREA(3) := KMT_VME_FILE AS KMT_MTUP_VALUES.RVB_VALUE; IF LENGTH PKT_DATA > 0 THEN KMT_MTM_AREA(4) := PKT_DATA AS KMT_MTUP_VALUES.RVB_VALUE ELSE KMT_MTM_AREA(4) := KMT_REM_FILE AS KMT_MTUP_VALUES.RVB_VALUE FI; KMT_MESSAGE(-87001,RC_IGNORED) FI; @ set up next data packet @ KMT_PP_BUILD_FILE_PACKET_DATA(RESULT); IF RESULT = EOF THEN @ all data sent, close file and send eof next @ KMT_FH_CLOSE_FILE(RESULT); @ shouldn't fail @ RESULT := IF RESULT <= 0 THEN 0 ELSE 89043 FI; STATE := SEND_EOF @ all data sent @ ELSE @ error reading from file? @ RESULT := IF RESULT <= 0 THEN 0 ELSE 89047 FI FI FI ELSE RESULT := 0 FI ; @ KMT_PH_MAKE_DATA @ SIM PROC KMT_PH_SENT_FILE IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ File sent, check ack @ BEGIN IF (EVENT = ACK_PKT AND PKT_NO = PKT_SEQ) OR (EVENT = NAK_PKT AND PKT_NO = PKT_SEQ+1 MOD 64) THEN @ any more files? no - we only allow 1 per send so: @ PKT_SEQ := PKT_SEQ+1 MOD 64; RETRY_TOTAL := RETRY_TOTAL + (RETRY_COUNT - 1); RETRY_COUNT := 0; KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); @ set up break @ STATE := SEND_BREAK @ packet data @ @ (ditto if previous pkt_data(0) was "Z") @ FI; RESULT := 0 END ; @ KMT_PH_SENT_FILE @ SIM PROC KMT_PH_SEND_DONE IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Break sent, check ack @ BEGIN IF EVENT = ACK_PKT THEN IF PKT_NO = PKT_SEQ THEN STATE := COMPLETE FI ELSF PKT_NO = PKT_SEQ+1 MOD 64 OR PKT_NO = 0 THEN @ they've sent nak(n+1) or nak(0) @ STATE := COMPLETE FI; RESULT := 0 END ; @ KMT_PH_SEND_DONE @ @ procedures for unexpected packets @ SIM PROC KMT_PH_REPORT_ERR IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ unexpected pkt type, send error pkt and remain in same state @ RESULT := 89000 ; @ KMT_PH_REPORT_ERR @ SIM PROC KMT_PH_GOT_ERROR IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ they've reported an error to us, log error message and abort @ BEGIN @ decode packet data and set up message text area for logging @ KMT_PP_TRANSLATE_TO_EBCDIC(); KMT_MTM_AREA(3) := PKT_DATA AS KMT_MTUP_VALUES.RVB_VALUE; RESULT := -87010 END ; @ KMT_PH_GOT_ERROR @ SIM PROC KMT_PH_SEND_NAK IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ send nak packet @ BEGIN KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_SEND_PACKET(NAK_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI END ; @ KMT_PH_SEND_NAK @ SIM PROC KMT_PH_NAK_ABORT IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Send NAK and abort @ BEGIN KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_SEND_PACKET(NAK_PKT,PKT_SEQ,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI; STATE := ABORT END ; @ KMT_PH_NAK_ABORT @ SIM PROC KMT_PH_ACK_LAST IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ if current packet is repeat of last packet then send ack @ IF PKT_NO+1 MOD 64 = PKT_SEQ @ i.e. P = N-1 @ THEN KMT_PP_BUILD_STRING_PACKET_DATA(NIL,RC_IGNORED); KMT_PP_SEND_PACKET(ACK_PKT,PKT_NO,READ_INT,RESULT); RESULT := IF RESULT <= 0 THEN 0 ELSE -89061 FI ELSE @ wrong packet sequence, error abort @ RESULT := 89000 FI ; @ KMT_PH_ACK_LAST @ SIM PROC KMT_PH_ERR_ABORT IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Send error packet and abort @ RESULT := 89001 ; @ KMT_PH_ERR_ABORT @ SIM PROC KMT_PH_SEND_IDLE IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ the wrong type of packet (or a bad packet) has arrived while @ @ sending a file - in this case it doesn't matter @ RESULT := 0 ; @ KMT_PH_SEND_IDLE @ SIM PROC KMT_PH_SET_ABORT IS GROUP KMT_PH_GRP (RESPONSE RESULT): @ Set ABORT state @ BEGIN STATE := ABORT; RESULT := 0 END ; @ KMT_PH_SET_ABORT @ @ protocol handler state event table @ (9)(15)SIM PROC GROUP KMT_PH_GRP(RESPONSE) KMT_PH_ACTION IS ((KMT_PH_REC_SERVER_IDLE , KMT_PH_REPORT_ERR , KMT_PH_REPORT_ERR , KMT_PH_GOT_ERROR , KMT_PH_REPORT_ERR , KMT_PH_GEN_CMD , KMT_PH_INIT_PARAMS , KMT_PH_KMT_CMD , KMT_PH_REPORT_ERR , KMT_PH_GOT_FILENAME , KMT_PH_INIT_PARAMS , KMT_PH_REPORT_ERR , KMT_PH_REPORT_ERR , KMT_PH_SEND_NAK , KMT_PH_REPORT_ERR), (KMT_PH_REC_INIT , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_GOT_ERROR , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_INIT_PARAMS , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_SEND_NAK , KMT_PH_NAK_ABORT ), (KMT_PH_REC_FILE , KMT_PH_BREAK , KMT_PH_NAK_ABORT , KMT_PH_GOT_ERROR , KMT_PH_FILE_HDR , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_NAK_ABORT , KMT_PH_INIT_PARAMS , KMT_PH_NAK_ABORT , KMT_PH_ACK_LAST , KMT_PH_SEND_NAK , KMT_PH_NAK_ABORT ), (KMT_PH_REC_DATA , KMT_PH_ERR_ABORT , KMT_PH_GOT_DATA , KMT_PH_GOT_ERROR , KMT_PH_ACK_LAST , KMT_PH_ERR_ABORT , KMT_PH_ERR_ABORT , KMT_PH_ERR_ABORT , KMT_PH_ERR_ABORT , KMT_PH_ERR_ABORT , KMT_PH_ERR_ABORT , KMT_PH_ERR_ABORT , KMT_PH_GOT_FILE , KMT_PH_SEND_NAK , KMT_PH_ERR_ABORT ), (KMT_PH_SEND_INIT , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE , KMT_PH_GOT_ERROR , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE , KMT_PH_READY_FILE , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE , KMT_PH_SEND_IDLE ), (KMT_PH_SEND_FILE , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_GOT_ERROR , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_READY_DATA , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_READY_DATA , KMT_PH_SET_ABORT , KMT_PH_SEND_IDLE , KMT_PH_SET_ABORT ), (KMT_PH_SEND_DATA , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_GOT_ERROR , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_READY_DATA , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_READY_DATA , KMT_PH_SET_ABORT , KMT_PH_SEND_IDLE , KMT_PH_SET_ABORT ), (KMT_PH_SEND_EOF , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_GOT_ERROR , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SENT_FILE , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SENT_FILE , KMT_PH_SET_ABORT , KMT_PH_SEND_IDLE , KMT_PH_SET_ABORT ), (KMT_PH_SEND_BREAK , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_GOT_ERROR , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SEND_DONE , KMT_PH_SET_ABORT , KMT_PH_SET_ABORT , KMT_PH_SEND_DONE , KMT_PH_SET_ABORT , KMT_PH_SEND_IDLE , KMT_PH_SET_ABORT )); @ PROTOCOL HANDLER @ IF KMT_TRACE_FLAGS.PH_TRACING THEN () KMT_MTUP_VALUES PARAMS := (STATE AS KMT_MTUP_VALUES.RI_VALUE, (L'EVENT) AS KMT_MTUP_VALUES.LI_VALUE); KMT_SP_LOG_TRACE_MESSAGE(300,PARAMS) FI; IF EVENT = ENTRY THEN @ increment retry count and test against maximum @ RETRY_COUNT := RETRY_COUNT+1; IF RETRY_COUNT > MAXTRY THEN RETRY_TOTAL := RETRY_TOTAL + (RETRY_COUNT - 1); RESULT := 89050 ELSE KMT_PH_ACTION(STATE,EVENT)(RESULT) FI ELSE KMT_PH_ACTION(STATE,EVENT)(RESULT) FI; IF RESULT NE 0 THEN IF RESULT = -89061 THEN @ unable to send packet - fatal error @ STATE := ABORT; EXIT_STATE := FATAL_ERROR ELSF (RESULT NE 89000) OR (STATE NE REC_SERVER_IDLE) THEN @ abort unless wrong seq no in Rec_Server_Idle state @ STATE := ABORT FI FI END ; @ KMT_PH @ ENDMODULE @ KMT_PH_MODULE @