DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400 Tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400 Tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ B T

⟦ca7de49d6⟧ TextFile

    Length: 16299 (0x3fab)
    Types: TextFile
    Names: »B«

Derivation

└─⟦afbc8121e⟧ Bits:30000532 8mm tape, Rational 1000, MC68020_OS2000 7_2_2
    └─ ⟦77aa8350c⟧ »DATA« 
        └─⟦f794ecd1d⟧ 
            └─⟦this⟧ 

TextFile

with Log;
with Machine;
with Byte_Defs;
with Transport;
with Transport_Defs;
with Transport_Name;
with String_Utilities;
with Device_Independent_Io;

procedure Os2000_Transfer
             (Local_File : String;
              Remote_File : String;
              Transliterate : Boolean;
              Transfer_Type : Os2000_Transfer_Utilities.Transfer_Type;
              Remote_Machine : String;
              Response : Profile.Response_Profile) is

    subtype Byte is Byte_Defs.Byte;
    subtype Byte_String is Byte_Defs.Byte_String;

    function "=" (L, R : Byte) return Boolean renames Byte_Defs."=";

    package Tp renames Transport;
    package Tn renames Transport_Name;
    package Td renames Transport_Defs;
    package Util renames Os2000_Transfer_Utilities;
    package Dio renames Device_Independent_Io;


    Handshake_Socket : constant Transport_Defs.Socket_Id := (1, 13);
    -- This is the socket on which the OS2000 server will
    -- wait for commands.  Sockets less than (4,0) are
    -- treated as privileged by OS2000 TCP/IP implementation.
    --

    Long_Time : constant Duration := 300.0;  -- 5 minutes

    Primary : Tp.Connection_Id;
    Secondary : Tp.Connection_Id;
    Status : Td.Status_Code;
    Count : Natural;
    Debug : constant Boolean := Util.Debug;

    task Transceiver is
        entry Start (Network : Td.Network_Name);
        entry Wait_For_Connection;
        entry Finish;
    end Transceiver;

    procedure Put_Debug (Msg : String) is
    begin
        Log.Put_Line (Msg, Kind => Profile.Debug_Msg, Response => Response);
    end Put_Debug;

    function Setup_Ax25_Port
                (Host : Td.Host_Id; Network : Td.Network_Name) return String is
        -- The_Job : constant String := Long_Integer'Image
        --                                (Long_Integer (Machine.Get_Task_Id));
        -- Disable : constant String :=
        --   Transport.Set_Options
        --      (Network,
        --       -- for Ax25 the port number is first byte of host id
        --       Context => Integer'Image (Integer (Host (Host'First))),
        --       Options => "ENABLED => FALSE");
    begin
        return Transport.Set_Options
                  (Network,
                   -- for Ax25 the port number is first byte of host id
                   Context => Integer'Image (Integer (Host (Host'First))),  
                   Options => "ENABLED => TRUE," & "PROTOCOL_HALF => DCE");
        -- "LEVEL_0 => (TASK =>" & The_Job & ")," &
        -- "LEVEL_2 => (MONITOR => TRUE)," &
        -- "LEVEL_3 => (MONITOR => TRUE)");
    end Setup_Ax25_Port;

    -- function Disable_Ax25_Port
    --             (Host : Td.Host_Id; Network : Td.Network_Name) return String is
    -- begin
    --     return Transport.Set_Options
    --               (Network,
    --                -- for Ax25 the port number is first byte of host id
    --                Context => Integer'Image (Integer (Host (Host'First))),
    --                Options => "ENABLED => FALSE");
    -- end Disable_Ax25_Port;

    procedure Transmit (Connection : Tp.Connection_Id; Data : Byte_String) is
        Status : Td.Status_Code;
        Total : Natural;
        Count : Natural;
    begin
        Tp.Transmit (Connection, Status, Data, Total);
        Util.Check_Transmit (Status, Response);
        while Total < Data'Length loop
            Tp.Transmit (Connection, Status,
                         Data (Data'First + Total .. Data'Last), Count);
            Util.Check_Transmit (Status, Response);
            Total := Total + Count;
        end loop;
    end Transmit;


    task body Transceiver is
        Status : Td.Status_Code;
        Count : Natural;
        Total : Natural := 0;
        File : Dio.File_Type;
        Rws : Natural;

        procedure Process_Output_Buffer
                     (S : in out Byte_String; Count : Natural) is
            -- change Lf to Cr on output
        begin
            for I in S'First .. S'First + Count - 1 loop
                if S (I) = Character'Pos (Ascii.Lf) then
                    S (I) := Character'Pos (Ascii.Cr);
                end if;
            end loop;
        end Process_Output_Buffer;

        procedure Process_Input_Buffer
                     (S : in out Byte_String; Count : Natural) is
            -- change Cr to Lf on input
        begin
            for I in S'First .. S'First + Count - 1 loop
                if S (I) = Character'Pos (Ascii.Cr) then
                    S (I) := Character'Pos (Ascii.Lf);
                end if;
            end loop;
        end Process_Input_Buffer;

    begin
        begin
            accept Start (Network : Td.Network_Name) do
                Tp.Open (Secondary, Status, Network);
                Util.Check_Open (Status, Response);
                if Debug then
                    Put_Debug ("Transceiver opened.");
                end if;
            end Start;
            if Debug then
                Put_Debug ("Transceiver connecting ...");
            end if;
            Tp.Connect (Secondary, Status);
            if Debug then
                Put_Debug ("Transceiver connected.");
            end if;
            accept Wait_For_Connection do
                Util.Check_Connect (Status, Response);
            end Wait_For_Connection;
        exception
            when Util.Check_Failed =>
                Log.Put_Line
                   ("Transceiver terminating due to Open or Connect failure",
                    Kind => Profile.Negative_Msg,
                    Response => Response);
                raise;
        end;

        declare
            S : Byte_String (1 .. 1024);
            Rf_Status : Util.Remote_File_Status;  
        begin
            Tp.Receive (Secondary, Status, S, Count, Long_Time);
            Util.Check_Receive (Status, Response);

            Rf_Status := Util.Extract_Status (S (1 .. Count));
            case Rf_Status is
                when Util.Success =>
                    null;
                when others =>
                    Log.Put_Line ("OS2000 unable to open file due to " &
                                  Util.Remote_File_Status'Image (Rf_Status),
                                  Kind => Profile.Error_Msg,
                                  Response => Response);
                    raise Util.No_Remote_File;
            end case;

            begin
                case Transfer_Type is
                    when Util.Put_Exe | Util.Put_File =>
                        Dio.Open (File, Dio.In_File, Local_File);
                        Log.Put_Line ("Opened R1000 file " & Local_File,
                                      Kind => Profile.Positive_Msg,
                                      Response => Response);

                    when Util.Get_File =>
                        Dio.Create (File, Dio.Out_File, Local_File);
                        Log.Put_Line ("Created R1000 file " & Local_File,
                                      Kind => Profile.Positive_Msg,
                                      Response => Response);
                end case;
            exception
                when others =>
                    Log.Put_Line ("Couldn't open R1000 file " & Local_File,
                                  Kind => Profile.Error_Msg,
                                  Response => Response);
                    raise Util.No_Local_File;
            end;

            Rws := 0;

            case Transfer_Type is
                when Util.Put_Exe | Util.Put_File =>
                    Count := 0;
                    while not Dio.End_Of_File (File) loop
                        Dio.Read (File, S, Count);

                        if Debug then
                            Put_Debug ("Number of bytes read: " &
                                       Integer'Image (Count));
                        end if;
                        if Transliterate then
                            Process_Output_Buffer (S, Count);
                        end if;

                        if Count = S'Length then
                            Transmit (Secondary, S);
                            Rws := Rws + 1;
                        elsif Count > 0 then
                            Transmit (Secondary, S (1 .. Count));
                            Rws := Rws + 1;
                        else
                            exit;
                        end if;
                        Total := Total + Count;
                    end loop;

                    if Transliterate and then (Count > 0) and then
                       (S (Count) /= Character'Pos (Ascii.Cr)) then
                        S (S'First) := Character'Pos (Ascii.Cr);
                        Transmit (Secondary, S (1 .. 1));
                        Rws := Rws + 1;
                    end if;

                when Util.Get_File =>
                    loop
                        Tp.Receive (Secondary, Status, S, Count, Long_Time);

                        if Count > 0 then
                            Util.Check_Receive (Status, Response);

                            if Transliterate then
                                Process_Input_Buffer (S, Count);
                            end if;
                            if Count = S'Length then
                                Dio.Write (File, S);
                            else
                                Dio.Write (File, S (1 .. Count));
                            end if;
                            Total := Total + Count;
                        else
                            exit;
                        end if;
                    end loop;

                    declare
                        Excess : Byte_String (1 .. 1);
                    begin
                        loop
                            Tp.Receive (Secondary, Status, Excess, Count);
                            if Count > 0 then
                                Log.Put_Line ("Excess data received: " &
                                              Character'Val (Excess (1)),
                                              Kind => Profile.Warning_Msg,
                                              Response => Response);  
                            end if;
                            exit when not Tp.Is_Connected (Secondary);
                        end loop;
                    end;
            end case;

            if Debug then
                Put_Debug ("Number of read/writes:  " & Integer'Image (Rws));
            end if;
            Log.Put_Line ("Number of bytes transferred = " &
                          Integer'Image (Total),
                          Kind => Profile.Positive_Msg,
                          Response => Response);
            Dio.Close (File);
            Log.Put_Line ("Closed file " & Local_File,
                          Kind => Profile.Positive_Msg,
                          Response => Response);
        exception
            when Util.No_Remote_File | Util.No_Local_File =>
                Log.Put_Line ("Transceiver not attempting transfer",
                              Kind => Profile.Negative_Msg,
                              Response => Response);

            when others =>
                Log.Put_Line
                   ("Transceiver got an unexpected exception in transfer.",
                    Kind => Profile.Exception_Msg,
                    Response => Response);
        end;

        Tp.Disconnect (Secondary);
        Tp.Close (Secondary);
        accept Finish;
    exception
        when Util.Check_Failed =>
            null;

        when others =>
            Log.Put_Line ("Transceiver got an unexpected exception.",
                          Kind => Profile.Exception_Msg,
                          Response => Response);
    end Transceiver;

    procedure Connect (Connection : Tp.Connection_Id;
                       Host : Td.Host_Id;
                       Socket : Td.Socket_Id) is
        Retries : constant := 20;
        Backoff : constant Duration := 3.0;
        Status : Td.Status_Code;
    begin
        for I in 1 .. Retries loop
            Tp.Connect (Connection, Status, Host, Socket);
            case Status is
                when Td.Not_Initialized | Td.Connection_Refused =>
                    delay Backoff;
                when others =>
                    exit;
            end case;
        end loop;
        Util.Check_Connect (Status, Response);
    end Connect;

begin
    declare
        Machine : constant String :=
           Util.Remote_Machine (Remote_Machine, Response);
        Network : constant Td.Network_Name := Util.Network (Machine, Response);
        Host : constant Td.Host_Id := Util.Host (Machine, Response);
        Is_Ax25 : constant Boolean :=
           String_Utilities.Equal
              (String (Network), "AX25", Ignore_Case => True);
    begin
        Log.Put_Line ("Initiating OS2000 transfer to remote machine " &
                      String_Utilities.Upper_Case (Machine),
                      Kind => Profile.Positive_Msg,
                      Response => Response);
        if Is_Ax25 then
            declare
                Result : constant String := Setup_Ax25_Port (Host, Network);
            begin
                if Result'Length > 0 then
                    Log.Put_Line ("Ax25 Options rejected: " & Result,
                                  Kind => Profile.Negative_Msg,
                                  Response => Response);
                end if;
            end;
        end if;

        begin
            Tp.Open (Primary, Status, Network);
            Util.Check_Open (Status, Response);

            Connect (Primary, Host, Handshake_Socket);

            Transceiver.Start (Network);
            while not Tp.Is_Connecting_Passive (Secondary) loop
                delay 0.5;
            end loop;
        exception
            when Util.Check_Failed =>
                Log.Put_Line
                   ("Aborting transfer because Open or Connect failed.",
                    Kind => Profile.Negative_Msg,
                    Response => Response);
                raise;
            when others =>
                Log.Put_Line
                   ("Unexpected exception in OS2000 transfer initialization",
                    Kind => Profile.Exception_Msg,
                    Response => Response);
                raise;
        end;

        declare
            My_Socket : constant Td.Socket_Id := Tp.Local_Socket (Secondary);
        begin
            if Debug then
                Put_Debug ("Secondary local socket = ");
                for I in My_Socket'Range loop
                    Put_Debug (Integer'Image (Integer (My_Socket (I))));
                end loop;
            end if;
        end;

        Transmit (Primary, Util.Make_Command
                              (Tp.Local_Socket (Secondary), Transfer_Type));

        if Debug then
            Put_Debug ("***TRANSMIT status => " & Td.Image (Status));
        end if;

        Transceiver.Wait_For_Connection;

        declare
            Send_Name : Byte_String (Remote_File'First .. Remote_File'Last);
        begin
            Log.Put_Line ("Requesting OS2000 to open file " &
                          String_Utilities.Upper_Case (Remote_File),
                          Kind => Profile.Positive_Msg,
                          Response => Response);

            for I in Remote_File'Range loop
                Send_Name (I) := Character'Pos (Remote_File (I));
            end loop;
            Transmit (Primary, Send_Name);
        end;
        Transceiver.Finish;
        Tp.Disconnect (Primary);
        Tp.Close (Primary);

        Log.Put_Line ("[OS2000 transfer complete]",
                      Kind => Profile.Auxiliary_Msg,
                      Response => Response);
    end;
exception
    when Util.Remote_Machine_Unknown =>
        Log.Put_Line ("Aborting transfer because remote machine unknown",
                      Kind => Profile.Negative_Msg,
                      Response => Response);
        abort Transceiver;

    when Util.Check_Failed =>
        abort Transceiver;

    when others =>
        Log.Put_Line ("Unexpected exception in OS2000 transfer.",
                      Kind => Profile.Exception_Msg,
                      Response => Response);
        abort Transceiver;
        raise;
end Os2000_Transfer;