?? RIGHT := 110 ??
?? NEWTITLE := ' NOS/VE File Server : rpc_segment_transport', EJECT ??
MODULE dfm$rpc_segment_transport;

{ Purpose: This module contains the file server interfaces for use with the
{          remote procedure call mechanism for transporting large amount
{          of data from the server to the client.
{
{ Design:
{         1.  On the server a transient segment is created.
{         2.  The client makes repeated calls to obtain the segment.
{             The data is transferred from the server wired data area
{             to the user's sequence.
{         3.  The server deletes the transient segment on the next
{              remote procedure call received.

?? NEWTITLE := 'Global Declarations Referenced by this Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dfd$request_package
*copyc dfe$error_condition_codes
*copyc dfk$keypoints
*copyc dft$procedure_address_ordinal
*copyc dft$rpc_queue_entry_loc_int
*copyc dft$receive_server_rpc_segment
*copyc dft$rpc_buffer_header
*copyc dft$rpc_parameters
*copyc oss$task_private
*copyc ost$status
?? POP ??
*copyc dfp$convert_queue_entry_loc
*copyc dfp$fetch_queue_entry
*copyc dfp$send_remote_procedure_call
*copyc dfp$validate_queue_entry_loc
*copyc i#move
*copyc mmp$create_segment
*copyc mmp$delete_segment
*copyc mmp$set_access_selections
*copyc osp$set_status_condition
*copyc osp$verify_system_privilege
?? TITLE := 'Global Declarations Declared by this Module', EJECT ??

  VAR
    dfv$p_server_rpc_segment: [XDCL, oss$task_private] ^SEQ ( * ) := NIL;

?? TITLE := ' Server: [INLINE, XDCL]  dfp$delete_server_rpc_segment', EJECT ??

{   This procedure deleted the server rpc segment if one exists.
{ This allows freeing extra pages associated with the segment.

  PROCEDURE [INLINE, XDCL] dfp$delete_server_rpc_segment;

    VAR
      segment_pointer: mmt$segment_pointer,
      status: ost$status;

    IF dfv$p_server_rpc_segment <> NIL THEN
      segment_pointer.kind := mmc$sequence_pointer;
      segment_pointer.seq_pointer := dfv$p_server_rpc_segment;
      mmp$delete_segment (segment_pointer, { Validation ring number = } 2, status);
      dfv$p_server_rpc_segment := NIL;
    IFEND;
  PROCEND dfp$delete_server_rpc_segment;
?? TITLE := '  Client: [XDCL, #GATE] dfp$receive_server_rpc_segment ', EJECT ??

*copyc dfh$receive_server_rpc_segment

  PROCEDURE [XDCL, #GATE] dfp$receive_server_rpc_segment
    (    queue_entry_location: dft$rpc_queue_entry_location;
         server_segment_offset: ost$segment_length;
         request_size: ost$segment_length;
     VAR p_client_segment: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      current_server_offset: ost$segment_length,
      local_p_client_segment: ^SEQ ( * ),
      p_copy_data: dft$p_receive_data,
      p_cpu_queue_entry: ^dft$cpu_queue_entry,
      p_driver_queue_entry: ^dft$driver_queue_entry,
      p_queue_interface_table: dft$p_queue_interface_table,
      p_receive_data: dft$p_receive_data,
      p_receive_from_server_params: dft$p_receive_parameters,
      p_send_buffer_header: ^dft$buffer_header,
      p_send_rpc_buffer_header: ^dft$rpc_buffer_header,
      p_server_parameters: ^dft$receive_server_rpc_segment,
      queue_entry_loc_int: dft$rpc_queue_entry_loc_int,
      remaining_data: ost$segment_length;

    #KEYPOINT (osk$entry, 0, dfk$receive_server_rpc_segment);
    osp$verify_system_privilege;

{ Obtain the pointers to the remote procedure call buffer areas.

    dfp$convert_qel_ext_to_int (queue_entry_location, queue_entry_loc_int);
    dfp$validate_queue_entry_loc (queue_entry_loc_int, 'DFP$RECEIVE_SERVER_RPC_SEGMENT',
          p_queue_interface_table, status);
    IF status.normal THEN
      local_p_client_segment := p_client_segment;
      dfp$fetch_queue_entry (p_queue_interface_table, queue_entry_loc_int.queue_index,
            queue_entry_loc_int.queue_entry_index, p_driver_queue_entry, p_cpu_queue_entry);
      RESET p_cpu_queue_entry^.p_send_buffer;
      NEXT p_send_buffer_header IN p_cpu_queue_entry^.p_send_buffer;
      NEXT p_send_rpc_buffer_header IN p_cpu_queue_entry^.p_send_buffer;
      NEXT p_server_parameters IN p_cpu_queue_entry^.p_send_buffer;

      current_server_offset := server_segment_offset;
      remaining_data := request_size;

    /receive_all_data/
      WHILE remaining_data > 0 DO
        p_server_parameters^.starting_offset := current_server_offset;
        IF remaining_data > dfc$maximum_user_data_area THEN
          p_server_parameters^.receive_size := dfc$maximum_user_data_area;
        ELSE
          p_server_parameters^.receive_size := remaining_data;
        IFEND;
        dfp$send_remote_procedure_call (queue_entry_location, dfc$receive_server_rpc_segment,
              #SIZE (p_server_parameters^), { Send data size = } 0, p_receive_from_server_params,
              p_receive_data, status);
        IF NOT status.normal THEN
          EXIT /receive_all_data/;
        IFEND;

{ Move the data to the user's segment.

        NEXT p_copy_data: [[REP p_server_parameters^.receive_size OF cell]] IN local_p_client_segment;
        IF p_copy_data = NIL THEN
          osp$set_status_condition (dfe$info_full, status);
          EXIT /receive_all_data/;
        IFEND;
        p_copy_data^ := p_receive_data^;

{ Now compute the next area of the server segment.

        remaining_data := remaining_data - p_server_parameters^.receive_size;
        current_server_offset := current_server_offset + p_server_parameters^.receive_size;
      WHILEND /receive_all_data/;
    IFEND;
    IF status.normal THEN
      p_client_segment := local_p_client_segment;
    IFEND;
    #KEYPOINT (osk$exit, 0, dfk$receive_server_rpc_segment);
  PROCEND dfp$receive_server_rpc_segment;

?? TITLE := '  Server: [XDCL, #GATE] dfp$reserve_server_rpc_segment', EJECT ??

*copyc dfh$reserve_server_rpc_segment

  PROCEDURE [XDCL, #GATE] dfp$reserve_server_rpc_segment
    (VAR p_seq: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      ring_attribute: array [1 .. 1] of mmt$attribute_descriptor,
      segment_pointer: mmt$segment_pointer;

    #KEYPOINT (osk$entry, 0, dfk$reserve_server_rpc_segment);
    osp$verify_system_privilege;
    dfp$delete_server_rpc_segment;
    ring_attribute [1].keyword := mmc$kw_ring_numbers;
    ring_attribute [1].r1 := 3;
    ring_attribute [1].r2 := 3;
    mmp$create_segment (^ring_attribute, mmc$sequence_pointer, { Ring} 2, segment_pointer, status);
    IF status.normal THEN
      mmp$set_access_selections (segment_pointer.seq_pointer, mmc$as_sequential, status);
    IFEND;
    IF status.normal THEN
      dfv$p_server_rpc_segment := segment_pointer.seq_pointer;
      p_seq := dfv$p_server_rpc_segment;
    IFEND;

    #KEYPOINT (osk$exit, 0, dfk$reserve_server_rpc_segment);
  PROCEND dfp$reserve_server_rpc_segment;

?? TITLE := '  Server: dfp$send_server_rpc_segment ', EJECT ??

{
{   This procedure is the server side of the dfp$receive_server_rpc_segment
{ request.   This procedure merely removes the requested data to the server
{ wired data area.
{

  PROCEDURE [XDCL] dfp$send_server_rpc_segment
    (VAR p_params_received_from_client {Input}: dft$p_receive_parameters;
     VAR p_data_received_from_client {Input}: dft$p_receive_data;
     VAR p_params_to_send_to_client {^Output}: dft$p_send_parameters;
     VAR p_data_to_send_to_client {^Output}: dft$p_send_data;
     VAR params_size_to_send_to_client: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      p_input_parameters: ^dft$receive_server_rpc_segment;

    status.normal := TRUE;
    params_size_to_send_to_client := 0;
    data_size_to_send_to_client := 0;
    IF dfv$p_server_rpc_segment = NIL THEN
      osp$set_status_condition (dfe$no_segment_reserved, status);
      RETURN;
    IFEND;

    NEXT p_input_parameters IN p_params_received_from_client;

    i#move (#ADDRESS (#RING (dfv$p_server_rpc_segment), #SEGMENT (dfv$p_server_rpc_segment),
          p_input_parameters^.starting_offset), p_data_to_send_to_client, p_input_parameters^.receive_size);
    data_size_to_send_to_client := p_input_parameters^.receive_size;

  PROCEND dfp$send_server_rpc_segment;


MODEND dfm$rpc_segment_transport;
