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

{ Purpose: This module contains the file server interfaces for use with the
{          remote procedure call mechanism for transporting large amount
{          of data from the client to the server.
{
{ Notes:   Module dfm$rpc_segment_transport contains the code for
{          moving large amounts of data from the server to the client.
{
{ Design: 1.  On the client the user tells how much of a file to send to
{             to the server.
{         2.  On the server a transient segment is created.
{         3.  The client makes repeated calls to send the user file.
{             The data is transferred from the user file to
{             to the data area on the client.  On the server the data is
{             transfered from the wired area to the transient segment at the
{             desired offset.
{         4.  The user request on the server obtains a pointer to the
{             transient segment and uses the segment.  The user request
{             on the server deletes the transient segment.
{             This is why these requests can
{             currently only be associated with NON restartable requests.
{
?? 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$send_client_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#build_adaptable_seq_pointer
*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_client_rpc_segment: [XDCL, oss$task_private] ^SEQ ( * ) := NIL;

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

*copyc dfh$delete_client_rpc_segment
  PROCEDURE [XDCL, #GATE] dfp$delete_client_rpc_segment;

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

    osp$verify_system_privilege;
    IF dfv$p_client_rpc_segment <> NIL THEN
      segment_pointer.kind := mmc$sequence_pointer;
      segment_pointer.seq_pointer := dfv$p_client_rpc_segment;
      mmp$delete_segment (segment_pointer, { Validation ring number = } 2, status);
      dfv$p_client_rpc_segment := NIL;
    IFEND;
  PROCEND dfp$delete_client_rpc_segment;

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

*copyc dfh$receive_client_rpc_segment

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

    #KEYPOINT (osk$entry, 0, dfk$receive_client_rpc_segment);
    osp$verify_system_privilege;
    p_seq := dfv$p_client_rpc_segment;
    status.normal := TRUE;
    IF dfv$p_client_rpc_segment = NIL THEN
      osp$set_status_condition (dfe$no_segment_reserved, status);
    IFEND;
    #KEYPOINT (osk$exit, 0, dfk$receive_client_rpc_segment);
  PROCEND dfp$receive_client_rpc_segment;

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

{
{    This procedure is the server side of the dfp$send_client_rpc_segment
{ remote procedure call.  This procedure merely moves the requested data from
{ the server wired data area to the transient segment.  The user must call
{ dfp$receive_client_rpc_segment to obtain the pointer to the transient
{ segment.
{

  PROCEDURE [XDCL] dfp$receive_part_client_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$send_client_rpc_segment,
      ring_attribute: array [1 .. 1] of mmt$attribute_descriptor,
      segment_pointer: mmt$segment_pointer;

    status.normal := TRUE;
    params_size_to_send_to_client := 0;
    data_size_to_send_to_client := 0;
    NEXT p_input_parameters IN p_params_received_from_client;

    IF dfv$p_client_rpc_segment = NIL THEN
      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 NOT status.normal THEN
        RETURN;
      IFEND;
      mmp$set_access_selections (segment_pointer.seq_pointer, mmc$as_sequential, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      i#build_adaptable_seq_pointer (#RING (segment_pointer.seq_pointer),
            #SEGMENT (segment_pointer.seq_pointer), { Offset } 0,
            (p_input_parameters^.starting_offset + p_input_parameters^.send_size), { Next } 0,
            dfv$p_client_rpc_segment);
    IFEND;

    IF (p_input_parameters^.starting_offset + p_input_parameters^.send_size) >
          #SIZE (dfv$p_client_rpc_segment^) THEN
      { The size of the sequence pointer contains the highest offset written.
      i#build_adaptable_seq_pointer (#RING (dfv$p_client_rpc_segment), #SEGMENT (dfv$p_client_rpc_segment),
            { Offset } 0, (p_input_parameters^.starting_offset + p_input_parameters^.send_size), { Next } 0,
            dfv$p_client_rpc_segment);
    IFEND;
    i#move (p_data_received_from_client, #ADDRESS (#RING (dfv$p_client_rpc_segment),
          #SEGMENT (dfv$p_client_rpc_segment), p_input_parameters^.starting_offset),
          p_input_parameters^.send_size);
  PROCEND dfp$receive_part_client_segment;

?? TITLE := '  Client: [XDCL, #GATE] dfp$send_client_rpc_segment ', EJECT ??

*copyc dfh$send_client_rpc_segment

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

    VAR
      current_server_offset: ost$segment_length,
      local_p_client_segment: ^SEQ ( * ),
      p_copy_data: ^SEQ ( * ),
      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$send_client_rpc_segment,
      queue_entry_loc_int: dft$rpc_queue_entry_loc_int,
      remaining_data: ost$segment_length;

    #KEYPOINT (osk$entry, 0, dfk$send_client_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$SEND_CLIENT_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;

    /send_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^.send_size := dfc$maximum_user_data_area;
        ELSE
          p_server_parameters^.send_size := remaining_data;
        IFEND;

       { Move the data from the user's segment to rpc data area.
        NEXT p_copy_data: [[REP p_server_parameters^.send_size OF cell]] IN local_p_client_segment;
        IF p_copy_data = NIL THEN
          osp$set_status_condition (dfe$info_full, status);
          EXIT /send_all_data/;
        IFEND;
        i#move (p_copy_data, p_cpu_queue_entry^.p_send_data, p_server_parameters^.send_size);

        dfp$send_remote_procedure_call (queue_entry_location, dfc$send_client_rpc_segment,
              #SIZE (p_server_parameters^), p_server_parameters^.send_size, p_receive_from_server_params,
              p_receive_data, status);
        IF NOT status.normal THEN
          EXIT /send_all_data/;
        IFEND;

        { Now compute the next area of the server segment.

        remaining_data := remaining_data - p_server_parameters^.send_size;
        current_server_offset := current_server_offset + p_server_parameters^.send_size;
      WHILEND /send_all_data/;
    IFEND;
    #KEYPOINT (osk$exit, 0, dfk$send_client_rpc_segment);
  PROCEND dfp$send_client_rpc_segment;

MODEND dfm$rpc_client_segment_transprt;

