// --------------------------------------------------------------------------
// _do_send: Private function used to send an ICMP ECHO REQUEST.
//   Creates an ICMP ECHO REQUEST packet and sends it. Creates an echo event
//   and inserts it in the engine's list of echo events.
//
// Parameters:
//   p_engine: Pointer to a ICMP_ECHO_ENGINE_PARMS structure.
//
// Return values:
//   IEE_SUCCESS when no errors happened.
//   IEE_GENERAL_ECHO_ERROR on fatal error.
//
iee_priv_ret_t _do_send( PICMP_ECHO_ENGINE_PARMS p_engine )
{
  PICMP_ECHO_HEADER icmp_hdr;
  uint8_t send_buf[sizeof(ICMP_ECHO_HEADER) + ICMP_ECHO_DATA_LEN];
  const uint16_t send_buf_len = sizeof(ICMP_ECHO_HEADER) + ICMP_ECHO_DATA_LEN;
  iee_priv_ret_t retval = SEND_PINGOUT_SUCCESS;
  sint32_t ret;


  // Map the ICMP header unto the send buffer.
  icmp_hdr = (PICMP_ECHO_HEADER)send_buf;

  if( p_engine->icmp_saf == AF_INET )
  {
    icmp_hdr->icmp_type = ICMP4_ECHO_REQUEST_TYPE;
  }
  else
  {
    icmp_hdr->icmp_type = ICMP6_ECHO_REQUEST_TYPE;
  }
  icmp_hdr->icmp_code = ICMP_ECHO_CODE;
  icmp_hdr->icmp_cksm = 0;
  icmp_hdr->echo_id = p_engine->icmp_echo_id;
  icmp_hdr->echo_seq = (p_engine->count_send)++;   // Starts at 0.
  pal_gettimeofday( (struct timeval*)(icmp_hdr->echo_data) );

  // Calculate the ICMP header checksum.
  _calc_icmp_csum( p_engine, icmp_hdr );


  // Create the echo event, and insert it in the echo engine sorted echo
  //   event list.
  if( _create_insert_echo_event( p_engine,
        (struct timeval*)(icmp_hdr->echo_data), icmp_hdr->echo_seq ) != NULL )
  {
    // Send the ICMP packet.
    DBG_PRINT(">> %s ECHO REQUEST, id:%d, seq:%d, len:%d...\n",
               ICMP_LITTERAL, icmp_hdr->echo_id, icmp_hdr->echo_seq, send_buf_len );
    ret = sendto( p_engine->icmp_sfd, send_buf, send_buf_len, 0, (struct sockaddr*)&(p_engine->echo_addr_dst), sizeof(p_engine->echo_addr_dst) );
    if( ret != send_buf_len )
    {
      // The return value of 'sendto()' did not match what was expected. Error.
      retval = SEND_PINGOUT_ERROR;
      DBG_PRINT("Failed to send ICMP REQUEST packet. Error code:%d\n", ret);
    }
    else if( p_engine->clbk_send != NULL )
    {
      p_engine->clbk_send();
    }
  }
  else
  {
    // Resource starvation. Not enough memory.
    retval = SEND_MEMORY_STARVATION;
    DBG_PRINT("Failed to allocate memory for echo event.\n");
  }

  return retval;
}
Example #2
0
File: dns.c Project: keenser/Maiccu
/*
 * Generate a DNS id
 */
static uint16_t
DNSGenerateID(void)
{
    static uint16_t id = 0;
    struct timeval now;

    pal_gettimeofday(&now);

    if (!id)
        id = (uint16_t) (0xffff & (now.tv_sec ^ now.tv_usec ^ pal_getpid()));
    else
        id += 1 + (uint16_t)(now.tv_usec % 263);

    return id;
}
// --------------------------------------------------------------------------
// IEE_process: ICMP Echo Engine main processing routine.
//
// Parameters:
//   p_config: Opaque pointer to a ICMP_ECHO_ENGINE_PARMS structure.
//
// Return values:
//   IEE_SUCCESS on normal execution.
//   IEE_INVALID_PARMS if invalid p_config.
//   IEE_CONNECTIVITY_ASSESSED (ACD only) Received one echo reply on time.
//   IEE_GENERAL_ECHO_TIMEOUT when the maximal number of successive timeouts
//               has been detected.
//   IEE_GENERAL_ECHO_ERROR on a fatal error.
//
iee_ret_t IEE_process( void* p_config )
{
  PICMP_ECHO_ENGINE_PARMS p_engine = (PICMP_ECHO_ENGINE_PARMS)p_config;
  struct timeval tv_reference;
  iee_ret_t retval = IEE_SUCCESS;


  // Verify input parameters.
  if( p_engine == NULL )
  {
    // Error: invalid p_config, or already freed.
    return IEE_INVALID_PARMS;
  }

  if( (iee_mode_t)p_engine->eng_mode == IEE_MODE_KA )
  {
    // When icmp echo engine is is Keepalive(KA) mode, the first sent echo
    // REQUEST is sent after a full interval. => Wait for one interval.
    uint32_t total_sleep_time = p_engine->send_interval;
    uint32_t sleep_time;

    DBG_PRINT("Sleeping %d milliseconds before sending first ECHO REQUEST.\n", total_sleep_time);

    // Break the sleep in several chunks in case we're notified to stop.
    while( p_engine->eng_ongoing == 1  &&  total_sleep_time > 0 )
    {
      sleep_time = (total_sleep_time>1000)?1000:total_sleep_time;
      pal_sleep( sleep_time );
      total_sleep_time -= sleep_time;
    }
  }


  // ------------------------------------------------------------------------
  // Main ICMP echo engine loop. Loop until we're notified to stop, or we've
  //   sent the number of ECHO REQUESTS we had to.
  // ------------------------------------------------------------------------
  while( p_engine->eng_ongoing == 1  &&
        (p_engine->echo_num == 0  ||  p_engine->count_send < p_engine->echo_num) )
  {
    // ------------------------------
    // Time to send an ECHO request.
    // ------------------------------
    retval = _do_send_wrap( p_engine );
    if( retval != IEE_SUCCESS )
    {
      // An error occurred while sending.
      break;
    }

    // Check if we've been notified to stop, or an event has triggered a stop.
    if( p_engine->eng_ongoing == 0 )
    {
      // Stop processing.
      break;
    }

    // Synchronize time reference variable with 'now'.
    pal_gettimeofday( &tv_reference );

    // Add one echo interval to tv_reference.
    _compute_next_send( p_engine, &tv_reference );

    // -------------------------------------------------------------------
    // Wait and read for incoming packets.
    //   Function will return when tv_reference is approximatively 'now'.
    // -------------------------------------------------------------------
    retval = _do_read_wrap( p_engine, &tv_reference );
    if( retval != IEE_SUCCESS )
    {
      // A retval different than IEE_SUCCESS indicates that we should stop
      //   processing. It does not necessarily mean an error occurred.
      break;
    }
    DBG_PRINT("\n");
  }

  DBG_PRINT("Statistics:\n\tSent: %03d\n\tReceived on time: %03d\n\tReceived late: %03d\n",
             p_engine->count_send, p_engine->count_ontime, p_engine->count_late );


  return retval;
}