コード例 #1
0
ファイル: cfdp_lib.c プロジェクト: Rileybrains/BARCoMmS
/*=r=*************************************************************************/
static MACHINE *m__start_new_sender_machine (REQUEST put_request)
     /* WHAT IT DOES:  Given a User Request (presumably a Put Request)
      *   it attempts to open a comm-link to the CFDP partner,
      *   allocate a state machine slot, and initialize the state machine.
      *   If successful, returns a pointer to the new state machine;
      *   otherwise, returns NULL.
      */
{
  MACHINE           *m = NULL;
  ID                 partner_id;
  /*------------------------------------------------------------*/

  /* Attempt to open a comm-link to the CFDP partner entity.
   * (The Put Request tells us who our partner is)
   */
  partner_id = put_request.info.put.dest_id;
  if (!pdu_output__open (mib__get_my_id(), partner_id))
    e_msg__ ("cfdp_engine: discarded incoming Put Request - "
             "(unable to communicate with node '%s').\n",
             cfdp_id_as_string (partner_id));

  /* If successful, attempt to allocate a slot in the machine-list */
  else if ((m = machine_list__allocate_slot ()) == NULL)
    e_msg__ ("cfdp_engine: discarded incoming Put Request - "
             "can't exceed %lu transactions\n",
             MAX_CONCURRENT_TRANSACTIONS);

  /* If successful, initialize the state machine's MACHINE structure */
  else
    aaa__initialize (m, &put_request, NULL);

  return (m);
}
コード例 #2
0
ファイル: cfdp_lib.c プロジェクト: Rileybrains/BARCoMmS
/*=r=*************************************************************************/
static MACHINE *m__restart_old_sender_machine (HDR hdr)
     /* WHAT IT DOES:  Given a PDU-header (that is presumably a Finished
      *   PDU), it attempts to open a comm-link to the CFDP partner,
      *   allocate a state machine slot, and initialize the state machine.
      *   If successful, returns a pointer to the new state machine;
      *   otherwise, returns NULL.
      */
{
  MACHINE           *m = NULL;
  ID                 partner_id;
  /*------------------------------------------------------------*/

  /* Attempt to open a comm-link to the CFDP partner entity.  Since we were 
   * (and are) the sender, our partner is the destination of this transaction.
   */
  partner_id = hdr.dest_id;   /* We're the sender, partner is dest-id */
  if (!pdu_output__open (mib__get_my_id(), partner_id))
    e_msg__ ("cfdp_engine: discarded incoming Fin PDU - "
             "unable to communicate with node '%s'\n",
             cfdp_id_as_string (partner_id));
  
  /* If successful, attempt to allocate a slot in the machine-list */
  else if ((m = machine_list__allocate_slot ()) == NULL)
    e_msg__ ("cfdp_engine: discarded incoming Fin PDU - "
             "can't exceed %lu transactions\n",
             MAX_CONCURRENT_TRANSACTIONS);

  /* If successful, initialize the state machine's MACHINE structure */
  else
    aaa__initialize (m, NULL, &hdr);

  return (m);
}
コード例 #3
0
ファイル: cfdp_lib.c プロジェクト: Rileybrains/BARCoMmS
/*=r=*************************************************************************/
static MACHINE *m__start_new_receiver_machine (HDR hdr)
     /* WHAT IT DOES:  Given a PDU-header (presumably Metadata/Filedata/EOF
      *   PDU), it attempts to open a comm-link to the CFDP partner,
      *   allocate a state machine slot, and initialize the state machine.
      *   If successful, returns a pointer to the new state machine;
      *   otherwise, returns NULL.
      */
{
  MACHINE           *m = NULL;
  ID                 partner_id;
  /*------------------------------------------------------------*/

  /* Attempt to open a comm-link to the CFDP partner entity.  Since we are
   * the receiver, our partner is the source of this transaction.
   */
  partner_id = hdr.trans.source_id;
  if (!pdu_output__open (mib__get_my_id(), partner_id))
    e_msg__ ("cfdp_engine: discarded incoming PDU "
             "(unable to communicate with node '%s').\n",
             cfdp_id_as_string (partner_id));

  /* If successful, attempt to allocate a slot in the machine-list */
  else if ((m = machine_list__allocate_slot ()) == NULL)
    e_msg__ ("cfdp_engine: discarded incoming PDU - "
             "can't exceed %lu transactions\n",
             MAX_CONCURRENT_TRANSACTIONS);

  /* If successful, initialize the state machine's MACHINE structure */
  else
    aaa__initialize (m, NULL, &hdr);

  return (m);
}
コード例 #4
0
ファイル: cfdp_lib.c プロジェクト: Rileybrains/BARCoMmS
/*=r=************************************************************************/
static void m__state_table (MACHINE *m, int event, 
                            PDU_AS_STRUCT *pdu_ptr, REQUEST *req_ptr)
     /* WHAT IT DOES:  Calls the appropriate state table routine (based
      *   upon the role that we are to play - e.g. Class 2 Sender).
      *   The given machine, event, PDU, and Request are all passed along 
      *   to the state table routine.  
      * NOTE:  Also enforces the restriction that the state tables are
      *   not re-entrant for any particular state machine.
      * NOTE:  If the given state machine finishes, it is deleted.
      */
{
  /*------------------------------------------------------------*/
  
  /* Avoid re-entering the engine core for any particular transaction */ 
  if (m->is_user_inside_the_engine_core)
    {
      w_msg__ ("cfdp_engine: user attempt to re-enter state tables denied.\n");
      return;
    }
  m->is_user_inside_the_engine_core = YES;
  
  /* Run the given state machine in the appropriate state table routine */
  if (m->publik.role == S_1)
    s1__state_table (m, event, pdu_ptr, req_ptr);
  else if (m->publik.role == S_2)
    s2__state_table (m, event, pdu_ptr, req_ptr);
  else if (m->publik.role == R_1)
    r1__state_table (m, event, pdu_ptr, req_ptr);
  else if (m->publik.role == R_2)
    r2__state_table (m, event, pdu_ptr, req_ptr);
  else
    e_msg__ ("cfdp_engine: unable to run state table; unknown Role.\n");

  m->is_user_inside_the_engine_core = NO;

  /* If the state machine has finished, delete it */
  if (m->has_this_state_machine_finished)
    {
      /* Engine-wide bookeeping */
      misc__update_summary_statistics (m);
      misc__set_last_condition_code (m->publik.condition_code);
      misc__set_last_trans_abandoned (m->publik.abandoned);
      /* Let the engine user know what has happened */
      indication__ (IND_MACHINE_DEALLOCATED, &(m->publik));
      /* Delete the state machine (give up the slot associated with it) */
      if (!machine_list__deallocate_slot (m))
        e_msg__ ("cfdp_engine: "
                 "attempt to delete completed state machine failed.\n");
    }
}
コード例 #5
0
/*=r=************************************************************************/
static void m__fault (const TRANS_STATUS *info)
   {
   /*------------------------------------------------------------*/
     e_msg__ (":::Fault  trans %s, fault='%s'.\n",
              cfdp_trans_as_string (info->trans),
              cfdp_condition_as_string (info->condition_code));
   }
