?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE : Interactive Load Leveling' ??
MODULE jmm$switch_remote_connection;

{ PURPOSE:
{   This module contains the procedures to initiate the switching of a
{   connection to a destination job on another mainframe.
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc clc$standard_file_names
*copyc clt$parameter_list
*copyc jmt$leveled_job_connect_data
*copyc jmt$paired_connection_data
*copyc osc$timesharing
*copyc osc$timesharing_terminal_file
*copyc oss$job_paged_literal
*copyc ost$free_running_clock
?? POP ??
*copyc amp$return
*copyc fsp$close_file
*copyc fsp$open_file
*copyc iip$vtp_create_paired_connect
*copyc iip$vtp_delete_paired_connect
*copyc jmp$generate_timesharing_title
*copyc nap$acquire_specific_connection
*copyc nap$attach_specific_server_appl
*copyc nap$detach_specific_server_appl
*copyc nap$get_attributes
*copyc nlp$register_nominal_connection
*copyc osp$generate_log_message
*copyc pmp$convert_mainframe_to_binary
*copyc pmp$get_unique_name
*copyc pmp$log_ascii
*copyc pmp$long_term_wait
*copyc rmp$request_terminal
?? OLDTITLE ??
?? NEWTITLE := 'log_unexpected_message', EJECT ??

  PROCEDURE log_unexpected_message
    (    message: string ( * ));

    VAR
      local_status: ost$status;

    pmp$log_ascii (message, $pmt$ascii_logset [pmc$system_log, pmc$job_log], pmc$msg_origin_system,
          local_status);
  PROCEND log_unexpected_message;
?? OLDTITLE ??
?? NEWTITLE := 'log_unexpected_status', EJECT ??

  PROCEDURE log_unexpected_status
    (    error_status: ost$status);

    VAR
      local_status: ost$status;

    osp$generate_log_message ($pmt$ascii_logset [pmc$system_log, pmc$job_log], error_status, local_status);
  PROCEND log_unexpected_status;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$switch_remote_connection', EJECT ??

{ PURPOSE:
{   The purpose of this request is to initiate the switching of a connection from
{   one mainframe to another.  A request to create a paired connection is made
{   and the response to this request is handled.

  PROCEDURE [XDCL, #GATE] jmp$switch_remote_connection
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);

?? NEWTITLE := 'create_paired_connection', EJECT ??

    PROCEDURE create_paired_connection
      (    file_id: amt$file_identifier;
           system_job_name: jmt$system_supplied_name;
           network_file_name: ost$name;
           destination_mainframe_id: pmt$mainframe_id;
           encrypted_password: ost$name;
       VAR status: ost$status);

      CONST
        paired_connect_timeout_interval = 120000; { in milliseconds

      VAR
        binary_mainframe_id: pmt$binary_mainframe_id,
        current_clock: ost$free_running_clock,
        ignore_status: ost$status,
        paired_connection_data: jmt$paired_connection_data,
        paired_connection_data_p: ^jmt$paired_connection_data,
        termination_data_p: ^SEQ ( * ),
        termination_attributes_p: ^nat$get_attributes,
        time_left: integer,
        timesharing_title: ost$name;


      status.normal := TRUE;

      pmp$convert_mainframe_to_binary (destination_mainframe_id, binary_mainframe_id, ignore_status);
      jmp$generate_timesharing_title (binary_mainframe_id, timesharing_title);

      paired_connection_data.connection_request := jmc$pcr_leveled_job_request;
      paired_connection_data.leveled_job_request.system_job_name := system_job_name;
      paired_connection_data.leveled_job_request.encrypted_password := encrypted_password;

      iip$vtp_create_paired_connect (file_id, timesharing_title, #SEQ (paired_connection_data),
            paired_connect_timeout_interval, status);
      IF NOT status.normal THEN
        log_unexpected_message ('Create paired connection failed with...');
        log_unexpected_status (status);
        paired_connection_data.connection_request := jmc$pcr_leveled_job_results;
        paired_connection_data.leveled_job_results.successful := FALSE;
        iip$vtp_delete_paired_connect (file_id, #SEQ (paired_connection_data), status);
        IF NOT status.normal THEN
          log_unexpected_message ('Delete paired connection failed with...');
          log_unexpected_status (status);
        IFEND;
      ELSE

        PUSH termination_attributes_p: [1 .. 1];
        termination_attributes_p^ [1].kind := nac$connection_state;
        termination_attributes_p^ [1].connection_state := nac$established;
        current_clock := #FREE_RUNNING_CLOCK (0);
        time_left := paired_connect_timeout_interval;
        WHILE (time_left > 0) AND (termination_attributes_p^ [1].connection_state <> nac$terminated) DO
          pmp$long_term_wait (time_left DIV 12, time_left DIV 12);
          nap$get_attributes (network_file_name, termination_attributes_p^, ignore_status);
          time_left := paired_connect_timeout_interval - ((#FREE_RUNNING_CLOCK (0) - current_clock) DIV 1000);
        WHILEND;

        IF (termination_attributes_p^ [1].connection_state = nac$terminated) THEN

{ Need to look at the peer termination data to verify that the job was disconnected due
{ to the leveled job accepting the switched connection successfully.

          PUSH termination_data_p: [[REP 256 OF cell]];
          PUSH termination_attributes_p: [1 .. 1];
          termination_attributes_p^ [1].kind := nac$peer_termination_data;
          termination_attributes_p^ [1].peer_termination_data := termination_data_p;
          nap$get_attributes (network_file_name, termination_attributes_p^, status);
          IF NOT status.normal THEN
            log_unexpected_message ('Unable to get peer termination data for a paired connection.');
            log_unexpected_status (status);
          ELSE
            RESET termination_data_p;
            NEXT paired_connection_data_p IN termination_data_p;
            IF (paired_connection_data_p = NIL) OR (termination_attributes_p^ [1].
                  peer_termination_data_length < #SIZE (paired_connection_data_p^)) OR
                  (paired_connection_data_p^.connection_request <> jmc$pcr_leveled_job_results) OR
                  (NOT paired_connection_data_p^.leveled_job_results.successful) THEN

              log_unexpected_message (
                    'Job disconnected while waiting for partner mainframe to delete the connection.');
            IFEND;
          IFEND;
        ELSE

{ Backout - The job should have been disconnected.  The target job must not have picked up the connection.
{   Delete the paired connection and return.

          log_unexpected_message ('The target job failed to delete the paired connection.');
          paired_connection_data.connection_request := jmc$pcr_leveled_job_results;
          paired_connection_data.leveled_job_results.successful := FALSE;
          iip$vtp_delete_paired_connect (file_id, #SEQ (paired_connection_data), status);
          IF NOT status.normal THEN
            log_unexpected_message ('Delete paired connection failed with...');
            log_unexpected_status (status);
          IFEND;
        IFEND;
      IFEND;

    PROCEND create_paired_connection;
?? OLDTITLE ??
?? EJECT ??

    CONST
      acquire_timeout = 60,
      max_connections = 1;

    VAR
      access_creation_selections: ^fst$file_cycle_attributes,
      access_selections: ^fst$attachment_options,
      create_attributes: ^nat$create_attributes,
      destination_mainframe_id: pmt$mainframe_id,
      encrypted_password: ost$name,
      file_id: amt$file_identifier,
      ignore_status: ost$status,
      leveled_job_connect_data_p: ^jmt$leveled_job_connect_data,
      network_file_name: ost$name,
      null_conn_attribute: ^ift$connection_attributes,
      parameter_list_p: ^clt$parameter_list,
      system_job_name_p: ^jmt$system_supplied_name,
      terminal_file_name: ost$name;


    status.normal := TRUE;

    parameter_list_p := ^parameter_list;
    RESET parameter_list_p;
    NEXT leveled_job_connect_data_p IN parameter_list_p;

    nap$attach_specific_server_appl (leveled_job_connect_data_p^.system_job_name, osc$timesharing,
          {max_connections} 1, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH create_attributes: [1 .. 2];
    create_attributes^ [1].kind := nac$data_transfer_timeout;
    create_attributes^ [1].data_transfer_timeout := nac$max_wait_time;
    create_attributes^ [2].kind := nac$receive_wait_swapout;
    create_attributes^ [2].receive_wait_swapout := TRUE;

    pmp$get_unique_name (network_file_name, ignore_status);
    nap$acquire_specific_connection (leveled_job_connect_data_p^.system_job_name, osc$timesharing,
          network_file_name, create_attributes, acquire_timeout, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    nap$detach_specific_server_appl (leveled_job_connect_data_p^.system_job_name, osc$timesharing, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH null_conn_attribute: [1 .. 1];
    null_conn_attribute^ [1].key := ifc$null_connection_attribute;

    pmp$get_unique_name (terminal_file_name, ignore_status);
    rmp$request_terminal (terminal_file_name, ^network_file_name, null_conn_attribute^, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH access_selections: [1 .. 1];
    access_selections^ [1].selector := fsc$access_and_share_modes;
    access_selections^ [1].access_modes.selector := fsc$specific_access_modes;
    access_selections^ [1].access_modes.value := $fst$file_access_options [fsc$read, fsc$append, fsc$modify];
    access_selections^ [1].share_modes.selector := fsc$required_share_modes;

    PUSH access_creation_selections: [1 .. 1];
    access_creation_selections^ [1].selector := fsc$file_contents_and_processor;
    access_creation_selections^ [1].file_contents := amc$list;
    access_creation_selections^ [1].file_processor := osc$null_name;

    fsp$open_file (terminal_file_name, amc$record, access_selections, access_creation_selections,
          access_creation_selections, NIL, NIL, file_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    create_paired_connection (file_id, leveled_job_connect_data_p^.system_job_name, network_file_name,
          leveled_job_connect_data_p^.destination_mainframe_id,
          leveled_job_connect_data_p^.encrypted_password, status);

    fsp$close_file (file_id, ignore_status);
    amp$return (terminal_file_name, ignore_status);
    amp$return (network_file_name, ignore_status);

  PROCEND jmp$switch_remote_connection;
?? OLDTITLE ??
MODEND jmm$switch_remote_connection;
