------------------------------------------------------------------------------ -- PURPOSE: Package Body for Kermit Protocol. -- -- -- NOTES: This program was produced by the Westinghouse Electric Corporation, -- as part of the STARS Foundation Ada Software procurement effort. -- -- (c) Copyright 1987 Westinghouse Electric Corporation -- (c) Copyright 1988 Westinghouse Electric Corporation - Updates -- All Rights Reserved. -- -- This material may be reproduced by or for the U.S. Government -- pursuant to the copyright licence under DOD FAR Suppl. Clause -- 52.227-7013 August 1984. -- Author : Elizabeth T Hobbs -------------------------------------------------------------------------------- separate (NETWORK_PROTOCOLS.KERMIT_PROTOCOL) package body RECEIVE_UTILITIES is procedure RECEIVE_INITIALIZATION(CURRENT_SEQUENCE : in out INTEGER) is --receive the other Kermit's S packet PACKET_TO_SEND : PACKET_TYPE; RESPONSE_PACKET : PACKET_TYPE; DATA_STRING : BYTE_STRING(1..NUM_FEATURES) := (1..NUM_FEATURES => SP); -- won't ever need more than this for response to s_packet NUMBER_FEATURES : INTEGER; COMPATIBLE : BOOLEAN := TRUE; begin --wait timeout RECEIVE_RESPONSE(RESPONSE_PACKET); if (RESPONSE_PACKET.KTYPE = Q_PACKET) or (RESPONSE_PACKET.KTYPE = T_PACKET) then -- start NAKs -- (can't resend previous packet, since there is no previous to resend) CREATE_PACKET(PACKET_TO_SEND, N_PACKET, DATA_STRING, 0, CURRENT_SEQUENCE); SEND_PACKET(PACKET_TO_SEND, CURRENT_SEQUENCE, RESPONSE_PACKET); end if; -- if we get here we have a packet of some kind (a timeout in SEND_PACKET -- causes TIMEOUT_ERROR to be raised) if RESPONSE_PACKET.KTYPE = E_PACKET then PRINT_ERROR_MSG(RESPONSE_PACKET); raise ERROR_RECEIVED; elsif RESPONSE_PACKET.KTYPE = S_PACKET and then RESPONSE_PACKET.SEQ = BYTE'VAL(CURRENT_SEQUENCE) then CHECK_SI_RESPONSE(RESPONSE_PACKET, COMPATIBLE); if not COMPATIBLE then raise INCOMPATIBLE_KERMITS; end if; CONSTRUCT_SI_RETURN(PACKET_TO_SEND); elsif RESPONSE_PACKET.KTYPE = B_PACKET then CREATE_PACKET(PACKET_TO_SEND, Y_PACKET, DATA_STRING, 0, CURRENT_SEQUENCE); PUT_PACKET(PACKET_TO_SEND); raise END_OF_TRANSMISSION; else -- we got a packet we weren't expecting raise UNEXPECTED_PACKET; end if; -- send ACK since all is ok--use earlier CONSTRUCT_SI_RETURN packet -- note: put_packet doesn't wait for response. We will pick up response -- (which is the senders next packet) in receive_file_header PUT_PACKET(PACKET_TO_SEND); CURRENT_SEQUENCE := (CURRENT_SEQUENCE + 1) mod 64; exception when others => raise FILE_TRANSFER_ERROR; end RECEIVE_INITIALIZATION; procedure RECEIVE_FILE_HEADER(CURRENT_SEQUENCE : in out INTEGER) is -- receive the f packet. -- current design has us get the filename from the -- name_of_file_being_transferred function and NOT the other Kermit PACKET_TO_SEND : PACKET_TYPE; RESPONSE_PACKET : PACKET_TYPE; PREVIOUS_SEQUENCE : INTEGER; DATA_STRING : BYTE_STRING(1..NUM_FEATURES) := (1..NUM_FEATURES => SP); -- won't ever need more than this for response to s_packet begin if CURRENT_SEQUENCE = 0 then PREVIOUS_SEQUENCE := 63; else PREVIOUS_SEQUENCE := CURRENT_SEQUENCE - 1; end if; --wait timeout RECEIVE_RESPONSE(RESPONSE_PACKET); if (RESPONSE_PACKET.KTYPE = Q_PACKET) or (RESPONSE_PACKET.KTYPE = T_PACKET) or (RESPONSE_PACKET.SEQ = BYTE'VAL(PREVIOUS_SEQUENCE)) then -- send previous ACK since problem encountered. -- we know previous was the response to the s_packet CONSTRUCT_SI_RETURN(PACKET_TO_SEND); SEND_PACKET(PACKET_TO_SEND, CURRENT_SEQUENCE, RESPONSE_PACKET); end if; -- if we get here we have a packet of some kind (a timeout in SEND_PACKET -- causes TIMEOUT_ERROR to be raised) if RESPONSE_PACKET.KTYPE = E_PACKET then PRINT_ERROR_MSG(RESPONSE_PACKET); raise ERROR_RECEIVED; elsif RESPONSE_PACKET.KTYPE = F_PACKET and then RESPONSE_PACKET.SEQ = BYTE'VAL(CURRENT_SEQUENCE) then -- normally we'd get the file name, but not in this case null; elsif RESPONSE_PACKET.KTYPE = B_PACKET then CREATE_PACKET(PACKET_TO_SEND, Y_PACKET, DATA_STRING, 0, CURRENT_SEQUENCE); PUT_PACKET(PACKET_TO_SEND); raise END_OF_TRANSMISSION; else -- we got a packet we we're expecting raise UNEXPECTED_PACKET; end if; -- send ACK since all is ok -- note: put_packet doesn't wait for response. We will pick up response -- (which is the senders next packet) in receive_data CREATE_PACKET(PACKET_TO_SEND, Y_PACKET, DATA_STRING, 0, CURRENT_SEQUENCE); PUT_PACKET(PACKET_TO_SEND); CURRENT_SEQUENCE := (CURRENT_SEQUENCE + 1) mod 64; exception when others => raise FILE_TRANSFER_ERROR; end RECEIVE_FILE_HEADER; procedure RECEIVE_DATA(CURRENT_SEQUENCE : in out INTEGER) is -- receive data packets, Z packet and B packet PACKET_TO_SEND : PACKET_TYPE; RESPONSE_PACKET : PACKET_TYPE; PREVIOUS_SEQUENCE : INTEGER; DATA_STRING : BYTE_STRING(1..1) := (1..1 => SP); begin loop -- get all of the data packets if CURRENT_SEQUENCE = 0 then PREVIOUS_SEQUENCE := 63; else PREVIOUS_SEQUENCE := CURRENT_SEQUENCE - 1; end if; --wait timeout RECEIVE_RESPONSE(RESPONSE_PACKET); if (RESPONSE_PACKET.KTYPE = Q_PACKET) or (RESPONSE_PACKET.KTYPE = T_PACKET) or (RESPONSE_PACKET.SEQ = BYTE'VAL(PREVIOUS_SEQUENCE)) then -- resend previous ACK since we encountered a problem -- besides we know what the previous packet was, so we can resend it CREATE_PACKET(PACKET_TO_SEND, Y_PACKET, DATA_STRING, 0, PREVIOUS_SEQUENCE); SEND_PACKET(PACKET_TO_SEND, CURRENT_SEQUENCE, RESPONSE_PACKET); end if; -- if we get here we have a packet of some kind (a timeout in SEND_PACKET -- causes TIMEOUT_ERROR to be raised) exit when RESPONSE_PACKET.KTYPE /= D_PACKET or RESPONSE_PACKET.SEQ /= BYTE'VAL(CURRENT_SEQUENCE); -- we have a data packet, so get the data, decode as necessary -- (and write to file ) EXTRACT_DATA(RESPONSE_PACKET); -- send ACK since all is ok -- note: put_packet doesn't wait for response. We will pick up response -- (which is the senders next packet) at top of loop CREATE_PACKET(PACKET_TO_SEND, Y_PACKET, DATA_STRING, 0, CURRENT_SEQUENCE); PUT_PACKET(PACKET_TO_SEND); CURRENT_SEQUENCE := (CURRENT_SEQUENCE + 1) mod 64; end loop; if RESPONSE_PACKET.KTYPE = E_PACKET then PRINT_ERROR_MSG(RESPONSE_PACKET); raise ERROR_RECEIVED; elsif RESPONSE_PACKET.KTYPE = Z_PACKET then -- normally you'd close the file at least or -- check to see if a D in the data field to discard the file -- but we're not doing any of this -- send ACK since all is ok -- note: put_packet doesn't wait for response. CREATE_PACKET(PACKET_TO_SEND, Y_PACKET, DATA_STRING, 0, CURRENT_SEQUENCE); SEND_PACKET(PACKET_TO_SEND, CURRENT_SEQUENCE, RESPONSE_PACKET); if RESPONSE_PACKET.KTYPE = E_PACKET then PRINT_ERROR_MSG(RESPONSE_PACKET); raise ERROR_RECEIVED; elsif RESPONSE_PACKET.KTYPE = B_PACKET then CURRENT_SEQUENCE := (CURRENT_SEQUENCE + 1) mod 64; CREATE_PACKET(PACKET_TO_SEND, Y_PACKET, DATA_STRING, 0, CURRENT_SEQUENCE); PUT_PACKET(PACKET_TO_SEND); -- for now, not waiting else -- we got a packet we weren't expecting raise UNEXPECTED_PACKET; end if; elsif RESPONSE_PACKET.KTYPE = B_PACKET then -- actually this is received out of order but stop anyway -- normally you'd make sure file is closed or whatever then end CREATE_PACKET(PACKET_TO_SEND, Y_PACKET, DATA_STRING, 0, CURRENT_SEQUENCE); PUT_PACKET(PACKET_TO_SEND); raise END_OF_TRANSMISSION; else -- we got a packet we weren't expecting raise UNEXPECTED_PACKET; end if; exception when others => raise FILE_TRANSFER_ERROR; end RECEIVE_DATA; end RECEIVE_UTILITIES;