?? RIGHT := 110 ??
MODULE nam$external_connection_mgmt;
{
{ This module contains the external interfaces to the connection management
{ service provided by NAMVE. These procedures call ring 3 procedures that
{ manipulate the connection management data structures.
?? PUSH (LISTEXT:=ON) ??
*copyc fst$file_reference
*copyc jmt$system_supplied_name
*copyc nae$application_interfaces
*copyc nae$directory_me_conditions
*copyc nat$change_attributes
*copyc nat$create_attributes
*copyc nat$directory_interfaces
*copyc nat$directory_search_identifier
*copyc nat$get_attributes
*copyc nat$network_address
*copyc nat$translation_attributes
*copyc nat$directory_priority
*copyc nat$protocol
*copyc nat$wait_time
*copyc ost$i_wait
?? POP ??
?? TITLE := 'XREF PROCEDURES', EJECT ??
*copyc amp$return
*copyc nap$get_attributes
*copyc nap$namve_system_error
*copyc nlp$accept_switch_offer
*copyc nlp$acquire_connection
*copyc nlp$acquire_specific_connection
*copyc nlp$get_title_translation
*copyc nlp$offer_connection_switch
*copyc nlp$request_connection
*copyc osp$append_status_integer
*copyc osp$append_status_parameter
*copyc osp$i_await_activity_completion
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc pmp$get_microsecond_clock
?? TITLE := 'GLOBAL VARIABLES', EJECT ??
*copyc oss$job_paged_literal
  VAR
    attributes_parameter: [READ, OSS$JOB_PAGED_LITERAL] string (10) := 'ATTRIBUTES',
    get_title_translation: [READ, OSS$JOB_PAGED_LITERAL] string (25) := 'NAP$GET_TITLE_TRANSLATION';


?? TITLE := 'NAP$ACCEPT_SWITCH_OFFER', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$accept_switch_offer (file: fst$file_reference;
        source: jmt$system_supplied_name;
        attributes: ^nat$change_attributes;
        wait_time: nat$wait_time;
    VAR status: ost$status);

*copyc nah$accept_switch_offer

    VAR
      activity_list: array [1 .. 2] of ost$i_activity,
      file_attributes: ^nat$create_attributes,
      i: integer,
      ready_index: integer;

    status.normal := TRUE;
    IF attributes <> NIL THEN
      PUSH file_attributes : [LOWERBOUND(attributes^) .. UPPERBOUND(attributes^)];
      FOR i := LOWERBOUND (attributes^) TO UPPERBOUND (attributes^) DO
        file_attributes^[i].kind := attributes^[i].kind;
        CASE attributes^[i].kind OF
        = nac$data_transfer_timeout =
          file_attributes^[i].data_transfer_timeout := attributes^[i].data_transfer_timeout;
        = nac$eoi_message =
          file_attributes^[i].eoi_message := attributes^[i].eoi_message;
        = nac$eoi_message_enabled =
          file_attributes^[i].eoi_message_enabled := attributes^[i].eoi_message_enabled;
        = nac$eoi_peer_termination =
          file_attributes^[i].eoi_peer_termination := attributes^[i].eoi_peer_termination;
        = nac$null_attribute =
            ;
        = nac$receive_wait_swapout =
          file_attributes^[i].receive_wait_swapout := attributes^[i].receive_wait_swapout;
        = nac$termination_data =
          file_attributes^[i].termination_data := attributes^[i].termination_data;
        ELSE
        CASEND;
      FOREND;
    ELSE
      file_attributes := NIL;
    IFEND;

    nlp$accept_switch_offer (file, source, file_attributes, FALSE, status);
    IF (NOT status.normal) AND (status.condition = nae$no_switch_offered) AND (wait_time > 0) THEN
      activity_list [1].activity := nac$i_await_switch_offer;
      activity_list [1].source := source;
      activity_list [2].activity := osc$i_await_time;
      activity_list [2].milliseconds := wait_time;
      osp$i_await_activity_completion (activity_list, ready_index, status);
      IF status.normal THEN
        nlp$accept_switch_offer (file, source, file_attributes, FALSE, status);
      IFEND;
    IFEND;

  PROCEND nap$accept_switch_offer;
?? TITLE := 'NAP$ACQUIRE_CONNECTION', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$acquire_connection (server: nat$application_name;
        file: fst$file_reference;
        attributes: ^nat$create_attributes;
        wait_time: nat$wait_time;
    VAR status: ost$status);

*copyc nah$acquire_connection

     CONST
       local_clock = 0;

     VAR
       activity_list: array [1 .. 2] of ost$i_activity,
       last_time: integer,
       now: integer,
       ready_index: integer,
       time: integer;

    status.normal := TRUE;
    nlp$acquire_connection (server, file, {file_exists:=} FALSE, attributes, status);
    IF NOT status.normal THEN
      activity_list [1].activity := nac$i_await_connection;
      activity_list [1].server := server;
      activity_list [2].activity := osc$i_await_time;
      activity_list [2].milliseconds := wait_time;
      time := wait_time;
      last_time := #FREE_RUNNING_CLOCK (local_clock);
      WHILE (NOT status.normal) AND (status.condition = nae$no_connection_available) AND (time > 0) DO
        activity_list [2].milliseconds := time;
        osp$i_await_activity_completion (activity_list, ready_index, status);
        IF status.normal AND (ready_index = 1) THEN
          nlp$acquire_connection (server, file, {file_exists:=} FALSE, attributes, status);
          IF NOT status.normal THEN
            now := #FREE_RUNNING_CLOCK (local_clock);
            time := time - ((now - last_time) DIV 1000);
            last_time := now;
          IFEND;
        ELSEIF status.normal AND (ready_index = 2) THEN
          time := 0;
          osp$set_status_condition ( nae$no_connection_available,  status);
        IFEND;
      WHILEND;
    IFEND;

  PROCEND nap$acquire_connection;
?? TITLE := '[XDCL, #GATE] nap$acquire_specific_connection', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$acquire_specific_connection
   (    system_job_name: jmt$system_supplied_name;
        server: nat$application_name;
        file: fst$file_reference;
        attributes: ^nat$create_attributes;
        wait_time: nat$wait_time;
    VAR status: ost$status);

     CONST
       local_clock = 0;

     VAR
       activity_list: array [1 .. 2] of ost$i_activity,
       last_time: integer,
       now: integer,
       ready_index: integer,
       time: integer;

    status.normal := TRUE;
    nlp$acquire_specific_connection (system_job_name, server, file, {file_exists} FALSE, attributes, status);
    IF NOT status.normal THEN
      activity_list [1].activity := nac$i_await_connection;
      activity_list [1].server := server;
      activity_list [2].activity := osc$i_await_time;
      activity_list [2].milliseconds := wait_time;
      time := wait_time;
      last_time := #FREE_RUNNING_CLOCK (local_clock);
      WHILE (NOT status.normal) AND (status.condition = nae$no_connection_available) AND (time > 0) DO
        activity_list [2].milliseconds := time;
        osp$i_await_activity_completion (activity_list, ready_index, status);
        IF status.normal AND (ready_index = 1) THEN
          nlp$acquire_specific_connection (system_job_name, server, file, {file_exists} FALSE, attributes,
                status);
          IF NOT status.normal THEN
            now := #FREE_RUNNING_CLOCK (local_clock);
            time := time - ((now - last_time) DIV 1000);
            last_time := now;
          IFEND;
        ELSEIF status.normal AND (ready_index = 2) THEN
          time := 0;
          osp$set_status_condition (nae$no_connection_available, status);
        IFEND;
      WHILEND;
    IFEND;

  PROCEND nap$acquire_specific_connection;
?? TITLE := 'NAP$CLONE_CONNECTION', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$clone_connection (server: nat$application_name;
        file: fst$file_reference;
        attributes: ^nat$create_attributes;
        wait_time: nat$wait_time;
    VAR status: ost$status);

*copyc nah$acquire_connection

     CONST
       local_clock = 0;

     VAR
       activity_list: array [1 .. 2] of ost$i_activity,
       last_time: integer,
       now: integer,
       ready_index: integer,
       time: integer;

    status.normal := TRUE;
    nlp$acquire_connection (server, file, {file_exists:=} TRUE, attributes, status);
    IF NOT status.normal THEN
      activity_list [1].activity := nac$i_await_connection;
      activity_list [1].server := server;
      activity_list [2].activity := osc$i_await_time;
      activity_list [2].milliseconds := wait_time;
      time := wait_time;
      last_time := #FREE_RUNNING_CLOCK (local_clock);
      WHILE (NOT status.normal) AND (status.condition = nae$no_connection_available) AND (time > 0) DO
        activity_list [2].milliseconds := time;
        osp$i_await_activity_completion (activity_list, ready_index, status);
        IF status.normal AND (ready_index = 1) THEN
          nlp$acquire_connection (server, file, {file_exists:=} TRUE, attributes, status);
          IF NOT status.normal THEN
            now := #FREE_RUNNING_CLOCK (local_clock);
            time := time - ((now - last_time) DIV 1000);
            last_time := now;
          IFEND;
        ELSEIF status.normal AND (ready_index = 2) THEN
          time := 0;
          osp$set_status_condition ( nae$no_connection_available,  status);
        IFEND;
      WHILEND;
    IFEND;

  PROCEND nap$clone_connection;
?? TITLE := 'NAP$AWAIT_SERVER_RESPONSE', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$await_server_response (file: fst$file_reference;
        wait_time: nat$wait_time;
    VAR status: ost$status);

*copyc nah$await_server_response

    VAR
      activity_list: array [1 .. 2] of ost$i_activity,
      local_file: ^fst$file_reference,
      ready_index: integer;

    status.normal := TRUE;
    PUSH local_file: [#SIZE (file)];
    local_file^ := file;

    IF wait_time > 0 THEN
      activity_list [1].activity := nac$i_await_server_response;
      activity_list [1].file := local_file;
      activity_list [2].activity := osc$i_await_time;
      activity_list [2].milliseconds := wait_time;
      osp$i_await_activity_completion (activity_list, ready_index, status);
      IF (status.normal) AND (ready_index = 2) THEN
{ The task waited for the specified time but the server did not respond.
        osp$set_status_abnormal (nac$status_id, nae$no_server_response, local_file^, status);
      IFEND;
    IFEND;

  PROCEND nap$await_server_response;
?? TITLE := 'NAP$GET_TITLE_TRANSLATION', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$get_title_translation (
         search_identifier: nat$directory_search_identifier;
         wait_time: nat$wait_time;
     VAR attributes {input, output} : ^nat$translation_attributes;
     VAR network_address: nat$network_address;
     VAR status: ost$status);

*copyc nah$get_title_translation

    VAR
      activity_list: array [1 .. 2] of ost$i_activity,
      address: nat$osi_translation_address,
      current_time: integer,
      end_time: integer,
      i: integer,
      identifier: nat$directory_entry_identifier,
      ignore_status: ost$status,
      priority: nat$directory_priority,
      ready_index: integer,
      request_complete: boolean,
      service: nat$protocol,
      title: string (nac$max_title_length),
      title_length: nat$title_length,
      user_identifier: ost$name,
      user_info: SEQ (REP nac$max_directory_data_length OF cell),
      user_info_length: nat$directory_data_length;

    status.normal := TRUE;
    IF attributes <> NIL THEN
      FOR i := LOWERBOUND (attributes^) TO UPPERBOUND (attributes^) DO
        CASE attributes^ [i].selector OF
        = nac$translation_title, nac$translation_priority, nac$translation_data, nac$translation_protocol =
          ;
        ELSE
          osp$set_status_abnormal (nac$status_id, nae$invalid_selector, get_title_translation, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, attributes_parameter, status);
          osp$append_status_integer (osc$status_parameter_delimiter, i, 10, FALSE, status);
          RETURN;
        CASEND;
      FOREND;
    IFEND;

    request_complete := FALSE;
    pmp$get_microsecond_clock (current_time, ignore_status);
    end_time := current_time + (wait_time * 1000);
    activity_list [1].activity := nac$i_await_title_translation;
    activity_list [1].translation_request := search_identifier;
    activity_list [2].activity := osc$i_await_time;

  /get_translation/
    WHILE status.normal AND NOT request_complete DO
      pmp$get_microsecond_clock (current_time, ignore_status);
      IF end_time > current_time THEN {wait for a translation}
        activity_list [2].milliseconds := (end_time - current_time) DIV 1000;
        osp$i_await_activity_completion (activity_list, ready_index, status);
      ELSE {no wait ... look for a translation immediately}
        ready_index := 1;
      IFEND;
      IF status.normal THEN
        IF ready_index = 1 THEN
          nlp$get_title_translation (search_identifier, title, address, service, ^user_info, user_info_length,
                priority, user_identifier, identifier, status);
          IF status.normal THEN
            network_address.kind := address.kind;
            CASE address.kind OF
            = nac$osi_transport_address =
              network_address.osi_transport_address := address.osi_transport_address;
            = nac$osi_session_address, nac$osi_non_cdna_session_addr =
              network_address.osi_session_address := address.osi_session_address;
            = nac$osi_presentation_address, nac$osi_non_cdna_present_addr =
              network_address.osi_presentation_address := address.osi_presentation_address;
            ELSE {reject this translation and try for another}
              CYCLE /get_translation/;
            CASEND;
            IF attributes <> NIL THEN
              FOR i := LOWERBOUND (attributes^) TO UPPERBOUND (attributes^) DO
                CASE attributes^ [i].selector OF
                = nac$translation_title =
                  attributes^ [i].title^ := title;
                  title_length := #SIZE (title);
                  WHILE (title_length > 1) AND (title (title_length) = ' ') DO
                    title_length := title_length - 1;
                  WHILEND;
                  attributes^ [i].title_length := title_length;

                = nac$translation_priority =
                  attributes^ [i].priority := priority;

                = nac$translation_data =
                  attributes^ [i].data^ := user_info;
                  attributes^ [i].data_length := user_info_length;

                = nac$translation_protocol =
                  attributes^ [i].protocol := service;

                CASEND;
              FOREND;
            IFEND;
            request_complete := TRUE;
          ELSEIF status.condition = nae$wait_for_distributed_title THEN
            osp$set_status_condition ( nae$no_translation_available,  status);
          ELSEIF status.condition = nae$translation_req_not_active THEN
            osp$set_status_abnormal (nac$status_id, nae$invalid_directory_search_id, get_title_translation,
                  status);
          IFEND;
        ELSEIF ready_index = 2 THEN { The task waited for the specified time and the server did not respond.
          osp$set_status_condition ( nae$no_translation_available,  status);
        IFEND;
      IFEND;
    WHILEND /get_translation/;

  PROCEND nap$get_title_translation;
?? TITLE := 'NAP$OFFER_CONNECTION_SWITCH', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$offer_connection_switch (file: fst$file_reference;
        destination: jmt$system_supplied_name;
        wait_time: nat$wait_time;
    VAR status: ost$status);

*copyc nah$offer_connection_switch

    VAR
      activity_list: array [1 .. 2] of ost$i_activity,
      local_file: ^fst$file_reference,
      ready_index: integer;

    status.normal := TRUE;
    PUSH local_file: [#SIZE (file)];
    local_file^ := file;

    nlp$offer_connection_switch (local_file^, destination, FALSE, status);
    IF (status.normal) AND (wait_time > 0) THEN
      activity_list [1].activity := nac$i_await_switch_accept;
      activity_list [1].file := local_file;
      activity_list [2].activity := osc$i_await_time;
      activity_list [2].milliseconds := wait_time;
      osp$i_await_activity_completion (activity_list, ready_index, status);
      IF ready_index = 2 THEN
{ The task waited for the specified time and the switch offer was not accepted.
        osp$set_status_abnormal (nac$status_id, nae$switch_offer_not_accepted, local_file^, status);
      IFEND;
    IFEND;

  PROCEND nap$offer_connection_switch;
?? TITLE := 'NAP$REQUEST_CONNECTION', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$request_connection (server: nat$network_address;
        client: nat$application_name;
        file: fst$file_reference;
        protocol: nat$protocol;
        attributes: ^nat$create_attributes;
        wait_time: nat$wait_time;
    VAR status: ost$status);

*copyc nah$request_connection

    VAR
      activity_list: array [1 .. 2] of ost$i_activity,
      connection_attributes: array [1 .. 1] of nat$get_attribute,
      ignore_status: ost$status,
      local_file: ^fst$file_reference,
      ready_index: integer;

    status.normal := TRUE;
    PUSH local_file: [#SIZE (file)];
    local_file^ := file;

    nlp$request_connection (server, client, local_file^, protocol, attributes, status);
    IF (status.normal) AND (wait_time > 0) THEN
      activity_list [1].activity := nac$i_await_server_response;
      activity_list [1].file := local_file;
      activity_list [2].activity := osc$i_await_time;
      activity_list [2].milliseconds := wait_time;
      osp$i_await_activity_completion (activity_list, ready_index, status);
      IF (NOT status.normal) OR (ready_index = 2) THEN
        amp$return (local_file^, ignore_status);
      IFEND;

      IF ready_index = 2 THEN
{ The task waited for the specified time and the server did not respond.
        osp$set_status_abnormal (nac$status_id, nae$server_response_timeout, local_file^, status);
      IFEND;

      IF status.normal THEN
        connection_attributes [1].kind := nac$connection_state;
        nap$get_attributes (local_file^, connection_attributes, ignore_status);
        IF ignore_status.normal THEN
          CASE connection_attributes [1].connection_state OF
          = nac$connection_request_sent =
           { Should have timed out. }
          = nac$connection_request_received =
           { Should never end up here. }
            nap$namve_system_error (FALSE, 'Invalid response on request connection.', NIL);
          = nac$established =
           { Request complete. }
          = nac$terminated =
            amp$return (local_file^, ignore_status);
            osp$set_status_condition ( nae$connection_terminated,  status);
          ELSE
          CASEND;
        IFEND;
      IFEND;
    IFEND;

  PROCEND nap$request_connection;
MODEND nam$external_connection_mgmt;
