diff options
Diffstat (limited to 'tests/Network_Adapters_Test.cpp')
-rw-r--r-- | tests/Network_Adapters_Test.cpp | 1210 |
1 files changed, 1210 insertions, 0 deletions
diff --git a/tests/Network_Adapters_Test.cpp b/tests/Network_Adapters_Test.cpp new file mode 100644 index 00000000000..0c557d438d5 --- /dev/null +++ b/tests/Network_Adapters_Test.cpp @@ -0,0 +1,1210 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// Network_Adapters_Test.cpp +// +// = DESCRIPTION +// Tests the ICMP-echo support in ACE. +// +// = AUTHOR +// Robert S. Iakobashvili <roberti@go-WLAN.com> <coroberti@walla.co.il> +// Gonzalo A. Diethelm <gonzalo.diethelm@aditiva.com> made aceing +// +// ============================================================================ + +// We need this to be able to check for ACE_HAS_ICMP_SUPPORT +#include "ace/config.h" +#include "test_config.h" + +#if defined (ACE_HAS_ICMP_SUPPORT) && (ACE_HAS_ICMP_SUPPORT == 1) + +#include "ace/ACE.h" +#include "ace/Get_Opt.h" +#include "ace/Signal.h" +#include "ace/High_Res_Timer.h" +#include "ace/Atomic_Op.h" +#include "ace/Sched_Params.h" +#include "ace/Reactor.h" +#include "ace/Timer_Queue.h" +#include "ace/OS_NS_string.h" + +#include "Network_Adapters_Test.h" + + +ACE_RCSID (tests, + Network_Adapters_Test, + "$Id$") + + +/** + * There are two major uses of the functionality: + * + * 1. to check a local network adapter; + * 2. to check, which of the remote CEs (computer elements) are alive. + * + * For the first purpose we are creating a raw socket, binding it to + * the IP-address in question (adapter to be monitored), and are + * sending via the adapter ICMP echo-checks to a list of 3-rd party + * ping-points. If at least a single 3-rd party replies us within a + * configurable timeout by an ICMP-reply, our adapter is OK, if not we + * may wish to repeat ICMP-probing once or twice more. We may also + * wish to make such tests regular with a certain timeout. + * + * For the second purpose we are creating a raw socket, and without + * binding it are sending via any our CE's adapter ICMP echo-checks to + * a list of CEs to be monitored. An array of chars (named ping_status + * in main ()), corresponding to the array of addresses + * (ping_points_addrs in main ()), contains status of each monitored + * CE. When we get ICMP-reply from a ping_points_addrs[I] IP-address, + * we are placing 0 to the ping_status[I]. The ICMP-probing may be + * configured to test 2-3 times each pinged CE. We may also wish to + * make such tests regular with a certain timeout. + * + * Command line options: + * + * -b IPv4 of the interface to bind to the socket (only for the + * purpose 1), e.g. -b 192.168.5.5; + * + * -p IPv4 addresses of the remote CEs, which we are going to check + * (purpose 2), or they are 3-rd points for the purpose 1, + * e.g. “-p 192.168.5.120: 192.168.5.122: 192.168.5.125 + * + * -w milliseconds to wait for echo-reply, on lan 100-200 msec, on + * WAN may be 2000-5000 msec, for GPRS may reach 10000 - 20000 + * mseconds; + * + * -t as we are doing such checks regularly time in seconds between + * checks. + * + * In main we are activating by open () an instance of Echo_Handler + * with parameters. + * + * Repeats_Handler serves to repeat the checks each + * repeats_seconds_timer seconds. + * + * Stop_Handler contains a list of handlers to be stopped and is + * supposed to close this business. + + * Attention: Running the test without parameters just with defaults + * makes pinging to the loopback address. Therefore, the raw socket + * sees both ICMP_ECHO and ICMP_ECHOREPLY with the first output in log + * as not a ICMP_ECHOREPLY message and further ICMP_ECHOREPLY + * received. + */ + + +Echo_Handler::Echo_Handler (void) + : ping_socket_ (), + reply_wait_ (), + remote_addrs_ (0), + number_remotes_ (0), + success_status_ (0), + delete_success_status_ (0), + max_attempts_num_ (0), + current_attempt_ (0), + connect_to_remote_ (0) +{ +} + +Echo_Handler::~Echo_Handler (void) +{ + ACE_DEBUG ((LM_DEBUG, "(%P|%t) Echo_Handler::~Echo_Handler - entered.\n")); + + this->ping_socket ().close (); + if (this->remote_addrs_) + { + delete [] this->remote_addrs_; + this->remote_addrs_ = 0; + } + if (this->success_status_ && this->delete_success_status_) + { + delete this->success_status_; + } + this->success_status_ = 0; + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) Echo_Handler::~Echo_Handler - completed.\n")); +} + +int +Echo_Handler::open (ACE_Reactor * const reactor, + ACE_Time_Value const & reply_wait, + ACE_INET_Addr const & remote_addr, + ACE_TCHAR * success_status, + size_t max_attempts_num, + ACE_Addr const & local_addr, + int connect_to_remote) +{ + if (this->reactor ()) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "reactor is already set. \n"), + -1); + if (!reactor) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed : " + "NULL pointer to reactor provided. \n"), + -1); + + this->reactor (reactor); + this->reply_wait_ = reply_wait; + + if (this->remote_addrs_) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "this->remote_addrs_ already initialized. \n"), + -1); + + if (! (this->remote_addrs_ = new ACE_INET_Addr)) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: to " + "allocate a single ACE_INET_Addr for " + "this->remote_addrs_. \n"), + -1); + + // now copy to keep it locally + this->remote_addrs_[0] = remote_addr; + this->number_remotes_ = 1; + if (this->success_status_) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "this->success_status_ already initialized. \n"), + -1); + + if (! success_status) + { + if (! (this->success_status_ = new ACE_TCHAR)) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "to allocate a single " + "ACE_TCHAR for this->success_status_. \n"), + -1); + this->delete_success_status_ = 1; + } + else + { + this->success_status_ = success_status; + } + + // place 'failed' to the array. + this->success_status_[0] = 1; + + this->max_attempts_num_ = max_attempts_num; + this->current_attempt_ = this->max_attempts_num_; + + if (this->ping_socket ().open (local_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed to " + "initialize ping_socket_. \n"), + -1); + + this->connect_to_remote_ = connect_to_remote; + + // Register with the reactor for input. + if (this->reactor ()->register_handler (this, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - can't register " + "with reactor for " + "handling input.\n"), + -1); + return 0; +} + +int +Echo_Handler::open (ACE_Reactor * const reactor, + ACE_Time_Value const & reply_wait, + ACE_INET_Addr const remote_addrs[], + size_t number_remotes, + ACE_TCHAR *success_status, + size_t max_attempts_num, + ACE_Addr const & local_addr) +{ + if (this->reactor ()) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "reactor is already set. \n"), + -1); + + if (!reactor) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: NULL " + "pointer to reactor provided. \n"), + -1); + + this->reactor (reactor); + this->reply_wait_ = reply_wait; + + if (!remote_addrs) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "NULL remote_addr pointer provided. \n"), + -1); + + if (!number_remotes) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "size of remote_addrs array is 0.\n"), + -1); + + this->number_remotes_ = number_remotes; + + if (this->remote_addrs_) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "this->remote_addrs_ already initialized. \n"), + -1); + + if (! (this->remote_addrs_ = new ACE_INET_Addr [this->number_remotes_])) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "to allocate an array of ACE_INET_Addr " + "objects for this->remote_addrs_. \n"), + -1); + + // now copy to keep them locally + for (size_t i = 0; i < this->number_remotes_; ++i) + { + this->remote_addrs_[i] = remote_addrs[i]; + } + + if (this->success_status_) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "this->success_status_ already initialized. \n"), + -1); + + if (! success_status) + { + if (! (this->success_status_ = new ACE_TCHAR [this->number_remotes_])) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed: " + "to allocate an array of chars for " + "this->success_status_ . \n"), + -1); + this->delete_success_status_ = 1; + } + else + { + this->success_status_ = success_status; + } + + // place 'failed' to the this->success_status_ array. + for (size_t j = 0; j < this->number_remotes_; ++j) + { + this->success_status_[j] = 1; + } + + this->max_attempts_num_ = max_attempts_num; + this->current_attempt_ = this->max_attempts_num_; + + if (this->ping_socket ().open (local_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - failed to " + "initialize ping_socket_. \n"), + -1); + + // register with the reactor for input + if (this->reactor ()->register_handler (this, + ACE_Event_Handler::READ_MASK) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::open - " + "can't register with reactor for " + "handling input.\n"), + -1); + return 0; +} + +ACE::Ping_Socket & +Echo_Handler::ping_socket (void) +{ + return this->ping_socket_; +} + +int +Echo_Handler::dispatch_echo_checks (int first_call) +{ + // Set ones , if this is the first call (not from handle_timeout) + if (first_call) + { + for (size_t j = 0; j < this->number_remotes_; ++j) + { + this->success_status_[j] = 1; + } + this->current_attempt_ = this->max_attempts_num_; + } + + // Send echo-checks. + for (size_t i = 0; i < this->number_remotes_; ++i) + { + if (this->success_status_[i] != 0) + { + if (this->ping_socket ().send_echo_check ( + this->remote_addrs_[i], + this->connect_to_remote_) == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) Echo_Handler::dispatch_echo_checks - " + "failed for this->remote_addrs_[%d]. \n", + i)); + } + } + + int rval_sched = -1; + if ((rval_sched = + this->reactor ()->schedule_timer (this, + 0, + ACE_Time_Value (1), + this->reply_wait_)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::dispatch_echo_checks - " + "schedule_timer() error.\n"), + -1); + return 0; +} + +int +Echo_Handler::handle_close (ACE_HANDLE handle, ACE_Reactor_Mask) +{ + ACE_UNUSED_ARG (handle); + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) Echo_Handler::handle_close - started.\n")); + +#if 0 + this->ping_socket ().close (); +#endif + + this->reactor ()->cancel_timer (this); + +#if 0 + this->reactor ()->remove_handler (this, + ACE_Event_Handler::ALL_EVENTS_MASK | + ACE_Event_Handler::DONT_CALL); +#endif + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) Echo_Handler::handle_close - completed.\n")); + return 0; +} + +ACE_HANDLE +Echo_Handler::get_handle (void) const +{ + return ((ACE::ICMP_Socket &) this->ping_socket_).get_handle (); +} + +int +Echo_Handler::handle_input (ACE_HANDLE) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Echo_Handler::handle_input - " + "activity occurred on handle %d!\n", + this->ping_socket ().get_handle ())); + + ACE_TCHAR buf[BUFSIZ]; + ACE_OS::memset (buf, 0, sizeof buf); + + ACE_INET_Addr addr; + int rval_recv = -1; + + // Receive an <n> byte <buf> from the datagram socket + // (uses<recvfrom(3)>). + rval_recv = + this->ping_socket ().recv (this->ping_socket ().icmp_recv_buff (), + ACE::Ping_Socket::PING_BUFFER_SIZE, + addr); + switch (rval_recv) + { + case -1: + // Complain and leave, but keep registered, returning 0. + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::handle_input - " + "%p bad read\n", "client"), + 0); + // NOTREACHED + + case 0: + // Complain and leave + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Echo_Handler::handle_input - " + "closing daemon (fd = %d)\n", + this->get_handle ()), + 0); + // NOTREACHED + + default: + ACE_DEBUG ((LM_INFO, + "(%P|%t) Echo_Handler::handle_input - " + "message from %d bytes received.\n", + rval_recv)); + + if (! this->ping_socket ().process_incoming_dgram ( + this->ping_socket ().icmp_recv_buff (), + rval_recv)) + { + for (size_t k = 0; k <this->number_remotes_; ++k) + { + if (addr.get_ip_address () == + this->remote_addrs_[k].get_ip_address ()) + { + if (addr.addr_to_string (buf, sizeof buf) == -1) + { + ACE_ERROR ((LM_ERROR, + "%p\n", "can't obtain peer's address")); + } + else + { + ACE_DEBUG ((LM_INFO, + "(%P|%t) Echo_Handler::handle_input - " + "ECHO_REPLY received " + "from %s.\n" + "\tMarking this peer, as alive.\n\n", + buf)); + } + // mark as successful + this->success_status_[k] = 0; + break; + } + } + } + break; + } + + return 0; +} + +int +Echo_Handler::handle_timeout (ACE_Time_Value const &, + void const *) +{ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Echo_Handler::handle_timeout - " + "timer for ping_socket_ with handle %d.\n", + this->ping_socket ().get_handle ())); + + int need_to_proceed = 0; + + for (size_t i = 0; i < this->number_remotes_; ++i) + { + if (this->success_status_[i]) + { + need_to_proceed = 1; + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Echo_Handler::handle_timeout - " + "this->success_status_[%d] is not zero. " + "Need to proceed echo-checks . \n", i)); + break; + } + } + + if (!need_to_proceed) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Echo_Handler::handle_timeout - " + "need_to_proceed == 0. " + "Completed echo-checks. \n")); + } + + if (!this->current_attempt_ || !need_to_proceed) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Echo_Handler::handle_timeout - " + "completed ECHO-checks for handle (%d).\n\n\n", + this->ping_socket ().get_handle ())); + return -1; // to de-register from Reactor and make clean-up + // in handle-close + } + + if (this->current_attempt_) + { + --this->current_attempt_; + } + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Echo_Handler::handle_timeout - attempt %d.\n", + this->current_attempt_)); + + this->dispatch_echo_checks (); + return 0; +} + +int +Echo_Handler::does_echo_test_successful (void) +{ + for (size_t i = 0; i < this->number_remotes_; ++i) + { + if (!this->success_status_[i]) + { + return 1; + } + } + return 0; +} + + +Stop_Handler::Stop_Handler (ACE_Reactor * const reactor) + : counter_ ((counter_sig) 1) +{ + this->reactor (reactor); + ACE_OS::memset (this->handlers_to_stop_, + 0, + sizeof this->handlers_to_stop_); +} + +Stop_Handler::~Stop_Handler (void) +{ + ACE_DEBUG ((LM_INFO, "(%P|%t) Stop_Handler::~Stop_Handler.\n")); +} + +int +Stop_Handler::open (void) +{ + // Register the signal handler object to catch the signals. + if (this->reactor ()->register_handler (SIGINT, this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Stop_Handler::open - " + "register_handler for SIGINT error.\n"), + -1); + + if (this->reactor ()->register_handler (SIGTERM, this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Stop_Handler::open - " + "register_handler for SIGTERM error.\n"), + -1); + +#if ! defined (ACE_WIN32) + if (this->reactor ()->register_handler (SIGQUIT, this) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Stop_Handler::open - " + "register_handler for SIGQUIT error.\n"), + -1); +#endif /* #if ! defined (ACE_WIN32) */ + return 0; +} + +int +Stop_Handler::handle_signal (int signum, + siginfo_t * , + ucontext_t *) +{ + ACE_DEBUG ((LM_DEBUG, "(%P|%t) Stop_Handler::handle_signal - started.\n")); + if (! --this->counter_) + { + ACE_DEBUG ((LM_INFO, "\n-- Stop_Handler::handle_signal --- " + "SIGNAL %d RECEIVED -----------.\n", + signum)); + return reactor ()->notify (this, ACE_Event_Handler::READ_MASK); + } + ACE_DEBUG ((LM_DEBUG, "(%P|%t) Stop_Handler::handle_signal - " + "finished.\n")); + return 0; +} + +int +Stop_Handler::handle_input (ACE_HANDLE handle) +{ + ACE_UNUSED_ARG (handle); + + ACE_DEBUG ((LM_INFO, "(%P|%t) Stop_Handler::handle_input - entered\n")); + + for (size_t i = 0; i < HANDLERS_TO_STOP_TABLE_SIZE; ++i) + { + // remove from the reactor's tables all non-null entries + if (this->handlers_to_stop_[i]) + { +#if defined ACE_HAS_EXCEPTIONS + + // protect from deleted pointer + try + { +#endif // ACE_HAS_EXCEPTIONS + + this->reactor ()->cancel_timer (this->handlers_to_stop_[i]); + this->reactor ()->remove_handler ( + this->handlers_to_stop_[i], + ACE_Event_Handler::ALL_EVENTS_MASK + | ACE_Event_Handler::DONT_CALL); +#if defined ACE_HAS_EXCEPTIONS + } + catch (...) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) Stop_Handler::handle_input - " + "EXCEPTION CATCHED. Most probably " + "handler's pointer has been deleted.\n")); + } +#endif // ACE_HAS_EXCEPTIONS + this->handlers_to_stop_[i] = 0; + } + } + + this->reactor ()->remove_handler (this, + ACE_Event_Handler::SIGNAL_MASK | + ACE_Event_Handler::DONT_CALL); + + if (reactor ()->end_reactor_event_loop () ==-1) + { + ACE_ERROR_RETURN ((LM_DEBUG, + "(%P|%t) Stop_Handler::handle_signal - " + "reactor_->end_reactor_event_loop().\n"), + -1); + } + + ACE_DEBUG ((LM_INFO, + "(%P|%t) Stop_Handler::handle_input - completed.\n")); + return 0; +} + +int +Stop_Handler::handle_close (ACE_HANDLE handle, ACE_Reactor_Mask close_mask) +{ + ACE_UNUSED_ARG (handle); + ACE_UNUSED_ARG (close_mask); + + ACE_DEBUG ((LM_INFO, "(%P|%t) Stop_Handler::handle_close - " + "entered.\n")); + this->reactor ()->remove_handler (this, + ACE_Event_Handler::SIGNAL_MASK | + ACE_Event_Handler::DONT_CALL); + + if (reactor ()->end_reactor_event_loop () ==-1) + ACE_ERROR_RETURN ((LM_DEBUG, + "Stop_Handler::handle_close - " + "reactor_->end_reactor_event_loop().\n"), + -1); + return 0; +} + +int +Stop_Handler::handle_timeout (ACE_Time_Value const & current_time, + void const * act) +{ + ACE_UNUSED_ARG (current_time); + ACE_UNUSED_ARG (act); + + return 0; +} + +// Register handler with us for stopping. +int +Stop_Handler::register_handler (ACE_Event_Handler *handler) +{ + if (!handler) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Stop_Handler::register_handler - " + "error, handler is a null pointer.\n"), + -1); + + size_t index = 0; + + for (index = 0; + (index < HANDLERS_TO_STOP_TABLE_SIZE && + this->handlers_to_stop_[index]); + ++index) + ; + + if (index == HANDLERS_TO_STOP_TABLE_SIZE) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) Stop_Handler::register_handler " + "- error, no space in " + "handlers_to_stop_table.\nIncrease" + "HANDLERS_TO_STOP_TABLE_SIZE.\n")), + -1); + } + + this->handlers_to_stop_[index] = handler; + return 0; +} + +// Unregister handler, registered before with us for stopping. +int +Stop_Handler::unregister_handler (ACE_Event_Handler *handler) +{ + if (!handler) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Stop_Handler::unregister_handler - " + "error, handler is a null pointer.\n"), + -1); + + size_t index = 0; + + for (index = 0; + (index < HANDLERS_TO_STOP_TABLE_SIZE && + handler != this->handlers_to_stop_[index]); + ++index) + ; + + size_t entrance = 0; + if (index == HANDLERS_TO_STOP_TABLE_SIZE) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) Stop_Handler::unregister_" + "handler - error, the handler was not " + "found amoung registered handlers.\n")), + -1); + + entrance = index; + // null the entrance. Nulled entrances cannot be destroyed + this->handlers_to_stop_[entrance] = 0; + + return 0; +} + + +Repeats_Handler::Repeats_Handler (void) + : check_handler_ (0), + seconds_timer_ (60), + counter_ (0) +{ +} + +Repeats_Handler::~Repeats_Handler (void) +{ + ACE_DEBUG ((LM_INFO, "(%P|%t) Repeats_Handler::~Repeats_Handler.\n")); +} + +int +Repeats_Handler::open (Echo_Handler * check_handler, + ACE_Reactor * const reactor, + unsigned int seconds_timer) +{ + if (!check_handler) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Repeats_Handler::open - error: " + "NULL check_handler.\n"), + -1); + + this->check_handler_ = check_handler; + + if (!reactor) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) Stop_Handler::open - error: " + "NULL reactor.\n")), + -1); + + this->reactor (reactor); + this->seconds_timer_ = seconds_timer; + + if (this->reactor ()->schedule_timer ( + this, + 0, + ACE_Time_Value (1), + ACE_Time_Value (this->seconds_timer_)) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t) Repeats_Handler::open - " + "schedule_timer () error.\n"), + -1); + return 0; +} + +int +Repeats_Handler::handle_close (ACE_HANDLE handle, ACE_Reactor_Mask close_mask) +{ + ACE_UNUSED_ARG (handle); + ACE_UNUSED_ARG (close_mask); + + ACE_DEBUG ((LM_INFO, "(%P|%t) Repeats_Handler::handle_close - entered.\n")); + + this->reactor ()->remove_handler (this, + ACE_Event_Handler::ALL_EVENTS_MASK | + ACE_Event_Handler::DONT_CALL); + return 0; +} + +static int one_button_test = 0; + +int +Repeats_Handler::handle_timeout (ACE_Time_Value const & current_time, + void const * act) +{ + ACE_UNUSED_ARG (current_time); + ACE_UNUSED_ARG (act); + + this->counter_++ ; + if (one_button_test && this->counter_ > 3) + { + ::raise (SIGINT); + } + if (this->check_handler_) + { + return this->check_handler_->dispatch_echo_checks (true); + } + + return -1; +} + +// to create core on some UNIX platforms +#if defined (ACE_HAS_SIG_C_FUNC) +extern "C" +{ +#endif /* #if defined (ACE_HAS_SIG_C_FUNC) */ + +#if ! defined (ACE_WIN32) + static void sigsegv_handler (int) + { + ACE_OS::abort (); + } +#endif /* #if ! defined (ACE_WIN32) */ + +#if defined (ACE_HAS_SIG_C_FUNC) +} +#endif /* #if defined (ACE_HAS_SIG_C_FUNC) */ + +#if defined (ACE_WIN32) +BOOL CtrlHandler(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_SHUTDOWN_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + ::raise (SIGINT); + return TRUE; + + // Pass other signals to the next handler. + default: + return FALSE; + } +} +#endif /* #if defined (ACE_WIN32) */ + + +Fini_Guard::Fini_Guard (void) +{ +} + +Fini_Guard::~Fini_Guard (void) +{ + ACE::fini (); +} + + +#define MAX_NUMBER_OF_PING_POINTS 16 + +static int number_of_ping_points = 0; +static char ping_points_ips [MAX_NUMBER_OF_PING_POINTS][16]; +static ACE_INET_Addr ping_points_addrs [MAX_NUMBER_OF_PING_POINTS]; +static char local_ip_to_bind [16]; + +static int wait_echo_reply_timer = 500; // 500 ms to wait is the default +static int repeats_seconds_timer = 60; // 60 seconds between repeats + +static int +is_ip_address_local (char const * const ip_to_bind) +{ + ACE_INET_Addr *the_addr_array; + size_t how_many = 0; + int rc = ACE::get_ip_interfaces (how_many, the_addr_array); + + if (rc != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", "is_ip_address_local () - error: " + "ACE::get_ip_interfaces failed"), + -1); + + if (how_many == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "is_ip_address_local () - error: " + "No interfaces presently configured " + "in the kernel\n"), + -1); + + // debugging messages + ACE_DEBUG ((LM_DEBUG, + "is_ip_address_local () - there are %d interfaces\n", + how_many)); + + for (size_t i = 0; i < how_many; ++i) + { + ACE_DEBUG ((LM_DEBUG, "\t%s\n", the_addr_array[i].get_host_addr ())); + } + + for (size_t j = 0; j < how_many; ++j) + { + if (!ACE_OS::strcmp (the_addr_array[j].get_host_addr (), ip_to_bind)) + { + return 0; + } + } + return -1; +} + +static int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_OS::memset (ping_points_ips, 0, sizeof ping_points_ips); + ACE_OS::memset (local_ip_to_bind, 0, sizeof local_ip_to_bind); + + if (argc == 1) // one button test + { + one_button_test = 1; + repeats_seconds_timer = 2; + number_of_ping_points = 1; + + ACE_OS::strncpy (ping_points_ips [0], + "127.0.0.1", + sizeof ping_points_ips [0]); + + ping_points_addrs[0].set ((u_short) 0, ping_points_ips[0]); + return 0; + } + + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("b:p:t:w:")); + int c, counter = 0; + ACE_INET_Addr b_temp_addr; + char *token = 0; + while ((c = get_opt ()) != EOF) + { + switch (c) + { + case 'b': // ip-address of the interface to bind to + ACE_OS::strncpy (local_ip_to_bind, + get_opt.optarg, + sizeof local_ip_to_bind); + + if (!ACE_OS::strlen (local_ip_to_bind) || + b_temp_addr.set ((u_short)0, local_ip_to_bind) != 0) + { + ACE_ERROR ((LM_ERROR, "%s, -b should be followed by a valid " + "IPv4 address.\n", + "Network_Adapters_Test")); + // print_usage (); + return -1; + } + if (is_ip_address_local (local_ip_to_bind) == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + "%s, the IPv4 address of the -b option (%s) " + "is not a local " + "address of your computer.\n" + "\tPlease correct it.\n", + "Network_Adapters_Test", + local_ip_to_bind), + -1); + } + break; + + case 'p': // ping-point (target) ip-addresses, separated by ":'" + + // tokenizing the string + for (token = ACE_OS::strtok (get_opt.optarg, ACE_TEXT (":")); + token != 0 && counter < MAX_NUMBER_OF_PING_POINTS; + token = ACE_OS::strtok (0, ACE_TEXT (":"))) + { + if (ping_points_addrs[counter].set ((u_short)0, token) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "%s - error: the address \"%s\" is not " + "a valid IPv4 " + "address. \n", "Network_Adapters_Test", + token), + -1); + ++number_of_ping_points; + ++counter; + } + break; + + case 't': + repeats_seconds_timer = ACE_OS::atoi (get_opt.optarg); + break; + + case 'w': + wait_echo_reply_timer = ACE_OS::atoi (get_opt.optarg); + break; + + default: + // return print_usage (argc,argv); + break; + + } + } + + if (!number_of_ping_points) + { + ACE_ERROR_RETURN ((LM_ERROR, + "%s - error: no valid IPv4 addresses " + "were provided, using -p option. \n", + "Network_Adapters_Test"), + -1); + } + + return 0; +} + +int +run_main (int argc, ACE_TCHAR *argv[]) +{ + ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test")); + + ACE::init (); + + // to call for ACE::fini () in its destructor + Fini_Guard fg; + +#if defined (ACE_WIN32) + SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE); +#else /* #if defined (ACE_WIN32) */ + // Set a handler for SIGSEGV signal to call for abort. + ACE_Sig_Action sa1 ((ACE_SignalHandler) sigsegv_handler, SIGSEGV); +#endif /* #if defined (ACE_WIN32) */ + + // Just to ensure that user has root/administrative permissions to + // open raw sockets. + if (ACE_OS::sched_params ( + ACE_Sched_Params (ACE_SCHED_FIFO, + ACE_Sched_Params::priority_min (ACE_SCHED_FIFO), + ACE_SCOPE_PROCESS)) != 0) + { + if (ACE_OS::last_error () == EPERM) + { + ACE_DEBUG ((LM_MAX, + ACE_TEXT ("user is not superuser, ") + ACE_TEXT ("unable to run this test\n"))) ; + return -1; + } + } + + if (::parse_args (argc, argv) == -1) + { + return -1; + } + + ACE_Reactor * main_reactor = 0; + ACE_NEW_RETURN (main_reactor, ACE_Reactor, -1); + + (void) ACE_High_Res_Timer::global_scale_factor (); + main_reactor->timer_queue ()->gettimeofday ( + &ACE_High_Res_Timer::gettimeofday_hr); + + /** + * Stop_Handler's is supposed to stop the activity of all + * handlers by a SIGINT signal. We create and activate here an object of + * Stop_Handler and pass an instance of reactor (main_reactor), + * running demultiplexing event loop in the "main thread". + */ + Stop_Handler* stop_handler = 0; + ACE_NEW_RETURN (stop_handler, Stop_Handler (main_reactor), -1); + if (stop_handler->open () == -1) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", "\"Network_Adapters_Test\" main() - " + "stop_handler->open () failed.\nExiting ...\n")); + ACE_OS::exit(-2); + } + + ACE_TCHAR *ping_status = 0; + ACE_NEW_RETURN (ping_status, ACE_TCHAR[number_of_ping_points], -1); + + // wait_echo_reply_timer is in msec + int seconds = 0; + int milliseconds = 0; + seconds = wait_echo_reply_timer / 1000; + milliseconds = wait_echo_reply_timer % 1000; + ACE_Time_Value const wait_timer (seconds, milliseconds); + + Echo_Handler *ping_handler; + ACE_NEW_RETURN (ping_handler, Echo_Handler, -1); + + if (ACE_OS::strlen (local_ip_to_bind)) + { + // We are willing to bind the raw-socket to a certain adapter, + // probably because we are willing to check connectivity/etc + // of the local adapter. + ACE_INET_Addr local_adapter; + local_adapter.set ((u_short) 0, local_ip_to_bind); + if (ping_handler->open (main_reactor, + wait_timer, + ping_points_addrs, + number_of_ping_points, + ping_status, + 2, // max_attempts_number + local_adapter) == -1) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", "\"Network_Adapters_Test\" main() - " + "ping_handler->open () failed.\nExiting ...\n")); + ACE_OS::exit (-4); + } + } + else + { + // Binding to a local adapter is not of our interest. We just + // are willing to check all these remote IPs, to monitor, that + // they are alive. + if (ping_handler->open (main_reactor, + wait_timer, + ping_points_addrs, + number_of_ping_points, + ping_status, + 2) == -1) // max_attempts_number + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "\"Network_Adapters_Test\" main() - " + "ping_handler->open () failed.\nExiting ...\n")); + ACE_OS::exit (-4); + } + } + + Repeats_Handler *repeats_handler; + ACE_NEW_RETURN (repeats_handler, Repeats_Handler, -1); + if (repeats_handler->open (ping_handler, + main_reactor, + repeats_seconds_timer) == -1) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "\"Network_Adapters_Test\" main() - " + "repeats_handler->open failed.\nExiting ...\n")); + ACE_OS::exit (-4); + } + + stop_handler->register_handler (repeats_handler); + stop_handler->register_handler (ping_handler); + + // Demultiplexing event loop of the main_reactor. + while (main_reactor->reactor_event_loop_done () == 0) + { + main_reactor->run_reactor_event_loop (); + } + + ACE_DEBUG ((LM_INFO, + "(%P|%t|%T) \"Network_Adapters_Test\" main() - " + "out of reactor's loop.\n")); + + delete repeats_handler; + delete ping_handler; + delete [] ping_status; + delete stop_handler; + delete main_reactor; + + ACE_END_TEST; + return 0; +} + +#else + +int +run_main (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test")); + + ACE_DEBUG ((LM_INFO, + "(%P|%t|%T) \"Network_Adapters_Test\" main() - " + "ICMP support not configured.\n" + "Define ACE_HAS_ICMP_SUPPORT = 1 in your config.h " + "file to enable.\n")); + + ACE_END_TEST; + + return 0; +} + +#endif /* ACE_HAS_ICMP_SUPPORT == 1 */ |