?? RIGHT := 110 ??
?? TITLE := 'NOS/VE Device Manager: Get server fmd ' ??
MODULE dmm$get_server_fmd;

{ PURPOSE:
{   This client module serves to act as an interface between File Manager
{   and the server mainframe when getting FMD for a file on that mainframe.

?? NEWTITLE := '   Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dfe$error_condition_codes
*copyc dft$server_descriptor
*copyc dmt$error_condition_codes
*copyc dmt$stored_fmd
*copyc dmt$stored_fmd_size
*copyc gft$system_file_identifier
*copyc ost$status
?? POP ??
*copyc dfp$fetch_served_family_info
*copyc dfp$send_remote_procedure_call
*copyc dfp$set_invalid_family_index
*copyc dfv$served_family_table_root
*copyc dfp$get_served_file_desc_p
*copyc dmp$get_stored_fmd
*copyc dmp$get_stored_fmd_size
*copyc gfp$get_fde_p
*copyc i#move
*copyc jmp$system_job
*copyc osp$enforce_exception_policies
*copyc osp$file_access_condition
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$set_status_from_condition
*copyc osv$initial_exception_context
?? TITLE := '  Client: [XDCL, #GATE] dmp$get_server_fmd', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$get_server_fmd
    (    sfid: gft$system_file_identifier;
     VAR stored_fmd: dmt$stored_fmd;
     VAR stored_fmd_size: dmt$stored_fmd_size;
     VAR status: ost$status);

?? NEWTITLE := 'dfp$remote_procedure_call_ch', EJECT ??

{ PURPOSE:
{   This procedure is a condition handler established to call a routine to clear the assignment of a task
{   services queue_entry if a task aborts with a queue_entry assigned to it.  The queue_entry must be clear
{   before the task can safely exit.

    PROCEDURE dfp$remote_procedure_call_ch
      (    condition: pmt$condition;
           cond_desc: ^pmt$condition_information;
           save: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      dfp$ch_cleanup;
      osp$set_status_from_condition (dfc$file_server_id, condition, save, status, handler_status);
      EXIT dmp$get_server_fmd;

    PROCEND dfp$remote_procedure_call_ch;
*block
*copyc dfp$begin_ch_remote_proc_call
*copyc dfp$end_ch_remote_proc_call
*blockend
?? OLDTITLE, EJECT ??
    VAR
      context: ^ost$ecp_exception_context,
      family: ost$family_name,
      local_status: ost$status,
      p_fde: gft$file_desc_entry_p,
      p_queue_interface_table: dft$p_queue_interface_table,
      p_receive_data: dft$p_receive_data,
      p_receive_parameters: dft$p_receive_parameters,
      p_remote_sfid: ^gft$system_file_identifier,
      p_send_data: dft$p_send_data,
      p_send_parameters: dft$p_send_parameters,
      p_served_family_entry: ^dft$served_family_table_entry,
      p_server_descriptor: dft$server_descriptor_p,
      queue_entry_location: dft$rpc_queue_entry_location,
      queue_index: dft$queue_index,
      remote_sfid: gft$system_file_identifier,
      served_family_table_index: dft$served_family_table_index,
      server_location: dft$server_location,
      server_mainframe_id: pmt$binary_mainframe_id,
      valid_index: boolean,
      valid_sfid: boolean;

    status.normal := TRUE;
    context := NIL;
    gfp$get_fde_p (sfid, p_fde);
    IF p_fde = NIL THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$illegal_use_of_sfid,
            ' invalid sfid - dmp$get_server_fmd.', status);
      RETURN;
    IFEND;
    dfp$get_served_file_desc_p (p_fde, p_server_descriptor);

    REPEAT
      IF (p_server_descriptor^.header.file_state = dfc$awaiting_recovery) THEN
        { the remote sfid is not usable
        #SPOIL (p_server_descriptor^.header.file_state);
        IF context = NIL THEN
          PUSH context;
          context^ := osv$initial_exception_context;
        IFEND;
        osp$set_status_condition (dfe$server_not_active, context^.condition_status);
        osp$enforce_exception_policies (context^);
        status := context^.condition_status;
      IFEND;
    UNTIL status.normal OR (NOT osp$file_access_condition (status)) OR (NOT context^.wait);

    IF (p_server_descriptor^.header.file_state = dfc$terminated) THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$server_has_terminated, '', status);
      RETURN;
    IFEND;

    served_family_table_index := p_server_descriptor^.header.served_family_table_index;
    remote_sfid := p_server_descriptor^.header.remote_sfid;

    dfp$fetch_served_family_info (served_family_table_index, family, server_mainframe_id,
          p_queue_interface_table, queue_index, valid_index);
    IF NOT valid_index THEN
      dfp$set_invalid_family_index (served_family_table_index, ' invalid index dfp$set_seg_eoi ', status);
      RETURN;
    IFEND;

    p_served_family_entry := ^dfv$served_family_table_root.
          p_family_list_pointer_array^ [p_server_descriptor^.header.served_family_table_index.pointers_index].
          p_served_family_list^ [p_server_descriptor^.header.served_family_table_index.family_list_index];

    IF (p_server_descriptor^.header.server_lifetime <> p_served_family_entry^.server_lifetime) OR
          (p_server_descriptor^.header.file_state = dfc$terminated) THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$server_has_terminated, '', status);
      RETURN;
    IFEND;
    server_location.server_location_selector := dfc$served_family_table_index;
    server_location.served_family_table_index := served_family_table_index;

  /wait_for_active/
    REPEAT
      dfp$begin_ch_remote_proc_call (server_location, {send_if_deactivated=} FALSE, queue_entry_location,
            p_send_parameters, p_send_data, status);
      IF NOT  status.normal THEN
        #SPOIL (p_served_family_entry^.server_state);
        CASE p_served_family_entry^.server_state OF
        = dfc$active =
          CYCLE /wait_for_active/;
        = dfc$terminated =
          osp$set_status_condition (dfe$server_has_terminated, status);
        = dfc$deactivated, dfc$inactive, dfc$awaiting_recovery =
          IF context = NIL THEN
            PUSH context;
            context^ := osv$initial_exception_context;
          IFEND;
          context^.condition_status := status;
          osp$enforce_exception_policies (context^);
          status := context^.condition_status;
        ELSE
        CASEND;

      IFEND;
    UNTIL status.normal OR (NOT osp$file_access_condition (status)) OR (NOT context^.wait);

    NEXT p_remote_sfid IN p_send_parameters;
    p_remote_sfid^ := remote_sfid;

    dfp$send_remote_procedure_call (queue_entry_location, dfc$get_server_fmd, #SIZE (p_remote_sfid^), 0,
          p_receive_parameters, p_receive_data, status);

    IF status.normal THEN
      IF p_receive_data = NIL THEN
        stored_fmd_size := #SIZE (p_receive_parameters^);
        IF #SIZE (stored_fmd) < stored_fmd_size THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_too_small,
                'FMD too small - dmp$get_server_fmd.', status);
        ELSE
          i#move (p_receive_parameters, ^stored_fmd, stored_fmd_size);
        IFEND;
      ELSE { Fmd to big to fit in buffer, must be in data.
        stored_fmd_size := #SIZE (p_receive_data^);
        IF #SIZE (stored_fmd) < stored_fmd_size THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_too_small,
                'FMD too small - dmp$get_server_fmd.', status);
        ELSE
          i#move (p_receive_data, ^stored_fmd, stored_fmd_size);
        IFEND;
      IFEND;
    IFEND;
    dfp$end_ch_remote_proc_call (queue_entry_location, local_status);

  PROCEND dmp$get_server_fmd;
?? TITLE := '  Server: [XDCL, #GATE] dmp$server_get_fmd  ', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$server_get_fmd
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      fmd_size: dmt$stored_fmd_size,
      p_fmd: ^dmt$stored_fmd,
      p_sfid: ^gft$system_file_identifier;

    NEXT p_sfid IN p_param_received_from_client;
    dmp$get_stored_fmd_size (p_sfid^, fmd_size, status);
    IF status.normal THEN
      IF fmd_size <= #SIZE (p_send_to_client_params^) THEN
        NEXT p_fmd: [[REP fmd_size OF cell]] IN p_send_to_client_params;
        data_size_to_send_to_client := 0;
        send_parameters_length := fmd_size;
      ELSEIF fmd_size <= #SIZE (p_data_to_client^) THEN
        send_parameters_length := 0;
        data_size_to_send_to_client := fmd_size;
        NEXT p_fmd: [[REP fmd_size OF cell]] IN p_data_to_client;
      ELSE { Give up if its bigger than the data area.
          osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_too_small,
           'FMD too small - dmp$server_get_fmd.', status);
        RETURN;
      IFEND;
      dmp$get_stored_fmd (p_sfid^, p_fmd^, status);
    IFEND;
  PROCEND dmp$server_get_fmd;
?? OLDTITLE, OLDTITLE ??
MODEND dmm$get_server_fmd;
