diff -uNr a/smg_comms/manifest b/smg_comms/manifest --- a/smg_comms/manifest 8c55ef6a254359bf52a32b6d58f2a954184505ee4294b2cd1f7f6dd29911b873aba792eb6b88f9d62653ccb3d6d0fddf88146635729154848fac78be60418ba2 +++ b/smg_comms/manifest 268276f725ebbbf0eb0e11adcd2516571acb8958068b17040e1fb841a2edd44878d73c932982d70c4192b70c43f2cc9edf699380aa98fe15a968d81bfc911b14 @@ -8,3 +8,4 @@ 549511 smg_comms_skeys_smsgs diana_coman Defines data structures and message types as well as methods for reading/writing Serpent keysets to/from Serpent messages. 549785 smg_comms_io_rsa_tests_only diana_coman Small refactoring of tests extracting the reading of RSA key into package of its own so it can be used throughout tests and thus get rid of the too long lines in test_packing.adb. 550310 smg_comms_keymgm diana_coman Adds read/write for Keys Management messages (both Serpent and RSA). Refactors the read/write of Serpent Keys messages so that the same core is called by RSA/Serpent specific-methods, adding also read/write of keys from/to RSA messages. +551086 smg_comms_files diana_coman Adds read/write for File Transfer (4.3) and File Request (4.4). Refactors the rest to have read/write of 16 bits values in one single place (i.e. separate method called from everywhere else) because of how common it is + sensitive to endianness. diff -uNr a/smg_comms/src/data_structs.ads b/smg_comms/src/data_structs.ads --- a/smg_comms/src/data_structs.ads 30b66c681c3de5ad3731a40c47760d77d58707d32b66d8a8bb987898067a631bf761adee878b08f77fe8d83df097900f8990ca75e02cb0a2aeec1a58a5209c4d +++ b/smg_comms/src/data_structs.ads d472416a6fdbb7fd240664149e4a120f449ac15839d611e8a6987c145d3fe13c0a2227fe8c6ba3bc8f4ed2350973e7dfe6a074ab87cb02fbaf786396169fe5cf @@ -44,6 +44,30 @@ RZ at 12 range 0 .. 7; end record; + -- length of a text field (i.e. 16 bits, strictly > 0) + subtype Text_Len is Positive range 1..2**16-1; + + -- A set of file names glued into a single string + -- NB: there IS at least ONE filename and one character + -- Upper limit for Text_Len is due to protocol's spec of text basic type + type U16_Array is array (Text_Len range <> ) of Interfaces.Unsigned_16; + type Filenames( F_No: Text_Len := 1; Sz: Text_Len := 1 ) is + record + -- filenames glued together into 1 single string + S : String( 1 .. Sz ) := (others => '0'); + -- indices in S, at which each filename starts + Starts: U16_Array( 1 .. F_No ) := (others => 1); + end record; + + -- A chunk of a file (for file transfer) + type File_Chunk( Len : Text_Len := 1; + Count : Interfaces.Unsigned_16 := 1; + Name_Len: Text_len := 1) is + record + Filename: String(1..Name_Len); + Content : Raw_Types.Octets(1..Len); + end record; + ------------------------- -- A set of Serpent Keys -- parametrized record for a Serpent Keyset diff -uNr a/smg_comms/src/messages.adb b/smg_comms/src/messages.adb --- a/smg_comms/src/messages.adb 796122dcf307899111d2909509460b1de5215ef1dfadb88af3f3b2654754aa225acf79ff0b50be884f184966920bcd30e236585fa46846dc36b8f58f67c726d1 +++ b/smg_comms/src/messages.adb fd5121b49fcbcb70293b002298fc82272ef291e959fe63d17b5b22ba02b1abb2b1d12a6d0d9541caebe43a300fe08cc329fbcace81b8341a00296f66eb182a84 @@ -4,6 +4,7 @@ with Interfaces; use Interfaces; with Serpent; with System; use System; +with Ada.Assertions; use Ada.Assertions; package body Messages is @@ -55,6 +56,299 @@ end if; end Read_KMgm_SMsg; + ------ File Transfer ------ + procedure Write_File_Transfer( Chunk : in File_Chunk; + Msg : out Raw_Types.Serpent_Msg) is + Pos: Integer := Msg'First; + U16: Interfaces.Unsigned_16; + begin + -- write type ID + Msg(Pos) := File_Transfer_S_Type; + Pos := Pos + 1; + + -- write filename as text field (size+2, text) + -- check against overflows + if Chunk.Name_Len > Text_Len'Last - 2 or + Pos + Integer(Chunk.Name_Len) + 2 > Msg'Last then + raise Invalid_Msg; + end if; + + -- write total size: filename size + 2 + U16 := Interfaces.Unsigned_16( Chunk.Name_Len + 2 ); + Write_U16( Msg, Pos, U16 ); + + -- write filename + String_To_Octets( Chunk.Filename, + Msg(Pos..Pos+Integer(Chunk.Name_Len)-1) ); + Pos := Pos + Integer(Chunk.Name_Len); + + --write content + -- check against overflow, including the 2 octets for counter at the end + if Chunk.Len > Text_Len'Last - 2 or + Pos + Integer(Chunk.Len) + 4 > Msg'Last then + raise Invalid_Msg; + end if; + + -- write total size for this text field + U16 := Interfaces.Unsigned_16( Chunk.Len + 2 ); + Write_U16( Msg, Pos, U16 ); + + -- write actual content + Msg(Pos..Pos+Chunk.Content'Length-1) := Chunk.Content; + Pos := Pos + Chunk.Content'Length; + + -- write counter + Write_U16( Msg, Pos, Chunk.Count ); + + -- write padding if needed + if Pos <= Msg'Last then + RNG.Get_Octets( Msg(Pos..Msg'Last) ); + end if; + + end Write_File_Transfer; + + -- The opposite of Write_File_Transfer method above. + -- Counter will contain the message counter + -- Chunk will contain the chunk counter, filename and content + procedure Read_File_Transfer( Msg : in Raw_Types.Serpent_Msg; + Chunk : out File_Chunk) is + Pos: Integer := Msg'First; + U16: Interfaces.Unsigned_16; + S_Name, E_Name: Integer; --start/end for filename in Msg + S_Len: Text_Len; -- length of filename (needed as Text_Len anyway) + S_Content, E_Content: Integer; --start/end for content in Msg + Content_Len: text_Len; -- length of content (needed as Text_Len anyway) + begin + -- read and check type ID + if Msg(Pos) /= File_Transfer_S_Type then + raise Invalid_Msg; + end if; + Pos := Pos + 1; + + -- read filename size + Read_U16( Msg, Pos, U16 ); + + -- check for overflow and underflow; filename size >= 1 + if Pos + Integer(U16) - 2 > Msg'Last or + U16 < 3 then + raise Invalid_Msg; + end if; + U16 := U16 - 2; + S_Len := Text_Len(U16); + + -- set start + end for reading filename later, when ready + S_Name := Pos; + E_Name := Pos + Integer(U16)-1; + Pos := Pos + S_Len; + + -- read size of content + Read_U16( Msg, Pos, U16 ); + -- check for overflow and underflow; content >=1; counter =2 octets + if Pos + Integer(U16) - 1 > Msg'Last or + U16 < 3 then + raise Invalid_msg; + end if; + U16 := U16 - 2; + Content_Len := Text_Len(U16); + -- set start and end for reading content later, when ready + S_Content := Pos; + E_Content := Pos + Integer(U16) - 1; + Pos := Pos + Content_Len; + + -- read counter + Read_U16( Msg, Pos, U16 ); + -- check chunking validity i.e. if counter>0 then no padding + if U16 /= 0 and Pos /= Msg'Last then + raise Invalid_Msg; + end if; + + -- create File_Chunk structure and fill it with data from Msg + declare + FC : File_Chunk( Len => Content_Len, + Count => U16, + Name_Len => S_Len); + begin + -- read from Msg + FC.Content := Msg( S_Content..E_Content ); + Octets_To_String( Msg( S_Name..E_Name ), FC.Filename); + -- copy to output var + Chunk := FC; + end; + + end Read_File_Transfer; + + ---- File Requests ---- + procedure Write_File_Request( FR : in Filenames; + Counter : in Interfaces.Unsigned_16; + Msg : out Raw_Types.Serpent_Msg; + Written : out Natural) is + Pos : Integer := Msg'First; + Max_Pos: Integer := Msg'Last - 2; -- 2 octets at end for counter + Text_Sz: Integer; + Max_Sz : Integer; + begin + -- write ID for File Request type + Msg( Pos ) := File_Req_S_Type; + Pos := Pos + 1; + + -- write Text size: filenames + separators + -- consider fewer filenames if they don't ALL fit + -- 2 octets are taken by size itself + Max_Sz := Max_Pos - Pos - 1; + Text_Sz := FR.Sz + FR.F_No - 1; + if Text_Sz > Max_Sz then + -- walk the array of filenames backwards and stop when they fit + Written := FR.F_No - 1; + -- calculate actual size written based on start of first discarded + -- filename and (Written -1) octets for needed separators + Text_Sz := Integer(FR.Starts(Written+1)) - FR.Starts'First + + (Written - 1); + + -- loop until either fits or nothing left + while Written > 0 and Text_Sz > Max_Sz loop + Written := Written - 1; + Text_Sz := Integer(FR.Starts(Written+1))- FR.Starts'First + + (Written - 1); + end loop; + -- check that there is what to write, since nothing -> invalid message + if Written = 0 then + raise Invalid_Msg; + end if; + + else --from if Text_Sz > Max_Sz + -- ALL are written + Written := FR.F_No; + end if; + + -- write Text_Sz + 2 (i.e. TOTAL size) + if Text_Sz + 2 > Integer(Interfaces.Unsigned_16'Last) then + raise Invalid_Msg; + end if; + + Write_U16( Msg, Pos, Interfaces.Unsigned_16(Text_Sz+2) ); + + -- write filenames separated by Sep + for I in 1..Written loop + declare + Start_Pos : Positive; + End_Pos : Positive; + Len : Positive; + begin + -- current start pos in FR.S + Start_Pos := Positive( FR.Starts( FR.Starts'First + I - 1)); + + -- calculate end based on start of next name or last + if I < FR.F_No then + End_Pos := Positive( FR.Starts( FR.Starts'First + I)) - 1; + else + End_Pos := FR.S'Last; + end if; + + -- NB: this WILL fail if starting positions are not in order! + Len := End_Pos - Start_Pos + 1; + if Len <= 0 then + raise Invalid_Msg; + end if; + + --write the actual filename + String_To_Octets( FR.S( Start_Pos..End_Pos ), Msg(Pos..Pos+Len-1) ); + Pos := Pos + Len; + + --if it's not the last one, write a separator + if I < Written then + Msg(Pos) := Sep; + Pos := Pos + 1; + end if; + end; + end loop; + + -- write the message counter in little endian at all times + Write_U16( Msg, Pos, Counter ); + + -- write padding if needed + if Pos <= Msg'Last then + Rng.Get_Octets( Msg(Pos..Msg'Last) ); + end if; + end Write_File_Request; + + -- Reads a request for files; the opposite of Write_File_Request above + procedure Read_File_Request( Msg : in Raw_Types.Serpent_Msg; + Counter : out Interfaces.Unsigned_16; + FR : out Filenames) is + Pos : Integer := Msg'First; + Max_Pos : Integer := Msg'Last - 2; --at least 2 reserved for counter + Text_Sz : Integer; + Max_Sz : Integer := Max_Pos - Pos - 1; --text only i.e. w.o. size itself + F_No : Integer; + U16 : Interfaces.Unsigned_16; + begin + -- read type ID and check + if Msg(Pos) /= File_Req_S_Type then + raise Invalid_Msg; + end if; + Pos := Pos + 1; + + -- read total size of filenames+separators + Read_U16( Msg, Pos, U16 ); + Text_Sz := Integer(U16); + -- take away the 2 octets for size itself + Text_Sz := Text_Sz - 2; + + -- check that Text_Sz is not overflowing/underflowing + if Text_Sz < 1 or Text_Sz > Max_Sz then + raise Invalid_Msg; + end if; + + -- count first the separators to know how many filenames + -- NB: there is always at least 1 filename as Text_Sz > 0 + F_No := 1; + for I in Pos .. Pos + Text_Sz - 1 loop + if Msg(I) = Sep then + F_No := F_No + 1; + end if; + end loop; + + -- create the output structure and discard separators + -- text without separators should be Text_Sz - F_No + 1 + -- (because ONLY one separator between 2 filenames allowed) + -- if it's not that => Invalid_Msg + -- F_No and Text_Sz are not overflow (earlier check + calc) + declare + F : Filenames(Text_Len(F_No), Text_Len(Text_Sz-F_No+1)); + S_Pos : Positive; + Index : Positive; + begin + S_Pos := F.S'First; + Index := F.Starts'First; + F.Starts(Index) := Interfaces.Unsigned_16(S_Pos); + + for I in Pos .. Pos + Text_Sz - 1 loop + -- copy over to F.S anything that is not separator + if Msg(I) /= Sep then + F.S( S_Pos ) := Character'Val(Msg(I)); + S_Pos := S_Pos + 1; + else + -- if it's separator, check and if ok, add next as start + if I = Pos + Text_Sz or -- separator as last character is error + Msg(I+1) = Sep or -- 2 consecutive separators is error + Index >= F.Starts'Last then -- too many separators is error + raise Invalid_Msg; + else + Index := Index + 1; + F.Starts( Index ) := Interfaces.Unsigned_16(S_Pos); + end if; + end if; + end loop; + + -- copy the whole structure to output variable + FR := F; + end; + + -- read message counter now + Pos := Pos + Text_Sz; + Read_U16( Msg, Pos, Counter ); + + end Read_File_Request; ------------------ -- RSA Messages -- @@ -100,6 +394,27 @@ end if; end Read_KMgm_RMsg; + + ----------Utilities ---------- + -- String to Octets conversion + procedure String_To_Octets(Str: in String; O: out Raw_Types.Octets) is + begin + Assert( Str'Length = O'Length ); + for I in 1..Str'Length loop + O( O'First+I-1 ) := Character'Pos(Str(Str'First + I - 1 )); + end loop; + end String_To_Octets; + + -- Octets to string conversion + -- NB: Str'Length has to be EQUAL to Octets'Length! + procedure Octets_To_String(O: in Raw_Types.Octets; Str: out String) is + begin + Assert( O'Length = Str'Length ); + for I in 1..O'Length loop + Str( Str'First+I-1 ) := Character'Val(O(O'First + I - 1 )); + end loop; + end Octets_To_String; + ------------------ -- private part -- ------------------ @@ -124,7 +439,6 @@ Msg : out Raw_Types.Octets) is Pos : Integer := Msg'First; Check : CRC32.CRC32; - PadLen: Integer; K : Serpent.Key; begin -- write Type ID @@ -158,19 +472,11 @@ Pos := Pos + 1; -- write message counter - Msg(Pos..Pos+1) := Raw_Types.Cast(Counter); - Cast_LE(Msg(Pos..Pos+1)); - Pos := Pos + 2; + Write_U16( Msg, Pos, Counter ); -- write padding as needed; endianness is irrelevant here - PadLen := Msg'Last - Pos + 1; - if PadLen > 0 then - declare - Pad : Raw_Types.Octets(1..PadLen); - begin - RNG.Get_Octets( Pad ); - Msg(Pos..Pos+PadLen-1) := Pad; - end; + if Pos <= Msg'Last then + RNG.Get_Octets( Msg(Pos..Msg'Last) ); end if; end Write_SKeys; @@ -196,7 +502,6 @@ K : Serpent.Key; Check : CRC32.CRC32; O4 : Raw_Types.Octets_4; - O2 : Raw_Types.Octets_2; begin Pos := Pos + 1; --read keys and check crc for each @@ -220,9 +525,7 @@ KS.Flag := Msg(Pos); Pos := Pos + 1; -- read and set message counter - O2 := Msg(Pos..Pos+1); - Cast_LE(O2); - Counter := Raw_Types.Cast(O2); + Read_U16( Msg, Pos, Counter ); -- rest of message is padding so it's ignored -- copy keyset to output variable Keyset := KS; @@ -266,12 +569,12 @@ end if; -- write the message count - Msg(Pos..Pos+1) := Raw_Types.Cast( Counter ); - Cast_LE( Msg(Pos..Pos+1) ); - Pos := Pos + 2; + Write_U16( Msg, Pos, Counter ); -- pad with random octets until the end of Msg - RNG.Get_Octets( Msg(Pos..Msg'Last) ); + if Pos <= Msg'Last then + RNG.Get_Octets( Msg(Pos..Msg'Last) ); + end if; end Write_KMgm; @@ -295,7 +598,6 @@ declare N_Burnt : Counter_8bits := Counter_8bits(Msg(Burnt_Pos)); Mgm : Keys_Mgm(N_Burnt); - O2 : Raw_Types.Octets_2; begin -- read count of server keys requested Mgm.N_Server := Msg(Pos); @@ -316,14 +618,33 @@ end if; -- read and set message counter - O2 := Msg(Pos..Pos+1); - Cast_LE(O2); - Counter := Raw_Types.Cast(O2); + Read_U16( Msg, Pos, Counter ); -- rest of message is padding so it's ignored -- copy the keys mgm structure to output param KMgm := Mgm; end; end Read_KMgm; + -- Write a 16 bits value to Octets at Pos; Pos increases by 2. + procedure Write_U16( Msg: in out Raw_Types.Octets; + Pos: in out Natural; + U16: in Interfaces.Unsigned_16) is + begin + Msg(Pos..Pos+1) := Raw_Types.Cast(U16); + Cast_LE(Msg(Pos..Pos+1)); + Pos := Pos + 2; + end Write_U16; + + -- Read a 16-bits values from Octets from Pos; Pos increases by 2. + procedure Read_U16( Msg: in Raw_Types.Octets; + Pos: in out Natural; + U16: out Interfaces.Unsigned_16) is + O2 : Raw_Types.Octets_2; + begin + O2 := Msg(Pos..Pos+1); + Cast_LE(O2); + U16 := Raw_Types.Cast(O2); + Pos := Pos + 2; + end Read_U16; end Messages; diff -uNr a/smg_comms/src/messages.ads b/smg_comms/src/messages.ads --- a/smg_comms/src/messages.ads 32cd2279d2e7501f1c713a414424c1bb37d4c54fd279b14221ed6409431c47f469dccffe0b5ed303b1e3b2c77b2d7bb81e7902a4facd4d96b8e28522a71bb69f +++ b/smg_comms/src/messages.ads d6c3980da332629a8c09cfbfb32e1962ad689c7ecbc4a8ee83b02f85c1aa1a3374c5371eeee7f0cc49fe4c4d8e758f86fa5ba204c5900bd6f4f95cabb3a06ef6 @@ -57,7 +57,34 @@ Counter : out Interfaces.Unsigned_16; KMgm : out Keys_Mgm); + ----------------- File Transfer ---------------------- + + -- Writes the given File Chunk to a File Transfer type of message + -- Chunk - chunk of file to write; contains counter, filename, content + procedure Write_File_Transfer( Chunk : in File_Chunk; + Msg : out Raw_Types.Serpent_Msg); + + -- The opposite of Write_File_Transfer method above. + -- Chunk will contain the counter, filename and content + procedure Read_File_Transfer( Msg : in Raw_Types.Serpent_Msg; + Chunk : out File_Chunk); + + ----------------- File Request ---------------------- + -- Writes a message to request the files specified through their names + -- Written parameter will hold the number of filenames actually written + -- NB: this can be less than the number of filenames provided! + -- When Written < FR.F_No, the FIRST Written filenames were written; the rest + -- did not fit into the message and it's up to caller to decide what to do. + procedure Write_File_Request( FR : in Filenames; + Counter : in Interfaces.Unsigned_16; + Msg : out Raw_Types.Serpent_Msg; + Written : out Natural); + -- Reads a request for files; the opposite of Write_File_Request above + -- Raises Invalid_Msg exception if the provided message fails checks. + procedure Read_File_Request( Msg : in Raw_Types.Serpent_Msg; + Counter : out Interfaces.Unsigned_16; + FR : out Filenames); ------------------ -- RSA Messages -- @@ -90,12 +117,20 @@ -- Reads a Key management structure from the given RSA Message -- The opposite of Write_KMgm_SMsg above - -- Raises Invalid_Message exception if given message fails sanity checks + -- Raises Invalid_Msg exception if given message fails sanity checks procedure Read_KMgm_RMsg( Msg : in Raw_Types.RSA_Msg; Counter : out Interfaces.Unsigned_16; KMgm : out Keys_Mgm); + -- String to Octets conversion + -- NB: Str'Length has to be EQUAL to Octets'Length! + procedure String_To_Octets(Str: in String; O: out Raw_Types.Octets); + + -- Octets to string conversion + -- NB: Str'Length has to be EQUAL to Octets'Length! + procedure Octets_To_String(O: in Raw_Types.Octets; Str: out String); + private -- if native is little endian, does nothing; @@ -103,6 +138,10 @@ -- (strictly for arrays of octets) procedure Cast_LE( LE: in out Raw_Types.Octets ); + -- separator used for list of filenames + F_Sep: constant String := ";"; --as string + Sep: constant Interfaces.Unsigned_8 := 16#3B#; -- ascii code + -- protocol message types IDs, fixed as per protocol specification -- Serpent messages end in "S_Type" -- RSA messages end in "R_Type" @@ -164,4 +203,24 @@ Counter : out Interfaces.Unsigned_16; KMgm : out Keys_Mgm); + -- helper methods to read/write a value on 16 bits (using Cast_LE as needed) + + -- Writing a 16-bits value to the given Octets at specified position. + -- NB: Caller has to make sure Pos <= Msg'Last -1 ; NO check here! + -- Msg - the array of octets into which the value is to be written + -- Pos - the position in Msg at which to write the value; + -- NB: Pos will be increased by 2 after the write! + -- U16 - the value to write + procedure Write_U16( Msg: in out Raw_Types.Octets; + Pos: in out Natural; + U16: in Interfaces.Unsigned_16); + + -- Reading a 16-bits value from the given Octets at specified position. + -- NB: Caller has to make sure Pos <= Msg'Last -1 ; NO check here! + -- Pos - the position in Msg from which to read the value; + -- NB: Pos will be increased by 2 after the read! + -- The opposite of Write_U16 above. + procedure Read_U16( Msg: in Raw_Types.Octets; + Pos: in out Natural; + U16: out Interfaces.Unsigned_16); end Messages; diff -uNr a/smg_comms/tests/test_packing.adb b/smg_comms/tests/test_packing.adb --- a/smg_comms/tests/test_packing.adb eafef048291aff4715a31fe02b0ba62cab5d4b2d5d1e904b4a25dba9b08584b198c4bab46ca115b4809dd8506875719d6f30c506797cd0b399a2077c22ba1882 +++ b/smg_comms/tests/test_packing.adb a8a3f14cbacaec0691d66c7058cd758c510e3addec91d5529093f6259ad65d3353b714f316a32cde7cc476cac611b167250ce6615db506cb7d62ed98cbcc8bdf @@ -93,7 +93,7 @@ end if; -- try to unpack a mangled package - Pkt(Pkt'First + 3) := Pkt(Pkt'First + 3) and 16#AB#; + Pkt(Pkt'First + 3) := Pkt(Pkt'First + 3) + 1; Decr_Msg := (others => 0); Decr_Msg := Packing.Unpack( Pkt, SKey, Success ); if Success then diff -uNr a/smg_comms/tests/test_serializing.adb b/smg_comms/tests/test_serializing.adb --- a/smg_comms/tests/test_serializing.adb 108527aa9877fd1aa76fdf913c50760854260b8406db12a4c7b1a1a052d593eacc2d59d8f36f7bf70bdc6ac21a3a28e80930c89a64020ae597b67976100f61e2 +++ b/smg_comms/tests/test_serializing.adb 60ba5dffa63414f5b2d28611da978ef0cdaaccaeeba3383699e8ebff223f608bed0f6752411067cf8a40bbb209040fcc621557bcf771f2459268abe0edcdc6a9 @@ -130,5 +130,175 @@ end Serialize_Keys_Mgm; + procedure Serialize_File_Request( Reps: in Positive) is + MaxSz: Positive := 340; + O2 : Raw_Types.Octets_2; + U16 : Interfaces.Unsigned_16; + Counter : Interfaces.Unsigned_16; + ReadCounter: Interfaces.Unsigned_16; + Written: Natural; + Msg : Raw_Types.Serpent_Msg; + F_No, Sz: Text_Len; + begin + for I in 1 .. Reps loop + -- generate a random size + RNG.Get_Octets( O2 ); + U16 := Raw_Types.Cast( O2 ); + Sz := Text_Len( Positive(U16) mod MaxSz + 1); + + -- generate a random number of files + RNG.Get_Octets( O2 ); + U16 := Raw_Types.Cast( O2 ); + F_No := Text_Len( Positive(U16) mod Sz ); + if F_No = 0 then + F_No := 1; + end if; + + declare + FR: Filenames(F_No, Sz); + ReadFR: Filenames; + O : Octets(1..Sz); + Len : Positive := Sz / F_No; + begin + Put_Line("Generating test for File Request with " & + Integer'Image(FR.F_No) & " filenames."); + -- generate a random counter + RNG.Get_Octets(O2); + Counter := Raw_Types.Cast(O2); + + -- fill FR + RNG.Get_Octets( O ); + -- replace separators if any + for I in O'Range loop + if O(I) = 59 then + O(I) := 69; + end if; + end loop; + + Octets_To_String( O, FR.S ); + for I in FR.Starts'Range loop + FR.Starts(I) := Interfaces.Unsigned_16( FR.Starts'First + + Len*(I-FR.Starts'First)); + end loop; + + -- write FR to message + Write_File_Request(FR, Counter, Msg, Written); + + -- check how many filenames were written + if Written /= FR.F_No then + Put_Line("FAIL: only " & Natural'Image(Written) & + " filenames written out of " & Natural'Image(FR.F_No)); + else + Put_Line("PASS: wrote " & Natural'Image(Written) & " filenames."); + end if; + + -- read it from message and check result + Read_File_Request(Msg, ReadCounter, ReadFR); + if ReadCounter /= Counter then + Put_Line("FAIL: ReadCounter is " & Unsigned_16'Image(ReadCounter) & + " instead of expected " & Unsigned_16'Image(Counter) ); + else + Put_Line("PASS: ReadCounter was read correctly as " & + Unsigned_16'Image(ReadCounter)); + end if; + if ReadFr.Sz /= FR.Sz then + Put_Line("FAIL: Read FR.Sz = " & Text_Len'Image(ReadFr.Sz) & + " while expected sz is " & Text_Len'Image(FR.Sz)); + else + Put_Line("PASS: Read FR.Sz as expected = " & + Text_Len'Image(ReadFr.Sz)); + end if; + if ReadFr /= FR then + Put_Line("FAIL: ReadFr different from FR."); + else + Put_Line("PASS: ReadFr as expected, same as FR."); + end if; + end; + end loop; + + -- test with more files than can fit + Put_Line("Test case for File Request with more files than fit."); + declare + F: Filenames(4, 16384); + ReadF: Filenames; + begin + F.Starts(1) := Interfaces.Unsigned_16(F.S'First); + F.Starts(2) := Interfaces.Unsigned_16(F.S'First + 342); + F.Starts(3) := 16370; + F.Starts(4) := 16380; + Write_File_Request(F, Counter, Msg, Written); + if Written /= 1 then + Put_Line("FAIL: Written is " & Natural'Image(Written) & + " instead of expected 1."); + else + Put_Line("PASS: Written is 1 out of 4, as expected."); + end if; + Read_File_Request(Msg, ReadCounter, ReadF); + if ReadF.F_No /= 1 or ReadF.Starts(1) /= 1 or ReadF.Sz /= 342 then + Put_Line("FAIL: F_No is " & Text_Len'Image(ReadF.F_No) & + " Sz is " & Text_Len'Image(ReadF.Sz)); + else + Put_line("PASS: written 1 out of 4 correctly."); + end if; + end; + end Serialize_File_Request; + + procedure Serialize_File_Chunk is + Filename : String := "afile.png"; + FC : File_Chunk( Len => 945, + Count => 0, + Name_Len => Filename'Length); + ReadFC : File_Chunk; + Msg : Raw_Types.Serpent_Msg; + begin + -- fill FC with random content + FC.Filename := Filename; + RNG.Get_Octets(FC.Content); + + -- write FC to message + Write_File_Transfer( FC, Msg ); + + -- read FC and check + Read_File_Transfer( Msg, ReadFC ); + + if FC /= ReadFC then + Put_Line("FAIL: read/write file chunk."); + else + Put_Line("PASS: read/write file chunk."); + end if; + end Serialize_File_Chunk; + + procedure Converter_String_Octets is + Len: constant Natural := 234; + -- original values + S: String(1..Len); + O: Octets(1..Len); + -- converted values + CS: String(1..Len); + CO: Octets(1..Len); + begin + -- original octets + RNG.Get_Octets(O); + Octets_To_String(O, CS); + String_To_Octets(CS, CO); + if CO /= O then + Put_Line("FAIL: octets different after string/octets conversion."); + else + Put_Line("PASS: octets same after string/octets conversion."); + end if; + + -- original string + for I in S'Range loop + S(I) := Character'Val(I mod 12); + end loop; + String_To_Octets(S, CO); + Octets_To_String(CO, CS); + if CS /= S then + Put_Line("FAIL: string different after string/octets conversion."); + else + Put_Line("PASS: string same after string/octets conversion."); + end if; + end Converter_String_Octets; + end Test_Serializing; diff -uNr a/smg_comms/tests/test_serializing.ads b/smg_comms/tests/test_serializing.ads --- a/smg_comms/tests/test_serializing.ads e6f805434755b87ed7e265a405c3a505498ab7d154c47206dc3a7ec980ee58fd3df2af9df762ea764f82dd59c7ac90f99f61e48b1b99a88d38762c497f816572 +++ b/smg_comms/tests/test_serializing.ads 77dfbf402e60b9cd4d8838421571bc7d018078b66c4b7d54c40bcae20cd5554072704d6476659f19f8dd4ba82a3a006f1e0b5b2c2228aaa0abaaa87c338c025a @@ -7,6 +7,10 @@ procedure Serialize_Keyset_SS; procedure Serialize_Keys_Mgm; + procedure Serialize_File_Request( Reps: in Positive ); + procedure Serialize_File_Chunk; + + procedure Converter_String_Octets; private diff -uNr a/smg_comms/tests/testall.adb b/smg_comms/tests/testall.adb --- a/smg_comms/tests/testall.adb 117663918d15b926acf72a7ae5e3736aab93b06a12148422d9a74de147fb6e6f66961282cec214a9f946e778db1129bfdf14b184e63b84df86e54a07312df35a +++ b/smg_comms/tests/testall.adb 8ccd7a252824f3a0ba71e0b69fb36b7347146ea1b64aa0b297799717384c3ff1e954792ec2c4e1c762252a0c96ae46e438fe4cd541fa5a477c29b11c991b5775 @@ -16,4 +16,7 @@ Test_Packing.Test_Pack_Unpack_RSA; Test_Serializing.Serialize_Keyset_SS; Test_Serializing.Serialize_Keys_Mgm; + Test_Serializing.Serialize_File_Chunk; + Test_Serializing.Serialize_File_Request(5); + Test_Serializing.Converter_String_Octets; end testall;