コード例 #6
0
ファイル: r2.c プロジェクト: Rileybrains/BARCoMmS
/*=r=*************************************************************************/
static boolean m__fault_handler (MACHINE *m, CONDITION_CODE fault)
/* WHAT IT DOES:  Responds to the given fault in accordance with the
 *   engine user's setting of "response to fault" (in the MIB).
 * RETURN STATUS:  If '1', the response to the given fault was 'ignore', 
 *   and the calling state table routine may continue with whatever it
 *   was doing.  If '0', the response was suspend, cancel, or abandon
 *   (and the calling state table routine should return immediately).
 */
{
  boolean          ok_for_caller_to_continue;
  /*------------------------------------------------------------*/

  /* Save the fault-type */
  m->publik.condition_code = fault;
  /* 'Indication' callback allows engine user to respond to events */
  indication__ (IND_FAULT, &(m->publik)); 

  /* Unless the user has configured to 'ignore' this fault, the calling
   * routine should not continue with what it was doing.
   */
  ok_for_caller_to_continue = NO;

  if (mib__response (fault) == RESPONSE_CANCEL) 
    { 
      m->have_we_initiated_a_cancel = YES; 
      aaa__cancel_locally (m); 
      m__ask_partner_to_cancel (m); 
      m__move_to_state_s2 (m); 
    } 

  else if (mib__response (fault) == RESPONSE_SUSPEND) 
    aaa__notice_of_suspension (m);

  else if (mib__response (fault) == RESPONSE_IGNORE) 
    ok_for_caller_to_continue = YES;

  else if (mib__response (fault) == RESPONSE_ABANDON) 
    aaa__abandon_this_transaction (m); 

  else 
    e_msg__ ("cfdp_engine: problem with the Fault mechanism in <R2>.\n");
  
  return (ok_for_caller_to_continue);
}
コード例 #7
0
ファイル: s1.c プロジェクト: Rileybrains/BARCoMmS
/*=r=*************************************************************************/
static void m__release_a_metadata_pdu (MACHINE *m)
     /* WHAT IT DOES:  Outputs a Metadata PDU, 
      *   and performs the actions required after the PDU is released.
      */
{
  TRANS_STATUS      *mp = &(m->publik);   /* useful shorthand */
  /*------------------------------------------------------------*/

  /*----------------*/
  /* Output the PDU */
  /*----------------*/

  aaa__send_metadata (m->hdr, m->publik.md);
  m->is_outgoing_md_buffered = NO;

  /*----------------------------------------------------*/
  /* Perform actions required after the PDU is released */
  /*----------------------------------------------------*/

  /* 'Indication' callback allows engine user to respond to events */
  indication__ (IND_METADATA_SENT, &(m->publik));

  if (mp->md.file_transfer && !m->is_external_xfer_open)
    /* This is the typical case -- we have been asked to send a file,
     * and the engine user is letting us build all the PDUs.
     */
    {
      if (!aaa__open_source_file (m))
        {
          e_msg__ ("cfdp_engine: unable to open source file '%s'.\n",
                   m->publik.md.source_file_name);
          if (!m__fault_handler (m, FILESTORE_REJECTION))
            return;
        }
      if (!aaa__is_file_structure_valid (m))
        {
          if (!m__fault_handler (m, INVALID_FILE_STRUCTURE))
            return;
        }
      
      /* Queue all the Filedata for metered released */
      nak__set_end_of_scope (&(m->nak), mp->md.file_size);
    }
  
  else if (mp->md.file_transfer && m->is_external_xfer_open)
    /* Special case:  Although a file is to be transferred, we are
     * not supposed to send Filedata PDUs (unless retransmissions
     * are necessary).  The engine user will send the initial set
     * of Filedata PDUs.
     * So, just chill until the engine user finishes sending the file.
     */
    ;
  
  else
    /* No file transfer, so initiate transfer of EOF */
    {
      /* Build and queue an EOF Pdu */
      m->eof = aaa__build_eof (mp->condition_code, 0, 0);
      m->is_outgoing_eof_buffered = YES;
    }
}
コード例 #8
0
ファイル: nak.c プロジェクト: CoreflightModeler/cfs-cfdp
/*=r=************************************************************************/
void nak__data_received (NAK *nak_ptr, u_int_4 begin, u_int_4 end)
     /* ALGORITHM:  The given data-range (begin-end) must fit one of the four 
      *   cases below.  Determine which case applies, and perform the 
      *   corresponding action(s).
      * ASSUMPTION:  The scope always starts at zero.
      */
{
  /*------------------------------------------------------------*/

  /* Validate the given inputs */
  if ((begin < 0) || (end < 0) || (begin > end))
    {
      e_msg__ ("cfdp_engine: Nak module ignored receipt of Filedata "
               "with invalid range (%lu-%lu)\n",
               begin, end);
      return;
    }
  else
    {
      /* If configured to do so, output a debug message */
      if (cfdp_is_message_class_enabled (CFDP_MSG_DEBUG_NAK))
        d_msg__ ("Valid_filedata_received: %lu-%lu.\n", begin, end);
    }      
  
  /*--------------------------------------------------------------
   * Case 1 -- the given range is fully within the current scope.
   * Action: the scope doesn't change; just remove the given range
   * from the current gap-list.
   * Example:  scope=0-1000, range=100-200.  
   *--------------------------------------------------------------*/

  if (end <= nak_ptr->end_of_scope)
    m__remove_range_from_list (nak_ptr, begin, end);

  /*------------------------------------------------------------------------
   * Case 2 -- the given range is both inside and outside the current scope.
   * Action:  The scope has to be extended, and the portion of the given
   * range that is within the current scope has to be removed from the
   * current gap-list.
   * Example:  scope=0-1000, range=900-1100.  New scope is 0-1100,
   * and the range 900-1000 is removed from gap-list.
   *------------------------------------------------------------------------*/

  else if ((begin < nak_ptr->end_of_scope) && (end > nak_ptr->end_of_scope))
    {
      m__remove_range_from_list (nak_ptr, begin, nak_ptr->end_of_scope);
      nak_ptr->end_of_scope = end;
    }

  /*-----------------------------------------------------------------
   * Case 3 -- the given range begins at the current scope boundary
   * (i.e. there is no gap between this new data and previously-received
   * data).  
   * Action:  Just extend the current scope.
   * Example:  scope=0-1000, range=1000-1100.  New scope is 0-1100.
   *-----------------------------------------------------------------*/

  else if (begin == nak_ptr->end_of_scope)
    nak_ptr->end_of_scope = end;

  /*----------------------------------------------------------------------
   * Case 4 -- the given range is completely outside the current scope;
   * i.e. there is a gap between the end of any previously-received
   * data and the start of this new data.  
   * Action:  Add the new gap to the list, and extend the current scope.
   * Example:  scope=0-1000, range=1100-1200.  New scope is 0-1200, and
   * a gap from 1000-1100 is added to the gap-list.
   *----------------------------------------------------------------------*/

  else if (begin > nak_ptr->end_of_scope)
    {
      m__add_gap_to_list (nak_ptr, nak_ptr->end_of_scope, begin);
      nak_ptr->end_of_scope = end;
    }
  
  else 
    /* If we got here, then there is a bug in the above code */
    ASSERT__BUG_DETECTED;
}
コード例 #9
0
ファイル: cfdp_lib.c プロジェクト: Rileybrains/BARCoMmS
/*=r=************************************************************************/
boolean cfdp_give_request (const char *request_string)
{
  CFDP_FILE            *fp;
  MACHINE              *m;
  REQUEST               request;
  boolean               successful = YES;
  /*------------------------------------------------------------*/

  REPORT_VERSION_ONCE;

  /*---------------------------------*/
  /* Validate the given User Request */
  /*---------------------------------*/

  if (request_string == NULL)
    {
      e_msg__ ("cfdp_engine: cfdp_give_request: given a null-pointer.\n");
      successful = NO;
    }

  else if (!utils__request_from_string (request_string, &request))
    /* The string does not represent a valid request */
    {
      e_msg__ ("cfdp_engine: request is invalid (%s).\n", request_string);
      successful = NO;
    }

  else if ((request.type == REQ_PUT) &&
           (cfdp_are_these_ids_equal (request.info.put.dest_id, 
                                      mib__get_my_id())))
    /* This Put Request is invalid */
    {
      e_msg__ ("cfdp_engine: Won't allow you to send a file to yourself!\n");
      successful = NO;
    }
  
  /* If the User Request is an "empty" one, just ignore it */
  else if (request.type == REQ_NONE)
    /* No action needed */
    d_msg__ ("cfdp_engine: ignoring an empty User Request.\n");
  

  /*---------------------------------------------------------
   * If the User Request is a Put Request, then create a new 
   * state machine, and pass the Put Request to that machine
   *---------------------------------------------------------*/
  
  else if (request.type == REQ_PUT)
    {
      /* Optimization:  If the source-file doesn't exist, catch it now */
      fp = fopen_callback (request.info.put.source_file_name, "rb");
      if (fp == NULL)
        /* The source-file doesn't exist; no point in trying to transfer it */
        {
          e_msg__ ("cfdp_engine: can't transfer non-existent file (%s).\n",
                   request.info.put.source_file_name);
          successful = NO;
        }
      else
        {
          /* It does exist; close it and let the state machine re-open it */
          fclose_callback (fp);
          /* Start a new state machine */
          if ((m = m__start_new_sender_machine (request)) != NULL)
            /* Fire the state table event associated with a Put Request */
            m__state_table (m, RECEIVED_PUT_REQUEST, NULL, &request);
          else
            successful = NO;
        }
    }
  
  
  /*------------------------------------------------------------------
   * If the User Request applies to *all* transactions, then pass it
   * to all active state machines
   *------------------------------------------------------------------*/
  
  else if (request.type == REQ_REPORT)
    /* Report all active transactions */
    m__give_request_to_all_trans (request.type);
  
  else if (request.type == REQ_FREEZE)
    /* Freeze all active transactions, and any future ones too */
    {
      m__give_request_to_all_trans (request.type);
      misc__freeze_all_partners ();
    }
  
  else if (request.type == REQ_THAW)
    /* Thaw all active transactions, and any future ones too */
    {
      m__give_request_to_all_trans (request.type);
      misc__thaw_all_partners ();
    }
  
  else if (request.type == REQ_ABANDON_ALL_TRANSACTIONS)
    m__give_request_to_all_trans (REQ_ABANDON);
  
  else if (request.type == REQ_CANCEL_ALL_TRANSACTIONS)
    m__give_request_to_all_trans (REQ_CANCEL);
  
  else if (request.type == REQ_SUSPEND_ALL_TRANSACTIONS)
    m__give_request_to_all_trans (REQ_SUSPEND);
  
  else if (request.type == REQ_RESUME_ALL_TRANSACTIONS)
    m__give_request_to_all_trans (REQ_RESUME);
  
  
  /*-----------------------------------------------------------------
   * If the User Request applies to one transaction, then attempt to
   * find an active state machine assigned to that transaction, and
   * pass the Request to that state machine.
   *-----------------------------------------------------------------*/
  
  else if ((request.type == REQ_ABANDON) ||
           (request.type == REQ_CANCEL) ||
           (request.type == REQ_SUSPEND) ||
           (request.type == REQ_RESUME))
    {
      if ((m = machine_list__get_this_trans (request.info.trans)) !=  NULL)
        /* Success (a machine is assigned to this transaction) */
        m__give_request_to_one_trans (m, request.type);
      else
        /* No state machine assigned */
        {
          e_msg__ ("cfdp_engine: ignoring User-Request that references "
                   "unknown transaction (%s).\n",
                   cfdp_trans_as_string (request.info.trans));
          successful = NO;
        }
    }
  
  
  else
    {
      w_msg__ ("cfdp_engine: ignoring unrecognized User-Request (%s).\n",
               request_string);
      successful = NO;
    }
  
  return (successful);
}
コード例 #10
0
ファイル: cfdp_lib.c プロジェクト: Rileybrains/BARCoMmS
/*=r=************************************************************************/
static boolean m__is_pdu_sane (PDU_TYPE pdu_type, ROLE my_role)
     /* WHAT IT DOES:  Returns 1 if it makes sense for a PDU of the given
      *   type to be received by a transaction assigned the given role;
      *   otherwise, returns 0.
      */
{
  boolean         sane;
  /*------------------------------------------------------------*/

  sane = NO;

  if      (pdu_type == _MD_)
    {
      if ((my_role == R_1) || (my_role == R_2))
        sane = YES;
      else
        e_msg__ ("cfdp_engine: PDU rejected - "
                 "Metadata can only come from Sender.\n");
    }

  else if (pdu_type == _FD_)
    {
      if ((my_role == R_1) || (my_role == R_2))
        sane = YES;
      else
        e_msg__ ("cfdp_engine: PDU rejected - "
                 "Filedata can only come from Sender.\n");
    }

  else if (pdu_type == _EOF_)
    {
      if ((my_role == R_1) || (my_role == R_2))
        sane = YES;
      else
        e_msg__ ("cfdp_engine: PDU rejected - "
                 "EOF can only come from Sender.\n");
    }

  else if (pdu_type == _ACK_EOF_)
    {
      if (my_role == S_2)
        sane = YES;
      else
        e_msg__ ("cfdp_engine: PDU rejected - "
                 "Ack-EOF can only come from Class 2 Receiver.\n");
    }

  else if (pdu_type == _NAK_)
    {
      if (my_role == S_2)
        sane = YES;
      else
        e_msg__ ("cfdp_engine: PDU rejected - "
                 "Nak can only come from Class 2 Receiver.\n");
    }

  else if (pdu_type == _FIN_)
    {
      if (my_role == S_2)
        sane = YES;
      else
        e_msg__ ("cfdp_engine: PDU rejected - "
                 "Fin can only come from Class 2 Receiver.\n");
    }

  else if (pdu_type == _ACK_FIN_)
    {
      if (my_role == R_2)
        sane = YES;
      else
        e_msg__ ("cfdp_engine: PDU rejected - "
                 "Ack-Fin can only come from Class 2 Sender.\n");
    }

  else
    e_msg__ ("cfdp_engine: PDU rejected - unrecognized pdu-type.\n");

  return (sane);
}
コード例 #11
0
ファイル: mib.c プロジェクト: Rileybrains/BARCoMmS
/*=r=************************************************************************/
boolean mib__set_parameter (const char *param_in, const char *value_in)
   {
     int                i;
     ID                 id;
     unsigned long int  long_int;
     char               param [MAX_MIB_PARAMETER_LENGTH+1];
     u_int_4            requested_size;
     char               value [MAX_MIB_VALUE_LENGTH+1];
   /*------------------------------------------------------------*/
     INITIALIZE_ONCE;

     /*--------------------------*/
     /* Validate input arguments */
     /*--------------------------*/

     if (strlen(param_in) == 0)
       {
         e_msg__ ("cfdp_engine: can't set MIB parameter; "
                  "no parameter given.\n");
         return (0);
       }
     else if (strlen(param_in) > MAX_MIB_PARAMETER_LENGTH)
       {
         e_msg__ ("cfdp_engine: can't set MIB parameter; "
                  "parameter-string (%s) is too long.\n",
                  param_in);
         return (0);
       }
     else if (strlen(value_in) == 0)
       {
         e_msg__ ("cfdp_engine: can't set MIB parameter; no value given.\n");
         return (0);
       }
     else if (strlen(value_in) > MAX_MIB_PARAMETER_LENGTH)
       {
         e_msg__ ("cfdp_engine: can't set MIB parameter; "
                  "value-string (%s) is too long.\n",
                  value_in);
         return (0);
       }

     COPY (param, m__convert_string_to_uppercase (param_in));
     COPY (value, m__convert_string_to_uppercase (value_in));

     /*-----------------------------------------*/
     /* Compare input with each Local parameter */
     /*-----------------------------------------*/

     if (!strcmp (param, MIB_MY_ID))
       {
         if (cfdp_id_from_string (value, &id))
           {
             m_mib_local.my_id = id;
             i_msg__ ("cfdp_engine: entity-id set to '%s'.\n",
                      cfdp_id_as_string (m_mib_local.my_id));
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set entity-id to illegal value "
                      "(%s).\n",
                      value);
             return (0);
           }
       }

     else if (!strcmp (param, MIB_ISSUE_EOF_RECV))
       {
         if (!strcmp (value, "YES"))
           {
             m_mib_local.issue_eof_recv = YES;
             i_msg__ ("cfdp_engine: 'issue_eof_recv' set to 'yes'.\n");
           }
         else if (!strcmp (value, "NO"))
           {
             m_mib_local.issue_eof_recv = NO;
             i_msg__ ("cfdp_engine: 'issue_eof_recv' set to 'no'.\n");
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'issue_eof_recv'; "
                      "value (%s) must be 'yes' or 'no'.\n",
                      value_in); 
             return (0);
           }
       }

     else if (!strcmp (param, MIB_ISSUE_EOF_SENT))
       {
         if (!strcmp (value, "YES"))
           {
             m_mib_local.issue_eof_sent = YES;
             i_msg__ ("cfdp_engine: 'issue_eof_sent' set to 'yes'.\n");
           }
         else if (!strcmp (value, "NO"))
           {
             m_mib_local.issue_eof_sent = NO;
             i_msg__ ("cfdp_engine: 'issue_eof_sent' set to 'no'.\n");
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'issue_eof_sent'; "
                      "value (%s) must be 'yes' or 'no'.\n",
                      value_in); 
             return (0);
           }
       }

     else if (!strcmp (param, MIB_ISSUE_FILE_SEGMENT_RECV))
       {
         if (!strcmp (value, "YES"))
           {
             m_mib_local.issue_file_segment_recv = YES;
             i_msg__ ("cfdp_engine: 'issue_file_segment_recv' set to 'yes'\n");
           }
         else if (!strcmp (value, "NO"))
           {
             m_mib_local.issue_file_segment_recv = NO;
             i_msg__ ("cfdp_engine: 'issue_file_segment_recv' set to 'no'.\n");
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'issue_file_segment_recv'; "
                      "value (%s) must be 'yes' or 'no'.\n",
                      value_in); 
             return (0);
           }
       }

     else if (!strcmp (param, MIB_ISSUE_FILE_SEGMENT_SENT))
       {
         if (!strcmp (value, "YES"))
           {
             m_mib_local.issue_file_segment_sent = YES;
             i_msg__ ("cfdp_engine: 'issue_file_segment_sent' set to 'yes'\n");
           }
         else if (!strcmp (value, "NO"))
           {
             m_mib_local.issue_file_segment_sent = NO;
             i_msg__ ("cfdp_engine: 'issue_file_segment_sent' set to 'no'.\n");
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'issue_file_segment_sent'; "
                      "value (%s) must be 'yes' or 'no'.\n",
                      value_in); 
             return (0);
           }
       }

     else if (!strcmp (param, MIB_ISSUE_RESUMED))
       {
         if (!strcmp (value, "YES"))
           {
             m_mib_local.issue_resumed = YES;
             i_msg__ ("cfdp_engine: 'issue_resumed' set to 'yes'.\n");
           }
         else if (!strcmp (value, "NO"))
           {
             m_mib_local.issue_resumed = NO;
             i_msg__ ("cfdp_engine: 'issue_resumed' set to 'no'.\n");
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'issue_resumed'; "
                      "value (%s) must be 'yes' or 'no'.\n",
                      value_in); 
             return (0);
           }
       }

     else if (!strcmp (param, MIB_ISSUE_SUSPENDED))
       {
         if (!strcmp (value, "YES"))
           {
             m_mib_local.issue_suspended = YES;
             i_msg__ ("cfdp_engine: 'issue_suspended' set to 'yes'.\n");
           }
         else if (!strcmp (value, "NO"))
           {
             m_mib_local.issue_suspended = NO;
             i_msg__ ("cfdp_engine: 'issue_suspended' set to 'no'.\n");
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'issue_suspended'; "
                      "value (%s) must be 'yes' or 'no'.\n",
                      value_in); 
             return (0);
           }
       }

     else if (!strcmp (param, MIB_ISSUE_TRANSACTION_FINISHED))
       {
         if (!strcmp (value, "YES"))
           {
             m_mib_local.issue_transaction_finished = YES;
             i_msg__ ("cfdp_engine: 'issue_transaction_finished' "
                      "set to 'yes'.\n");
           }
         else if (!strcmp (value, "NO"))
           {
             m_mib_local.issue_transaction_finished = NO;
             i_msg__ ("cfdp_engine: 'issue_transaction_finished' "
                      "set to 'no'.\n");
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'issue_transaction_finished'; "
                      "value (%s) must be 'yes' or 'no'.\n",
                      value_in); 
             return (0);
           }
       }

     else if (!strcmp (param, MIB_RESPONSE_TO_FAULT))
       {
         if ((!strcmp (value, "IGNORE")) ||
             (!strcmp (value, "SUSPEND")) ||
             (!strcmp (value, "CANCEL")) ||
             (!strcmp (value, "ABANDON")))
           {
             for (i=0; i<NUMBER_OF_CONDITION_CODES; i++)
               /* WARNING:  This library uses the same response for all faults.
                *   The CFDP protocol allows the user to choose a different
                *   response to each fault.  So, this library is not fully
                *   compliant with the CFDP protocol.  However, the library
                *   developer considers this to be a practical shortcut that
                *   simplifies things.
                */
               m_mib_local.response[i] = m__string_as_response (value);
             i_msg__ ("cfdp_engine: 'response_to_fault' set to '%s'.\n",
                      cfdp_response_as_string (m_mib_local.response[0]));
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'response_to_fault'; "
                      "value (%s) is invalid.\n",
                      value_in);
             return (0);
           }
       }

     /*------------------------------------------*/
     /* Compare input with each Remote parameter */
     /*------------------------------------------*/

     else if (!strcmp (param, MIB_ACK_LIMIT))
       {
         if (!isdigit ((int) value_in[0]))
           {
             e_msg__ ("cfdp_engine: can't set 'ack_limit'; "
                      "value (%s) must be numeric.\n",
                      value_in);
             return (0);
           }
         sscanf (value, "%lu", &long_int);
         m_mib_remote_default.ack_limit = (u_int_4) long_int;
         i_msg__ ("cfdp_engine: 'ack_limit' set to '%lu'.\n",
                  m_mib_remote_default.ack_limit);
       }

     else if (!strcmp (param, MIB_ACK_TIMEOUT))
       {
         if (!isdigit ((int) value_in[0]))
           {
             e_msg__ ("cfdp_engine: can't set 'ack_timeout'; "
                      "value (%s) must be numeric.\n",
                      value_in);
             return (0);
           }
         sscanf (value, "%lu", &long_int);
         m_mib_remote_default.ack_timeout = (u_int_4) long_int;
         i_msg__ ("cfdp_engine: 'ack_timeout' set to '%lu'.\n",
                  m_mib_remote_default.ack_timeout);
       }

     else if (!strcmp (param, MIB_INACTIVITY_TIMEOUT))
       {
         if (!isdigit ((int) value_in[0]))
           {
             e_msg__ ("cfdp_engine: can't set 'inactivity_timeout'; "
                      "value (%s) must be numeric.\n",
                      value_in);
             return (0);
           }
         sscanf (value, "%lu", &long_int);
         m_mib_remote_default.inactivity_timeout = (u_int_4) long_int;
         i_msg__ ("cfdp_engine: 'inactivity_timeout' set to '%lu'.\n",
                  m_mib_remote_default.inactivity_timeout);
       }

     else if (!strcmp (param, MIB_OUTGOING_FILE_CHUNK_SIZE))
       {
         if (!isdigit ((int) value_in[0]))
           {
             e_msg__ ("cfdp_engine: can't set 'outgoing_file_chunk_size'; "
                      "value (%s) must be numeric.\n",
                      value_in);
             return (0);
           }
         sscanf (value, "%lu", &long_int);
         requested_size = (u_int_4) long_int;
         if (requested_size > MAX_FILE_CHUNK_SIZE)
           {
             e_msg__ ("cfdp_engine: can't set 'outgoing_file_chunk_size'; "
                      "value (%s) exceeds max (%lu).\n",
                      value_in, MAX_FILE_CHUNK_SIZE);
             return (0);
           }
         else
           {
             m_mib_remote_default.outgoing_file_chunk_size = requested_size;
             i_msg__ ("cfdp_engine: 'outgoing_file_chunk_size' "
                      "set to '%lu'.\n",
                      m_mib_remote_default.outgoing_file_chunk_size);
           }
       }

     else if (!strcmp (param, MIB_NAK_LIMIT))
       {
         if (!isdigit ((int) value_in[0]))
           {
             e_msg__ ("cfdp_engine: can't set 'nak_limit'; "
                      "value (%s) must be numeric.\n",
                      value_in);
             return (0);
           }
         sscanf (value, "%lu", &long_int);
         m_mib_remote_default.nak_limit = (u_int_4) long_int;
         i_msg__ ("cfdp_engine: 'nak_limit' set to '%lu'.\n",
                  m_mib_remote_default.nak_limit);
       }

     else if (!strcmp (param, MIB_NAK_TIMEOUT))
       {
         if (!isdigit ((int) value_in[0]))
           {
             e_msg__ ("cfdp_engine: can't set 'nak_timeout'; "
                      "value (%s) must be numeric.\n",
                      value_in);
             return (0);
           }
         sscanf (value, "%lu", &long_int);
         m_mib_remote_default.nak_timeout = (u_int_4) long_int;
         i_msg__ ("cfdp_engine: 'nak_timeout' set to '%lu'.\n",
                  m_mib_remote_default.nak_timeout);
       }

     else if (!strcmp (param, MIB_SAVE_INCOMPLETE_FILES))
       {
         if (!strcmp (value, "YES"))
           {
             m_mib_remote_default.save_incomplete_files = YES;
             i_msg__ ("cfdp_engine: 'save_incomplete_files' set to 'yes'.\n");
           }
         else if (!strcmp (value, "NO"))
           {
             m_mib_remote_default.save_incomplete_files = NO;
             i_msg__ ("cfdp_engine: 'save_incomplete_files' set to 'no'.\n");
           }
         else
           {
             e_msg__ ("cfdp_engine: can't set 'save_incomplete_files'; "
                      "value (%s) must be 'yes' or 'no'.\n",
                      value_in); 
             return (0);
           }
       }

     else
       {
         e_msg__ ("cfdp_engine: can't set unrecognized MIB parameter "
                  "(%s).\n",
                  param);
         return (0);
       }

     return (1);
   }
