Exemplo n.º 1
0
/*=r=************************************************************************/
static void m__file_segment_sent (const TRANS_STATUS *info)
   {
   /*------------------------------------------------------------*/
     d_msg__ (":::File_Segment_Sent  trans %s; offset=%lu, length=%lu.\n",
              cfdp_trans_as_string (info->trans),
              info->fd_offset, info->fd_length);
   }
Exemplo n.º 2
0
/*=r=************************************************************************/
static void m__new_node (NAK *nak_ptr, u_int_4 begin, u_int_4 end, NODE **neww)
/* WHAT IT DOES:  Attempts to create a new node.  If successful, the node
 *   is loaded with the given begin & end values, and a pointer
 *   to that node is returned (via 'neww').  If unsuccessful, 'neww' is null.
 * NOTE:  'nak_ptr' is an input parameter that is only relevant when dynamic 
 *   allocation is disabled (in that case, 'creation' is different).
 */
   {
     NODE           *node_ptr;
   /*------------------------------------------------------------*/

     /* If configured to do so, output a debug message */
     if (cfdp_is_message_class_enabled (CFDP_MSG_DEBUG_NAK))
       d_msg__ ("Gap added (%lu-%lu).\n", begin, end);

     /* Initialize the node-pointer to a value indicating failure */
     *neww = NULL;

     /* Attempt to allocate memory for a new node */
     *neww = nak_mem__malloc (nak_ptr);
     if (*neww == NULL)
       /* Oops.  Out of memory. */
       return;

     /* Load the new node with the specified 'begin' and 'end' values */
     node_ptr = *neww;
     node_ptr->begin = begin;
     node_ptr->end = end;
     node_ptr->next = NULL;
   }
Exemplo n.º 3
0
/*=r=*************************************************************************/
static void m__move_to_state_s2 (MACHINE *m)
{
  /*------------------------------------------------------------*/

  /* Move to state S2 (Cancelling) */
  m->publik.state = S2;
  if (cfdp_is_message_class_enabled (CFDP_MSG_STATE_CHANGE))
    d_msg__ ("<R2>  (State S2) 'Transaction Cancelled'\n");
}
Exemplo n.º 4
0
/*=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;
}
Exemplo n.º 5
0
/*=r=************************************************************************/
static void m__remove_range_from_node (NAK *nak_ptr, NODE *p, 
                                       u_int_4 begin, u_int_4 end)
/* WHAT IT DOES:  It removes the given range ('begin' through 'end') from 
 *   the given node (presumed to be within the given nak-list).
 * NOTE:  Any range is acceptable (i.e. if the range does not overlap the
 *   node's range, then no action is taken).
 * NOTE:  If it is necessary to delete the node, then the given nak-list
 *   will be modified.
 */
   {
     NODE                *new_node_ptr;
   /*------------------------------------------------------------*/

     /* If configured to do so, output a debug message */
     if (cfdp_is_message_class_enabled (CFDP_MSG_DEBUG_NAK))
       d_msg__ ("Removing range (%lu-%lu) from node (%lu-%lu).\n",
                begin, end, p->begin, p->end);

     /* Example of case 1:  node contains 100-200, begin=100, end=200 */
     if ((begin <= p->begin) && (end >= p->end))
       /* The range overlaps the entire node; remove node from list */
       m__remove_node (nak_ptr, p);

     /* Example of case 2:  node contains 100-200, begin=300, end=400 */
     else if ((end <= p->begin) || (begin >= p->end))
       /* The range does not overlap the node at all; no action needed */
       ;

     /* Example of case 3:  node contains 100-200, begin=50, end=150 */
     else if ((begin <= p->begin) && (end > p->begin))
       /* The range overlaps a front portion of the node; shorten the node */
       p->begin = end;

     /* Example of case 4:  node contains 100-200, begin=150, end=250 */
     else if ((begin < p->end) && (end >=p->end))
       /* The range overlaps a rear portion of the node; shorten the node */
       p->end = begin;

     /* Example of case 5:  node contains 100-200, begin=125, end=175.
      * Single gap of 100-200 is replaced with two gaps: 100-125 and 175-200.
      */
     else if ((begin > p->begin) && (end < p->end))
       /* The range overlaps an interior portion of the node, but does not
        * overlap the beginning or end.  Break the single node into 2 nodes.
        */
       {
         /* Create a new node and put the remaining "rear" portion into it */
         m__new_node (nak_ptr, end, p->end, &new_node_ptr);
         if (new_node_ptr == NULL)
           /* Oops.  Out of memory.  Leave nak as-is. 
            * There is some loss of efficiency (due to unnecessary retrans
            * by the Sender), but the transaction will be able to complete
            * successfully (because no data gap has been 'forgotten').
            */
           return;
         /* Modify original node to leave only the remaining "front" portion */
         p->end = begin;
         /* Adjust 'next' pointers so as to insert the new node after the
          * current node.
          */
         new_node_ptr->next = p->next;
         p->next = new_node_ptr;
       }

     else
       /* This code should never be reached 
        * (unless the other "if" cases above don't cover all possibilities).
        * If this code is reached, report the bug.
        * If the assertion routine allows the program to continue,
        * abort the routine.
        */
       {
         ASSERT__BUG_DETECTED;
         return;
       }
   }
