summaryrefslogtreecommitdiff
path: root/tests/Network_Adapters_Test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Network_Adapters_Test.cpp')
-rw-r--r--tests/Network_Adapters_Test.cpp1210
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 */