コード例 #12
0
ファイル: r2.c プロジェクト: Rileybrains/BARCoMmS
/*=r=************************************************************************/
void r2__state_table (MACHINE *m, int event, 
                      PDU_AS_STRUCT *pdu_ptr, REQUEST *req_ptr)
     /* NOTE:  Conceptually, this state table has 2 states:
      *    S1 = Nominal 
      *    S2 = Transaction Cancelled
      * So, the state is always S1 unless the transaction is cancelled.
      * Transactions can be cancelled in 3 ways:
      *    1) the local User can issue a Cancel Request
      *    2) our CFDP partner can send an EOF-Cancel PDU.
      *    3) A fault may occur, and the response to that fault may be
      *       to cancel.
      */
{
  TRANS_STATUS        *mp = &(m->publik);   /* useful shorthand */
  /*------------------------------------------------------------*/

  /* Possibly display some debug info */
  if (cfdp_is_message_class_enabled (CFDP_MSG_STATE_ALL))
    aaa__display_state_and_event ("R2", m->publik.state, event);


  /*-----------------------*/
  /* Respond to each Event */
  /*-----------------------*/

  

  if (event == THROTTLE_OUTGOING_FILE_DIR_PDU)
    /* Release, at most, one outgoing PDU. */
    {
      if (mp->frozen)
        /* We can't release any PDUs while frozen */
        ;

      else if (mp->suspended)
        /* The only PDU that can released while suspended is an Ack */
        {
          if (m->is_outgoing_ack_buffered)
            /* An Ack PDU is ready.  Do we have the "green light"? */
            if (pdu_output__ready (FILE_DIR_PDU, mp->trans, m->hdr.dest_id))
              /* Light is green.  Send it */
              m__release_an_ack_pdu (m);
        }

      else if (m->is_outgoing_ack_buffered)
        /* We're not frozen or suspended, so we can release any PDU.
         * An Ack is ready.  Do we have the "green light"?
         */
        {
          if (pdu_output__ready (FILE_DIR_PDU, mp->trans, m->hdr.dest_id))
            /* Light is green.  Send it */
            m__release_an_ack_pdu (m);
        }

      else if (m->is_outgoing_nak_buffered)
        /* We're not frozen or suspended, so we can release any PDU.
         * A Nak is ready.  Do we have the "green light"?
         */
        {
          if (pdu_output__ready (FILE_DIR_PDU, mp->trans, m->hdr.dest_id))
            /* Light is green.  Send it */
            m__release_a_nak_pdu (m);
        }

      else if (m->is_outgoing_fin_buffered)
        /* We're not frozen or suspended, so we can release any PDU.
         * A Finished is ready.  Do we have the "green light"?
         */
        {
          if (pdu_output__ready (FILE_DIR_PDU, mp->trans, m->hdr.dest_id))
            /* Light is green.  Send it */
            m__release_a_fin_pdu (m);
        }
    }



  else if (event == RECEIVED_SUSPEND_REQUEST)
    /* A Suspend Request was received; suspend timers */
    aaa__notice_of_suspension (m);
  


  else if (event == RECEIVED_RESUME_REQUEST)
    /* A Resume Request was received; possibly resume timers */
    {
      /* 'Indication' callback allows engine user to respond to events */
      indication__ (IND_RESUMED, &(m->publik));
      mp->suspended = NO;
      /* Timers remain paused if either 'suspended' or 'frozen' */
      if (!mp->frozen)
        aaa__resume_timers (m);
    }



  else if (event == RECEIVED_CANCEL_REQUEST)
    /* Received a Cancel Request (from our User, not from our partner) */
    {
      /* If the transaction isn't already being cancelled, begin doing so */
      if (mp->state == S1)
        {
          mp->condition_code = CANCEL_REQUEST_RECEIVED;
          m->have_we_initiated_a_cancel = YES;
          /* Cancel both locally... */
          aaa__cancel_locally (m);
          /* ... and remotely (i.e. have our partner cancel too) */
          m__ask_partner_to_cancel (m);
          m__move_to_state_s2 (m);
        }
    }



  else if (event == RECEIVED_ABANDON_REQUEST)
    /* Abandon this transaction */
    aaa__abandon_this_transaction (m);



  else if (event == RECEIVED_REPORT_REQUEST)
    /* A Report Request was received; issue a Report */
    indication__ (IND_REPORT, &(m->publik));



  else if (event == RECEIVED_FREEZE_REQUEST)
    /* A "Freeze" was received, so suspend all timers. */
    {
      mp->frozen = YES;
      aaa__suspend_timers (m);
    }



  else if (event == RECEIVED_THAW_REQUEST)
    /* A "Thaw" was received; possibly resume all timers. */
    {
      mp->frozen = NO;
      /* Timers remain paused if either 'suspended' or 'frozen' */
      if (!mp->suspended)
        aaa__resume_timers (m);
    }



  else if (event == RECEIVED_METADATA_PDU)
    /* Received a Metadata PDU.  This is normally the first PDU we receive
     * but not always.  And its possible that we might receive more than one
     * Metadata pdu; We only respond to the first Metadata we receive.
     */
    {
      /* Ignore PDUs received while cancelling */
      if (mp->state == S2)
        return;

      /* CFDP messages that we send back to our partner will reuse the
       * header that we receive in the first message from them (except 
       * that the "direction" field will be reversed).
       * Note: The first message we receive may be Metadata, Filedata, or EOF.
       */

      /* Our outgoing PDU header will be the same as the first incoming
       * PDU header (but with the 'direction' field reversed).
       */
      if (!m->has_a_pdu_been_received)
        {
          aaa__reuse_senders_first_hdr (pdu_ptr->hdr, m);
          /* 'Indication' callback allows engine user to respond to events */
          indication__ (IND_MACHINE_ALLOCATED, &(m->publik));
          m->has_a_pdu_been_received = YES;
        }

      /* Note:  Metadata may arrive more than once (it shouldn't, but it
       * can).  Respond to the first Metadata and ignore all the others.
       */
      if (!mp->has_md_been_received)
        /* This is the first Metadata PDU for this transaction */
        {
          mp->has_md_been_received = YES;
          mp->md = pdu_ptr->data_field.md;
          /* 'Indication' callback allows engine user to respond to events */
          indication__ (IND_METADATA_RECV, &(m->publik));
  
          /* If this transaction will transfer a file, prepare */
          if (mp->md.file_transfer)
            {
              /* Open a temporary file (unless a file was already opened
               * in response to a Filedata or EOF PDU).
               * Note:  Normally, Metadata is the first PDU received,
               * but that is not guaranteed.
               */
              if (!m->is_there_an_open_file)
                {
                  if (aaa__open_temp_file (m))
                    m->is_there_an_open_file = YES;
                  else
                    {
                      e_msg__ ("cfdp_engine: unable to open a temp file "
                               "(MD).\n");
                      if (!m__fault_handler (m, FILESTORE_REJECTION))
                        return;
                    }
                }
            }

          /* Update the Nak-list to indicate that Metadata has been received */
          nak__metadata_sent_or_received (&(m->nak));

          /* <NOT_SUPPORTED> Metadata TLVs (processed here) */

          /* Protocol Optimization:  Don't wait for the Nak-timer to expire
           * before checking to see if retransmission is complete.
           */
          if (m->has_eof_been_received)
            {
              if (nak__is_list_empty (&m->nak))
                /* All data has been received; begin nominal Finish */
                m__all_data_has_been_received (m);
            }
        }
    }
  


  else if (event == RECEIVED_FILEDATA_PDU)
    /* Received a Filedata Pdu.  Nominally, we store it in a file, and 
     * update our bookkeeping.  But if the transaction is being cancelled,
     * don't bother.
     */
    {
      /* Ignore PDUs received while cancelling */
      if (mp->state == S2)
        return;
      
      /* Our outgoing PDU header will be the same as the first incoming
       * PDU header (but with the 'direction' field reversed).
       */
      if (!m->has_a_pdu_been_received)
        {
          aaa__reuse_senders_first_hdr (pdu_ptr->hdr, m);
          /* 'Indication' callback allows engine user to respond to events */
          indication__ (IND_MACHINE_ALLOCATED, &(m->publik));
          m->has_a_pdu_been_received = YES;
        }

      /* If we haven't already opened a file to receive the data, do so now */
      if (!m->is_there_an_open_file)
        {
          if (aaa__open_temp_file (m))
            m->is_there_an_open_file = YES;
          else
            {
              e_msg__ ("cfdp_engine: unable to open a temp file (FD).\n");
              if (!m__fault_handler (m, FILESTORE_REJECTION))
                return;
            }
        }
      
      /* Save the File-data in the temporary file */
      mp->fd_offset = pdu_ptr->data_field.fd.offset;
      mp->fd_length = pdu_ptr->data_field.fd.buffer_length;
      if (mib__issue_file_segment_recv())
        /* 'Indication' callback allows engine user to respond to events */
        indication__ (IND_FILE_SEGMENT_RECV, &(m->publik));
      aaa__store_file_data (m->fp, &pdu_ptr->data_field.fd);

      /* Update the received file size */
      if (mp->fd_offset + mp->fd_length > mp->received_file_size)
        /* This FD has made the file bigger than before */
        mp->received_file_size = mp->fd_offset + mp->fd_length;

      /* If this Filedata segment exposes a gap, add gap to nak-list.
       * (the 'nak' module takes care of all this bookkeeping stuff)
       */
      nak__data_received (&m->nak, mp->fd_offset, 
                          mp->fd_offset + mp->fd_length);

      /* If this Filedata PDU arrived *after* the EOF PDU (typically, not
       * the case), check for a "file size error".
       */
      if (m->has_eof_been_received)
        /* A "file_size_error" means that the received file-data cannot be
         * stored without extending the file's length beyond the length
         * specified in the EOF PDU.
         */
        if (!aaa__is_file_size_valid (m))
          if (!m__fault_handler (m, FILE_SIZE_ERROR))
            return;

      /* Protocol Optimization:  Don't wait for the Nak-timer to expire
       * before checking to see if retransmission is complete.
       */
      if (m->has_eof_been_received)
        {
          if (nak__is_list_empty (&m->nak))
            /* All data has been received; begin nominal Finish */
            m__all_data_has_been_received (m);
        }
    }
  


  else if (event == RECEIVED_EOF_NO_ERROR_PDU)
    /* Received an EOF-no-error Pdu.  This tells us that the Sender has
     * sent all data once.  We always Ack this pdu.  Nominally, we
     * take stock and respond with either a Nak or Finished PDU.  However,
     * if the transaction is being cancelled, don't bother.
     */
    {

      /*-------------------------------*/
      /* Always acknowledge an EOF PDU */
      /*-------------------------------*/

      /* Save a copy of the EOF */
      m->eof = pdu_ptr->data_field.eof;

      /* Our outgoing PDU header will be the same as the first incoming
       * PDU header (but with the 'direction' field reversed).
       */
      aaa__reuse_senders_first_hdr (pdu_ptr->hdr, m);

      /* Build and queue an Ack of the EOF (every EOF must be acked) */
      m->ack = aaa__build_ack_eof (m);
      m->is_outgoing_ack_buffered = YES;

      /*---------------------------------------*/
      /* Ignore PDUs received while cancelling */
      /*---------------------------------------*/
      if (mp->state == S2)
        return;
      
      /*--------------------------------------------------*/
      /* The rest of this logic only executes in state S1 */
      /*--------------------------------------------------*/

      /* We are now in Phase 2 (Handoff) */
      mp->phase = 2;

      /* Issue the Machine-Allocated Indication once per transaction */
      if (!m->has_a_pdu_been_received)
        {
          /* 'Indication' callback allows engine user to respond to events */
          indication__ (IND_MACHINE_ALLOCATED, &(m->publik));
          m->has_a_pdu_been_received = YES;
        }

      /* If configured to do so, issue an Indication to the user */
      if (mib__issue_eof_recv())
        indication__ (IND_EOF_RECV, &(m->publik));

      /* If this is the *first* EOF received for this transaction, then
       * additional actions must be taken; otherwise, it can be ignored.
       * Why would a second EOF be sent if we received the first one?
       * Because our Ack of the first EOF was dropped.
       */
      if (!m->has_eof_been_received)
        {
          m->has_eof_been_received = YES;

          /* Update the Nak-list (because this EOF may expose a file gap
           * beyond the highest Filedata offset received -- for example,
           * we received Filedata for offset 0 through 900, and the EOF
           * tells us the file is 1000 bytes long, so we are missing
           * filedata 900-1000).
           * (Again, the 'nak' module takes care of this bookkeeping stuff)
           */
          nak__set_end_of_scope (&m->nak, m->eof.file_size);
          
          /* Verify that the file-size given in the EOF is valid.  For 
           * example, if we received Filedata for offset 0 through 1100,
           * and the EOF tells us the file is 1000 bytes long, the file size
           * is invalid.
           */
          if (!aaa__is_file_size_valid (m))
            if (!m__fault_handler (m, FILE_SIZE_ERROR))
              return;

          if (nak__is_list_empty (&m->nak))
            /* All data has been received; begin nominal Finish */
            m__all_data_has_been_received (m);
          else
            /* Get the missing data (queue up our first Nak) */
            m->is_outgoing_nak_buffered = YES;
        }
    }
  


  else if (event == RECEIVED_EOF_CANCEL_PDU)
    /* Received an EOF-Cancel Pdu.  We always Ack this pdu.  If we have
     * initiated a Cancel, we have to wait for an Ack of our own cancel;
     * otherwise, we shut down after sending the Ack.
     */
    {
      /* Save a copy of the EOF PDU */
      m->eof = pdu_ptr->data_field.eof;

      /* Our outgoing PDU header will be the same as the first incoming
       * PDU header (but with the 'direction' field reversed).
       */
      if (!m->has_a_pdu_been_received)
        {
          aaa__reuse_senders_first_hdr (pdu_ptr->hdr, m);
          /* 'Indication' callback allows engine user to respond to events */
          indication__ (IND_MACHINE_ALLOCATED, &(m->publik));
          m->has_a_pdu_been_received = YES;
        }

      /* If we haven't already cancelled locally, accept partner's request */
      if (mp->state == S1)
        {
          aaa__cancel_locally (m);
          mp->condition_code = m->eof.condition_code;
          mp->phase = 4;
          m__move_to_state_s2 (m);
        }

      /* Regardless, we must acknowledge receipt of the EOF PDU */
      m->ack = aaa__build_ack_eof (m);
      m->is_outgoing_ack_buffered = YES;
    }



  else if (event == RECEIVED_ACK_FIN_NO_ERROR_PDU)
    /* Received Ack of Finished-no-error Pdu.  Nominally, we are done and
     * can shut down immediately.  However, if we have initiated a cancel,
     * we have to wait for an Ack of our Finished-Cancel PDU.
     */
    {
      if (mp->state == S1)
        /* This is the nominal situation */
        {
          if (mp->delivery_code == DATA_COMPLETE)
            /* We're done; we can shut down now */
            aaa__transaction_has_finished (m);
          else
            /* Why is our partner sending an Ack-Finished when we haven't
             * sent a Finished?
             */
            w_msg__ ("cfdp_engine: protocol violation: "
                     "ack of non-existent Finished-no-error.\n");
        }

      else
        /* Transaction is already being cancelled, so ignore this pdu */
        ;
    }



  else if (event == RECEIVED_ACK_FIN_CANCEL_PDU)
    /* Received Ack of Finished-Cancel Pdu.  If we have initiated a cancel,
     * this completes the transaction, and we can shut down immediately.
     * Otherwise, our partner has violated the protocol.
     */
    {
      if (mp->state == S1)
        /* Protocol violation - we didn't send a Finished-Cancel,
         * but our partner has  acknowledged receipt.
         */
        w_msg__ ("cfdp_engine: protocol violation: "
                 "ack of non-existent Finish-Cancel.\n");

      else
        /* Transaction is being cancelled */
        {
          /* This is the nominal path when a Cancel is initiated from our
           * side.  We sent a Finished-Cancel, and partner ack'd it, so
           * we can shut down this state machine.
           */
          aaa__transaction_has_finished (m);
        }                
    }



  else if (event == ACK_TIMER_EXPIRED)
    /* Ack-timer expired.  Resend the Fin Pdu (if permitted). */
    {
      /* 'Indication' callback allows engine user to respond to events */
      indication__ (IND_ACK_TIMER_EXPIRED, &(m->publik));

      if (mp->state == S1)
        /* This is the nominal situation */
        {
          /* If we've already sent the Fin PDU as many times as allowed,
           * then declare a Fault.
           */
          if (mp->attempts >= mib__ack_limit (NULL))
            /* Let the Fault mechanism decide what to do */
            if (!m__fault_handler (m, POSITIVE_ACK_LIMIT_REACHED))
              return;

          /* Try again -- Re-queue the Fin for metered release */
          m->is_outgoing_fin_buffered = YES;
        }

      else
        /* Transaction is being cancelled */
        {
          /* If we've already sent the Fin-Cancel PDU as many times as
           * allowed, the only choice is to give up (abandon the transaction).
           */
          if (mp->attempts >= mib__ack_limit (NULL))
            /* "Positive Ack Limit" has been reached; give up */
            aaa__abandon_this_transaction (m);
          else
            /* Try again -- Re-queue the Fin for metered release */
            m->is_outgoing_fin_buffered = YES;
        }
    }



  else if (event == NAK_TIMER_EXPIRED)
    /* Nak-timer expired.  If all data has been received, we move on to
     * phase 4 (send a Finished-No-Error PDU).  If not, send another
     * Nak PDU (if permitted).
     */
    {
      /* 'Indication' callback allows engine user to respond to events */
      indication__ (IND_NAK_TIMER_EXPIRED, &(m->publik));

      /* We should always be in state S1 when the Nak-timer expires, but
       * if we are not, then ignore it.
       */
      if (mp->state == S2)
        return;

      /* Every time the Nak-timer expires we check to see whether we 
       * have received all the requested retransmissions.
       */
      if (nak__is_list_empty (&m->nak))
        /* All data has been received; begin nominal Finish */
        m__all_data_has_been_received (m);
      else
        /* Still some data missing, so send another Nak (if permitted) */
        {
          /* If we've already sent the Nak PDU as many times as allowed,
           * then declare a Fault.
           */
          if (mp->attempts >= mib__nak_limit (NULL))
            /* Let the Fault mechanism decide what to do */
            if (!m__fault_handler (m, NAK_LIMIT_REACHED))
              return;

          /* Queue another outgoing Nak */
          m->is_outgoing_nak_buffered = YES;
        }
    }
  


  else if (event == INACTIVITY_TIMER_EXPIRED)
    /* Inactivity-timer expired */
    {
      /* 'Indication' callback allows engine user to respond to events */
      indication__ (IND_INACTIVITY_TIMER_EXPIRED, &(m->publik));

      if (mp->state == S1)
        {
          /* Restart the Inactivity-timer */
          m->inactivity_timer = timer__start (mib__inactivity_timeout(NULL));
          /* Let the Fault mechanism decide what else to do */
          if (!m__fault_handler (m, INACTIVITY_DETECTED))
            return;
        }

      else
        /* Transaction is being cancelled; give up */
        aaa__abandon_this_transaction (m);
    }



  else 
    /* Ignore any other events */
    w_msg__ ("cfdp_engine: ignored event '%s' in state %s "
             "for trans '%s' <R2>.\n",
             event__event_as_string(event), mp->state, 
             cfdp_trans_as_string (mp->trans));
}
コード例 #13
0
ファイル: r2.c プロジェクト: Rileybrains/BARCoMmS
/*=r=*************************************************************************/
static void m__all_data_has_been_received (MACHINE *m)
     /* WHAT IT DOES:  Performs the actions required after all data has
      *   been delivered.  Typically, validates the delivered file, moves
      *   it to the destination specified in the Metadata PDU, and
      *   builds/queues an outgoing Finished-No-error PDU.
      */
{
  TRANS_STATUS      *mp = &(m->publik);   /* useful shorthand */
  /*------------------------------------------------------------*/

  /* IMPORTANT:  The program will crash if the actions in this routine are
   * carried out more than once, so prevent that from happening.
   */
  if (mp->delivery_code == DATA_COMPLETE)
    /* Return immediately! */
    {
      w_msg__ ("cfdp_engine: 'all_data_has_been_received' called 2+ times.\n");
      return;
    }

  /* We've received everything, so delivery is complete... */
  mp->delivery_code = DATA_COMPLETE;

  /* ... and there is no need to send a Nak back to the sender. */
  m->is_outgoing_nak_buffered = NO;
  timer__cancel (&m->nak_timer);
  
  /* If a file has been transferred, do something with it */
  if (mp->md.file_transfer)
    {
      /* If the temporary file is still open, then close it */
      if (m->is_there_an_open_file)
        {
          ASSERT__ (m->fp != NULL);
          if (m->fp == NULL)
            /* This should never happen, but if it does, avoid crashing */
            ;
          else
            fclose_callback (m->fp);
          m->is_there_an_open_file = NO;
        }
      
      /* Validate the received file (via the checksum) */
      if (!aaa__is_file_checksum_valid (m))
        {
          if (!m__fault_handler (m, FILE_CHECKSUM_FAILURE))
            return;
        }
      
      /* Move the temporary file to the real destination */
      if (!rename_callback (mp->temp_file_name, mp->md.dest_file_name))
        /* Success */
        m->is_there_a_temp_file = NO;
      else
        /* Oops. Our attempt to move the file failed. */
        {
          e_msg__ ("cfdp_engine: unable to rename '%s' to '%s'.\n",
                   mp->temp_file_name, mp->md.dest_file_name);
          e_msg__ ("cfdp_engine: are they on separate filesystems?\n");
          if (!m__fault_handler (m, FILESTORE_REJECTION))
            return;
        }
    }
  
  /* <NOT_SUPPORTED> Filestore Requests (executed here) */
  
  /* Build and queue a Finished Pdu */
  m->fin = aaa__build_fin (NO_ERROR, mp->delivery_code);
  m->is_outgoing_fin_buffered = YES;
  mp->attempts = 0;
}