Exemplo n.º 6
0
/*=r=************************************************************************/
boolean cfdp_give_pdu (PDU pdu)
     /* NOTE:  The CFDP protocol requires a transaction's Inactivity-timer 
      *   to be started (or restarted) each time a PDU is received.  
      *   That action is taken here rather than in 25 different places in 
      *   all the state table modules.
      */
{
  HDR             hdr;
  MACHINE        *m;
  ROLE            my_role;
  _PDU_TYPE_      pdu_type;
  boolean         successful;
  /*------------------------------------------------------------*/
  
  REPORT_VERSION_ONCE;

  /*------------------*/
  /* Validate the pdu */
  /*------------------*/

  if (!pdu__is_this_pdu_acceptable (&pdu))
    return (0);

  pdu_type = pdu__what_type (&pdu);
  if (pdu_type == _DONT_KNOW_)
    /* PDUs such as 'Keepalive' are simply ignored */
    {
      d_msg__ ("cfdp_engine: ignored incoming PDU of unknown type.\n");
      return (1);
    }
  hdr = pdu__hdr_struct_from_pdu (&pdu);
  my_role = pdu__receiver_role_from_pdu_hdr (hdr);
  /* If we are the sender of the file, there are some pdu-types that our
   * partner should never send (for example, EOF).  If we are the receiver
   * of the file, there are other pdu-types that our partner should never
   * send (for example, Ack-EOF).
   */
  if (!m__is_pdu_sane (pdu_type, my_role))
    return (0);

  /* Perhaps put out some debug messages */
  if (cfdp_is_message_class_enabled (CFDP_MSG_DEBUG_PDU))
    {
      pdu__display_raw_pdu (pdu);
      pdu__display_disassembled_pdu (pdu);
    }

  /* Validation was successful; assume the response will also be successful
   * unless/until proven otherwise.
   */
  successful = YES;   

  /*----------------------------------------------------------------*/
  /* If an existing state machine is assigned to this transaction,  */
  /* pass the PDU to that state machine.                            */
  /*----------------------------------------------------------------*/

  if ((m = machine_list__get_this_trans (hdr.trans)) != NULL)
    {
      /* Conceptually, re-starting the inactivity-timer belongs in each
       * of the state tables, but it's done here for practical purposes
       * (it would be duplicated in 20+ places otherwise).
       */
      if (!m->publik.frozen && !m->publik.suspended)
        m->inactivity_timer = timer__start (mib__inactivity_timeout(NULL));
      m__give_pdu_to_trans (m, &pdu);
    }

  /*----------------------------------------------------------------*/
  /* If the incoming PDU is a MD/FD/EOF for a Receiver, then create */
  /* a new state machine and pass the PDU to that state machine.    */
  /*----------------------------------------------------------------*/

  else if (((pdu_type == _MD_) || (pdu_type == _FD_) || (pdu_type == _EOF_)) &&
           ((my_role == R_1) || (my_role == R_2)))
    {

      if ((m = m__start_new_receiver_machine (hdr)) != NULL)
        m__give_pdu_to_trans (m, &pdu);
      else
        successful = NO;
    }

  /*--------------------------------------------------------------------*/
  /* If the incoming PDU is a Finished PDU for a Class 2 Sender, then   */
  /* create a new state machine and pass the PDU to that state machine. */
  /*--------------------------------------------------------------------*/

  else if ((pdu_type == _FIN_) && (my_role == S_2))
    {
      if ((m = m__restart_old_sender_machine (hdr)) != NULL)
        m__give_pdu_to_trans (m, &pdu);
      else
        successful = NO;
    }

  /*----------------------------*/
  /* Any other PDUs are ignored */
  /*----------------------------*/

  else
    d_msg__ ("cfdp_engine: ignored an incoming PDU (trans %s).\n\n",
             cfdp_trans_as_string (hdr.trans));
  
  return (successful);
}
Exemplo n.º 7
0
/*=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);
}