// -------------------------------------------------------------------------- // _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; }
/* * 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; }