Revert "Use a variable on the stack to not have a temporary in the call"
[ACE_TAO.git] / ACE / tests / Network_Adapters_Test.cpp
blob54c3c0087634d61dcac6f6dd2a4bd6d46e090c13
1 //=============================================================================
2 /**
3 * @file Network_Adapters_Test.cpp
5 * Tests the ICMP-echo support in ACE.
7 * @author Robert S. Iakobashvili <coroberti@gmail.com> <coroberti@walla.co.il> Gonzalo A. Diethelm <gonzalo.diethelm@aditiva.com>
8 */
9 //=============================================================================
12 // We need this to be able to check for ACE_HAS_ICMP_SUPPORT
13 #include "ace/config-all.h"
14 #include "test_config.h"
16 #if defined (ACE_HAS_ICMP_SUPPORT) && (ACE_HAS_ICMP_SUPPORT == 1) && \
17 !defined ACE_LACKS_GETPROTOBYNAME
19 #include "ace/ACE.h"
20 #include "ace/Get_Opt.h"
21 #include "ace/Signal.h"
22 #include "ace/High_Res_Timer.h"
23 #include "ace/Atomic_Op.h"
24 #include "ace/Sched_Params.h"
25 #include "ace/Reactor.h"
26 #include "ace/Timer_Queue.h"
27 #include "ace/OS_NS_string.h"
28 #include "ace/OS_NS_signal.h"
29 #include "ace/Timer_Heap.h"
30 #include <memory>
32 #include "Network_Adapters_Test.h"
34 /**
35 * There are two major uses of the functionality:
37 * 1. to check a local network adapter;
38 * 2. to check which of the remote CEs (computer elements) are alive.
40 * For the first purpose we are creating a raw socket, binding it to
41 * the IP-address in question (adapter to be monitored), and are
42 * sending via the adapter ICMP echo-checks to a list of 3rd party
43 * ping-points. If at least a single 3rd party replies us within a
44 * configurable timeout by an ICMP-reply, our adapter is OK. If not, we
45 * may wish to repeat ICMP-probing once or twice more. We may also
46 * wish to make such tests regular with a configurable interval in seconds.
48 * For the second purpose we are creating a raw socket, and without
49 * binding it are sending via any our CE's adapter ICMP echo-checks to
50 * a list of CEs to be monitored. An array of chars (named ping_status
51 * in main ()), corresponding to the array of addresses
52 * (ping_points_addrs in main ()), contains status of each monitored
53 * CE. When we get ICMP-reply from a ping_points_addrs[I] IP-address,
54 * we are placing 0 to the ping_status[I]. The ICMP-probing may be
55 * configured to test 2-3 times each pinged CE. We may also wish to
56 * make such tests regular with a configurable interval in seconds.
58 * Command line options:
60 * -b IPv4 of the interface to bind to the socket (only for the
61 * purpose 1), e.g. -b 192.168.5.5;
63 * -p IPv4 addresses of the remote CEs, which we are going to check
64 * (purpose 2), or they are 3rd points for the purpose 1,
65 * e.g. -p 192.168.5.120: 192.168.5.122: 192.168.5.125
67 * -w milliseconds to wait for echo-reply, on lan 100-200 msec, on
68 * WAN may be 2000-5000 msec, for GPRS may reach 10000 - 20000
69 * mseconds;
71 * -t as we are doing such checks regularly time in seconds between
72 * checks.
74 * In main we are activating by open () an instance of Echo_Handler
75 * with parameters.
77 * Repeats_Handler serves to repeat the checks each
78 * repeats_seconds_timer seconds.
80 * Stop_Handler contains a list of handlers to be stopped and is
81 * supposed to close this business.
83 * Attention: Running the test without parameters (just using defaults)
84 * makes pinging to the loopback address. Therefore, the raw socket
85 * sees both ICMP_ECHO and ICMP_ECHOREPLY with the first output in log
86 * as not a ICMP_ECHOREPLY message and further ICMP_ECHOREPLY
87 * received. Don't worry, be happy - it's ok.
89 Echo_Handler::Echo_Handler ()
90 : ping_socket_ (),
91 reply_wait_ (),
92 remote_addrs_ (0),
93 number_remotes_ (0),
94 success_status_ (0),
95 delete_success_status_ (0),
96 max_attempts_num_ (0),
97 current_attempt_ (0),
98 connect_to_remote_ (0)
102 Echo_Handler::~Echo_Handler ()
104 ACE_DEBUG ((LM_DEBUG,
105 ACE_TEXT ("(%P|%t) Echo_Handler::~Echo_Handler - entered.\n")));
107 this->ping_socket ().close ();
108 if (this->remote_addrs_)
110 delete [] this->remote_addrs_;
111 this->remote_addrs_ = 0;
113 if (this->success_status_ && this->delete_success_status_)
115 delete this->success_status_;
117 this->success_status_ = 0;
119 ACE_DEBUG
120 ((LM_DEBUG,
121 ACE_TEXT ("(%P|%t) Echo_Handler::~Echo_Handler - completed.\n")));
125 Echo_Handler::open (ACE_Reactor * const reactor,
126 ACE_Time_Value const & reply_wait,
127 ACE_INET_Addr const & remote_addr,
128 ACE_TCHAR * success_status,
129 size_t max_attempts_num,
130 ACE_Addr const & local_addr,
131 int connect_to_remote)
133 if (this->reactor ())
134 ACE_ERROR_RETURN ((LM_ERROR,
135 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
136 ACE_TEXT ("reactor is already set.\n")),
137 -1);
138 if (!reactor)
139 ACE_ERROR_RETURN ((LM_ERROR,
140 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed : ")
141 ACE_TEXT ("NULL pointer to reactor provided.\n")),
142 -1);
144 this->reactor (reactor);
145 this->reply_wait_ = reply_wait;
147 if (this->remote_addrs_)
148 ACE_ERROR_RETURN ((LM_ERROR,
149 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
150 ACE_TEXT ("remote_addrs_ already initialized.\n")),
151 -1);
153 ACE_NEW_RETURN (this->remote_addrs_, ACE_INET_Addr, -1);
155 // now copy to keep it locally
156 this->remote_addrs_[0] = remote_addr;
157 this->number_remotes_ = 1;
158 if (this->success_status_)
159 ACE_ERROR_RETURN ((LM_ERROR,
160 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
161 ACE_TEXT ("success_status_ already initialized.\n")),
162 -1);
164 if (! success_status)
166 ACE_NEW_RETURN (this->success_status_, ACE_TCHAR, -1);
167 this->delete_success_status_ = 1;
169 else
171 this->success_status_ = success_status;
174 // place 'failed' to the array.
175 this->success_status_[0] = 1;
177 this->max_attempts_num_ = max_attempts_num;
178 this->current_attempt_ = this->max_attempts_num_;
180 if (this->ping_socket ().open (local_addr) == -1)
181 ACE_ERROR_RETURN ((LM_ERROR,
182 ACE_TEXT ("(%P|%t) Echo_Handler::open: %p\n"),
183 ACE_TEXT ("ping_socket_")),
184 -1);
186 this->connect_to_remote_ = connect_to_remote;
188 // Register with the reactor for input.
189 if (this->reactor ()->register_handler (this,
190 ACE_Event_Handler::READ_MASK) == -1)
191 ACE_ERROR_RETURN ((LM_ERROR,
192 ACE_TEXT ("(%P|%t) Echo_Handler::open: %p\n"),
193 ACE_TEXT ("register_handler for input")),
194 -1);
195 return 0;
199 Echo_Handler::open (ACE_Reactor * const reactor,
200 ACE_Time_Value const & reply_wait,
201 ACE_INET_Addr const remote_addrs[],
202 size_t number_remotes,
203 ACE_TCHAR *success_status,
204 size_t max_attempts_num,
205 ACE_Addr const & local_addr)
207 if (this->reactor ())
208 ACE_ERROR_RETURN ((LM_ERROR,
209 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
210 ACE_TEXT ("reactor is already set.\n")),
211 -1);
213 //FUZZ: disable check_for_NULL
214 if (!reactor)
215 ACE_ERROR_RETURN ((LM_ERROR,
216 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: NULL ")
217 ACE_TEXT ("pointer to reactor provided.\n")),
218 -1);
219 //FUZZ: enable check_for_NULL
221 this->reactor (reactor);
222 this->reply_wait_ = reply_wait;
224 if (!remote_addrs)
225 ACE_ERROR_RETURN ((LM_ERROR,
226 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
227 ACE_TEXT ("NULL remote_addr pointer provided.\n")),
228 -1);
230 if (!number_remotes)
231 ACE_ERROR_RETURN ((LM_ERROR,
232 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
233 ACE_TEXT ("size of remote_addrs array is 0.\n")),
234 -1);
236 this->number_remotes_ = number_remotes;
238 if (this->remote_addrs_)
239 ACE_ERROR_RETURN ((LM_ERROR,
240 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
241 ACE_TEXT ("remote_addrs_ already initialized.\n")),
242 -1);
244 ACE_NEW_RETURN (this->remote_addrs_,
245 ACE_INET_Addr[this->number_remotes_],
246 -1);
248 // now copy to keep them locally
249 for (size_t i = 0; i < this->number_remotes_; ++i)
251 this->remote_addrs_[i] = remote_addrs[i];
254 if (this->success_status_)
255 ACE_ERROR_RETURN ((LM_ERROR,
256 ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
257 ACE_TEXT ("success_status_ already initialized.\n")),
258 -1);
260 if (! success_status)
262 ACE_NEW_RETURN (this->success_status_,
263 ACE_TCHAR[this->number_remotes_],
264 -1);
265 this->delete_success_status_ = 1;
267 else
269 this->success_status_ = success_status;
272 // place 'failed' to the this->success_status_ array.
273 for (size_t j = 0; j < this->number_remotes_; ++j)
275 this->success_status_[j] = 1;
278 this->max_attempts_num_ = max_attempts_num;
279 this->current_attempt_ = this->max_attempts_num_;
281 // If this process doesn't have privileges to open a raw socket, log
282 // a warning instead of an error.
283 if (this->ping_socket ().open (local_addr) == -1)
285 if (errno == EPERM || errno == EACCES)
286 ACE_ERROR_RETURN ((LM_WARNING,
287 ACE_TEXT ("(%P|%t) Echo_Handler::open: ")
288 ACE_TEXT ("ping_socket_: insufficient privs to ")
289 ACE_TEXT ("run this test\n")),
290 -1);
291 else
292 ACE_ERROR_RETURN ((LM_ERROR,
293 ACE_TEXT ("(%P|%t) Echo_Handler::open: %p\n"),
294 ACE_TEXT ("ping_socket_")),
295 -1);
298 // register with the reactor for input
299 if (this->reactor ()->register_handler (this,
300 ACE_Event_Handler::READ_MASK) == -1)
301 ACE_ERROR_RETURN ((LM_ERROR,
302 ACE_TEXT ("(%P|%t) Echo_Handler::open: %p\n"),
303 ACE_TEXT ("register_handler for input")),
304 -1);
305 return 0;
308 ACE_Ping_Socket &
309 Echo_Handler::ping_socket ()
311 return this->ping_socket_;
315 Echo_Handler::dispatch_echo_checks (int first_call)
317 // Set ones , if this is the first call (not from handle_timeout)
318 if (first_call)
320 for (size_t j = 0; j < this->number_remotes_; ++j)
322 this->success_status_[j] = 1;
324 this->current_attempt_ = this->max_attempts_num_;
327 // Send echo-checks.
328 for (size_t i = 0; i < this->number_remotes_; ++i)
330 if (this->success_status_[i] != 0)
332 if (this->ping_socket ().send_echo_check (
333 this->remote_addrs_[i],
334 this->connect_to_remote_) == -1)
335 ACE_ERROR
336 ((LM_ERROR,
337 ACE_TEXT ("(%P|%t) Echo_Handler::dispatch_echo_checks - ")
338 ACE_TEXT ("failed for this->remote_addrs_[%d].\n"),
339 i));
343 int rval_sched = -1;
344 if ((rval_sched =
345 this->reactor ()->schedule_timer (this,
347 ACE_Time_Value (1),
348 this->reply_wait_)) == -1)
349 ACE_ERROR_RETURN ((LM_ERROR,
350 ACE_TEXT ("(%P|%t) Echo_Handler::dispatch_echo_checks:")
351 ACE_TEXT (" %p\n"),
352 ACE_TEXT ("schedule_timer")),
353 -1);
354 return 0;
358 Echo_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
360 ACE_DEBUG ((LM_DEBUG,
361 ACE_TEXT ("(%P|%t) Echo_Handler::handle_close - started.\n")));
363 #if 0
364 this->ping_socket ().close ();
365 #endif
367 this->reactor ()->cancel_timer (this);
369 #if 0
370 this->reactor ()->remove_handler (this,
371 ACE_Event_Handler::ALL_EVENTS_MASK |
372 ACE_Event_Handler::DONT_CALL);
373 #endif
375 ACE_DEBUG ((LM_DEBUG,
376 ACE_TEXT ("(%P|%t) Echo_Handler::handle_close - completed.\n")));
377 return 0;
380 ACE_HANDLE
381 Echo_Handler::get_handle () const
383 return ((ACE_ICMP_Socket &) this->ping_socket_).get_handle ();
387 Echo_Handler::handle_input (ACE_HANDLE)
389 ACE_DEBUG ((LM_DEBUG,
390 ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
391 ACE_TEXT ("activity occurred on handle %d!\n"),
392 this->ping_socket ().get_handle ()));
394 ACE_TCHAR buf[BUFSIZ];
395 ACE_OS::memset (buf, 0, sizeof buf);
397 ACE_INET_Addr addr;
398 int rval_recv = -1;
400 // Receive an <n> byte <buf> from the datagram socket
401 // (uses<recvfrom(3)>).
402 rval_recv =
403 this->ping_socket ().recv (this->ping_socket ().icmp_recv_buff (),
404 ACE_Ping_Socket::PING_BUFFER_SIZE,
405 addr);
406 switch (rval_recv)
408 case -1:
409 // Complain and leave, but keep registered, returning 0.
410 ACE_ERROR_RETURN ((LM_ERROR,
411 ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
412 ACE_TEXT ("%p: bad read\n"),
413 ACE_TEXT ("client")),
415 // NOTREACHED
417 case 0:
418 // Complain and leave
419 ACE_ERROR_RETURN ((LM_ERROR,
420 ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
421 ACE_TEXT ("closing daemon (fd = %d)\n"),
422 this->get_handle ()),
424 // NOTREACHED
426 default:
427 ACE_DEBUG ((LM_INFO,
428 ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
429 ACE_TEXT ("message from %d bytes received.\n"),
430 rval_recv));
432 if (! this->ping_socket ().process_incoming_dgram (
433 this->ping_socket ().icmp_recv_buff (),
434 rval_recv))
436 for (size_t k = 0; k <this->number_remotes_; ++k)
438 if (addr.is_ip_equal (this->remote_addrs_[k]))
440 if (addr.addr_to_string (buf, sizeof buf) == -1)
442 ACE_ERROR ((LM_ERROR,
443 ACE_TEXT ("%p\n"),
444 ACE_TEXT ("can't obtain peer's address")));
446 else
448 ACE_DEBUG
449 ((LM_INFO,
450 ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
451 ACE_TEXT ("ECHO_REPLY received ")
452 ACE_TEXT ("from %s; marking this peer alive\n"),
453 buf));
455 // mark as successful
456 this->success_status_[k] = 0;
457 break;
461 break;
464 return 0;
468 Echo_Handler::handle_timeout (ACE_Time_Value const &,
469 void const *)
471 ACE_DEBUG ((LM_DEBUG,
472 ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - ")
473 ACE_TEXT ("timer for ping_socket_ with handle %d.\n"),
474 this->ping_socket ().get_handle ()));
476 int need_to_proceed = 0;
478 for (size_t i = 0; i < this->number_remotes_; ++i)
480 if (this->success_status_[i])
482 need_to_proceed = 1;
484 ACE_DEBUG ((LM_DEBUG,
485 ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - ")
486 ACE_TEXT ("this->success_status_[%d] is not zero. ")
487 ACE_TEXT ("Need to proceed echo-checks.\n"), i));
488 break;
492 if (!need_to_proceed)
494 ACE_DEBUG ((LM_DEBUG,
495 ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - ")
496 ACE_TEXT ("need_to_proceed == 0. ")
497 ACE_TEXT ("Completed echo-checks.\n")));
500 if (!this->current_attempt_ || !need_to_proceed)
502 ACE_DEBUG ((LM_DEBUG,
503 ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - ")
504 ACE_TEXT ("completed ECHO-checks for handle (%d).\n"),
505 this->ping_socket ().get_handle ()));
506 return -1; // to de-register from Reactor and make clean-up
507 // in handle-close
510 if (this->current_attempt_)
512 --this->current_attempt_;
515 ACE_DEBUG
516 ((LM_DEBUG,
517 ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - attempt %d.\n"),
518 this->current_attempt_));
520 this->dispatch_echo_checks ();
521 return 0;
525 Echo_Handler::does_echo_test_successful ()
527 for (size_t i = 0; i < this->number_remotes_; ++i)
529 if (!this->success_status_[i])
531 return 1;
534 return 0;
538 Stop_Handler::Stop_Handler (ACE_Reactor * const reactor)
539 : counter_ ((counter_sig) 1)
541 this->reactor (reactor);
542 ACE_OS::memset (this->handlers_to_stop_,
544 sizeof this->handlers_to_stop_);
547 Stop_Handler::~Stop_Handler ()
549 ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%P|%t) Stop_Handler::~Stop_Handler.\n")));
553 Stop_Handler::open ()
555 // Register the signal handler object to catch the signals.
556 #if (SIGINT != 0)
557 if (this->reactor ()->register_handler (SIGINT, this) == -1)
558 ACE_ERROR_RETURN ((LM_ERROR,
559 ACE_TEXT ("(%P|%t) Stop_Handler::open: %p <%d>\n"),
560 ACE_TEXT ("register_handler for SIGINT"), SIGINT),
561 -1);
562 this->registered_signals_.sig_add (SIGINT);
563 #endif /* SIGINT != 0 */
565 #if (SIGTERM != 0)
566 if (this->reactor ()->register_handler (SIGTERM, this) == -1)
567 ACE_ERROR_RETURN ((LM_ERROR,
568 ACE_TEXT ("(%P|%t) Stop_Handler::open: %p <%d>\n"),
569 ACE_TEXT ("register_handler for SIGTERM"), SIGTERM),
570 -1);
571 this->registered_signals_.sig_add (SIGTERM);
572 #endif /* SIGTERM != 0 */
574 #if (SIGQUIT != 0)
575 if (this->reactor ()->register_handler (SIGQUIT, this) == -1)
576 ACE_ERROR_RETURN ((LM_ERROR,
577 ACE_TEXT ("(%P|%t) Stop_Handler::open: %p <%d>\n"),
578 ACE_TEXT ("register_handler for SIGQUIT"), SIGQUIT),
579 -1);
580 this->registered_signals_.sig_add (SIGQUIT);
581 #endif /* SIGQUIT != 0 */
582 return 0;
586 Stop_Handler::handle_signal (int signum, siginfo_t * , ucontext_t *)
588 ACE_DEBUG ((LM_DEBUG,
589 ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal - started.\n")));
590 if (! --this->counter_)
592 ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n-- Stop_Handler::handle_signal --- ")
593 ACE_TEXT ("SIGNAL %d RECEIVED -----------.\n"),
594 signum));
595 return reactor ()->notify (this, ACE_Event_Handler::READ_MASK);
597 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal - ")
598 ACE_TEXT ("finished.\n")));
599 return 0;
603 Stop_Handler::handle_input (ACE_HANDLE handle)
605 ACE_UNUSED_ARG (handle);
607 ACE_DEBUG ((LM_INFO,
608 ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - entered\n")));
610 for (size_t i = 0; i < HANDLERS_TO_STOP_TABLE_SIZE; ++i)
612 // remove from the reactor's tables all non-null entries
613 if (this->handlers_to_stop_[i])
615 // protect from deleted pointer
618 this->reactor ()->cancel_timer (this->handlers_to_stop_[i]);
619 this->reactor ()->remove_handler
620 (this->handlers_to_stop_[i],
621 ACE_Event_Handler::ALL_EVENTS_MASK
622 | ACE_Event_Handler::DONT_CALL);
624 catch (...)
626 ACE_ERROR ((LM_ERROR,
627 ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - ")
628 ACE_TEXT ("EXCEPTION CATCHED. Most probably ")
629 ACE_TEXT ("handler's pointer has been deleted.\n")));
631 this->handlers_to_stop_[i] = 0;
635 this->reactor ()->remove_handler (this->registered_signals_);
637 if (reactor ()->end_reactor_event_loop () == -1)
639 ACE_ERROR_RETURN ((LM_DEBUG,
640 ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal:%p\n"),
641 ACE_TEXT ("end_reactor_event_loop")),
642 -1);
645 ACE_DEBUG ((LM_INFO,
646 ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - completed.\n")));
647 return 0;
651 Stop_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask m)
653 ACE_DEBUG ((LM_INFO,
654 ACE_TEXT ("(%P|%t) Stop_Handler::handle_close - entered.\n")));
655 if (m == ACE_Event_Handler::SIGNAL_MASK)
656 return 0;
657 this->reactor ()->remove_handler (this,
658 ACE_Event_Handler::SIGNAL_MASK |
659 ACE_Event_Handler::DONT_CALL);
661 if (reactor ()->end_reactor_event_loop () == -1)
662 ACE_ERROR_RETURN ((LM_DEBUG,
663 ACE_TEXT ("Stop_Handler::handle_close: %p\n"),
664 ACE_TEXT ("end_reactor_event_loop")),
665 -1);
666 return 0;
670 Stop_Handler::handle_timeout (ACE_Time_Value const &,
671 void const *)
673 return 0;
676 // Register handler with us for stopping.
678 Stop_Handler::register_handler (ACE_Event_Handler *handler)
680 if (!handler)
681 ACE_ERROR_RETURN ((LM_ERROR,
682 ACE_TEXT ("(%P|%t) Stop_Handler::register_handler - ")
683 ACE_TEXT ("error, handler is a null pointer.\n")),
684 -1);
686 size_t index = 0;
688 for (index = 0;
689 (index < HANDLERS_TO_STOP_TABLE_SIZE &&
690 this->handlers_to_stop_[index]);
691 ++index)
694 if (index == HANDLERS_TO_STOP_TABLE_SIZE)
696 ACE_ERROR_RETURN ((LM_ERROR,
697 ACE_TEXT ("(%P|%t) Stop_Handler::register_handler ")
698 ACE_TEXT ("- error, no space in ")
699 ACE_TEXT ("handlers_to_stop_table.\nIncrease ")
700 ACE_TEXT ("HANDLERS_TO_STOP_TABLE_SIZE.\n")),
701 -1);
704 this->handlers_to_stop_[index] = handler;
705 return 0;
708 // Unregister handler, registered before with us for stopping.
710 Stop_Handler::unregister_handler (ACE_Event_Handler *handler)
712 if (!handler)
713 ACE_ERROR_RETURN ((LM_ERROR,
714 ACE_TEXT ("(%P|%t) Stop_Handler::unregister_handler - ")
715 ACE_TEXT ("error, handler is a null pointer.\n")),
716 -1);
718 size_t index = 0;
720 for (index = 0;
721 (index < HANDLERS_TO_STOP_TABLE_SIZE &&
722 handler != this->handlers_to_stop_[index]);
723 ++index)
726 size_t entrance = 0;
727 if (index == HANDLERS_TO_STOP_TABLE_SIZE)
728 ACE_ERROR_RETURN ((LM_ERROR,
729 ACE_TEXT ("(%P|%t) Stop_Handler::unregister_")
730 ACE_TEXT ("handler - error, the handler was not ")
731 ACE_TEXT ("found among registered handlers.\n")),
732 -1);
734 entrance = index;
735 // null the entrance. Nulled entrances cannot be destroyed
736 this->handlers_to_stop_[entrance] = 0;
738 return 0;
742 Repeats_Handler::Repeats_Handler ()
743 : check_handler_ (0),
744 seconds_timer_ (60),
745 counter_ (0)
749 Repeats_Handler::~Repeats_Handler ()
751 ACE_DEBUG ((LM_INFO,
752 ACE_TEXT ("(%P|%t) Repeats_Handler::~Repeats_Handler.\n")));
756 Repeats_Handler::open (Echo_Handler * check_handler,
757 ACE_Reactor * const reactor,
758 unsigned int seconds_timer)
760 if (!check_handler)
761 ACE_ERROR_RETURN ((LM_ERROR,
762 ACE_TEXT ("(%P|%t) Repeats_Handler::open - error: ")
763 ACE_TEXT ("NULL check_handler.\n")),
764 -1);
766 this->check_handler_ = check_handler;
768 if (!reactor)
769 ACE_ERROR_RETURN ((LM_ERROR,
770 ACE_TEXT ("(%P|%t) Stop_Handler::open - error: ")
771 ACE_TEXT ("NULL reactor.\n")),
772 -1);
774 this->reactor (reactor);
775 this->seconds_timer_ = seconds_timer;
777 if (this->reactor ()->schedule_timer (
778 this,
780 ACE_Time_Value (1),
781 ACE_Time_Value (this->seconds_timer_)) == -1)
782 ACE_ERROR_RETURN ((LM_ERROR,
783 ACE_TEXT ("(%P|%t) Repeats_Handler::open: %p\n"),
784 ACE_TEXT ("schedule_timer")),
785 -1);
786 return 0;
790 Repeats_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
792 ACE_DEBUG
793 ((LM_INFO,
794 ACE_TEXT ("(%P|%t) Repeats_Handler::handle_close - entered.\n")));
796 this->reactor ()->remove_handler (this,
797 ACE_Event_Handler::ALL_EVENTS_MASK |
798 ACE_Event_Handler::DONT_CALL);
799 return 0;
802 static int one_button_test = 0;
805 Repeats_Handler::handle_timeout (ACE_Time_Value const &,
806 void const *)
808 this->counter_++ ;
809 if (one_button_test && this->counter_ > 3)
811 ACE_OS::raise (SIGINT);
813 if (this->check_handler_)
815 return this->check_handler_->dispatch_echo_checks (true);
818 return -1;
821 // to create core on some UNIX platforms
822 #if defined (ACE_HAS_SIG_C_FUNC)
823 extern "C"
825 #endif /* #if defined (ACE_HAS_SIG_C_FUNC) */
827 #if ! defined (ACE_WIN32)
828 static void sigsegv_handler (int)
830 ACE_OS::abort ();
832 #endif /* #if ! defined (ACE_WIN32) */
834 #if defined (ACE_HAS_SIG_C_FUNC)
836 #endif /* #if defined (ACE_HAS_SIG_C_FUNC) */
838 #if defined (ACE_WIN32)
839 static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
841 switch (fdwCtrlType)
843 case CTRL_C_EVENT:
844 case CTRL_BREAK_EVENT:
845 case CTRL_SHUTDOWN_EVENT:
846 case CTRL_CLOSE_EVENT:
847 case CTRL_LOGOFF_EVENT:
848 ACE_OS::raise (SIGINT);
849 return TRUE;
851 // Pass other signals to the next handler.
852 default:
853 return FALSE;
856 #endif /* #if defined (ACE_WIN32) */
858 #define MAX_NUMBER_OF_PING_POINTS 16
860 static int number_of_ping_points = 0;
861 static char ping_points_ips [MAX_NUMBER_OF_PING_POINTS][16];
862 static ACE_INET_Addr ping_points_addrs [MAX_NUMBER_OF_PING_POINTS];
863 static char local_ip_to_bind [16];
865 static int wait_echo_reply_timer = 500; // 500 ms to wait is the default
866 static int repeats_seconds_timer = 60; // 60 seconds between repeats
868 static int
869 is_ip_address_local (char const * const ip_to_bind)
871 ACE_INET_Addr *the_addr_array = 0;
872 size_t how_many = 0;
873 int rc = ACE::get_ip_interfaces (how_many, the_addr_array);
875 if (rc != 0)
876 ACE_ERROR_RETURN ((LM_ERROR,
877 ACE_TEXT ("is_ip_address_local: %p\n"),
878 ACE_TEXT ("ACE::get_ip_interfaces")),
879 -1);
881 if (how_many == 0)
882 ACE_ERROR_RETURN ((LM_ERROR,
883 ACE_TEXT ("is_ip_address_local: "),
884 ACE_TEXT ("No interfaces presently configured ")
885 ACE_TEXT ("in the kernel\n")),
886 -1);
888 // debugging messages
889 ACE_DEBUG ((LM_DEBUG,
890 ACE_TEXT ("is_ip_address_local () - there are %d interfaces\n"),
891 how_many));
893 for (size_t i = 0; i < how_many; ++i)
895 ACE_DEBUG ((LM_DEBUG,
896 ACE_TEXT ("\t%s\n"),
897 the_addr_array[i].get_host_addr ()));
900 for (size_t j = 0; j < how_many; ++j)
902 if (!ACE_OS::strcmp (the_addr_array[j].get_host_addr (), ip_to_bind))
904 return 0;
907 return -1;
910 static int
911 parse_args (int argc, ACE_TCHAR *argv[])
913 ACE_OS::memset (ping_points_ips, 0, sizeof ping_points_ips);
914 ACE_OS::memset (local_ip_to_bind, 0, sizeof local_ip_to_bind);
916 if (argc == 1) // one button test
918 one_button_test = 1;
919 repeats_seconds_timer = 2;
920 number_of_ping_points = 1;
922 ACE_OS::strncpy (ping_points_ips [0],
923 "127.0.0.1",
924 sizeof ping_points_ips [0]);
926 ping_points_addrs[0].set ((u_short) 0, ping_points_ips[0]);
927 return 0;
930 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("b:p:t:w:"));
931 int c, counter = 0;
932 ACE_INET_Addr b_temp_addr;
933 ACE_TCHAR *token = 0;
934 while ((c = get_opt ()) != EOF)
936 switch (c)
938 case 'b': // ip-address of the interface to bind to
939 ACE_OS::strncpy (local_ip_to_bind,
940 ACE_TEXT_ALWAYS_CHAR (get_opt.optarg),
941 sizeof local_ip_to_bind);
943 if (!ACE_OS::strlen (local_ip_to_bind) ||
944 b_temp_addr.set ((u_short)0, local_ip_to_bind) != 0)
946 ACE_ERROR ((LM_ERROR,
947 ACE_TEXT ("-b should be followed by a valid ")
948 ACE_TEXT ("IPv4 address.\n")));
949 // print_usage ();
950 return -1;
952 if (is_ip_address_local (local_ip_to_bind) == -1)
954 ACE_ERROR_RETURN ((LM_ERROR,
955 ACE_TEXT ("the -b address (%s) ")
956 ACE_TEXT ("is not a local ")
957 ACE_TEXT ("address of your computer.\n")
958 ACE_TEXT ("\tPlease correct it.\n"),
959 local_ip_to_bind),
960 -1);
962 break;
964 case 'p': // ping-point (target) ip-addresses, separated by ":'"
966 // tokenizing the string
967 for (token = ACE_OS::strtok (get_opt.optarg, ACE_TEXT (":"));
968 token != 0 && counter < MAX_NUMBER_OF_PING_POINTS;
969 token = ACE_OS::strtok (0, ACE_TEXT (":")))
971 if (ping_points_addrs[counter].set ((u_short)0, token) != 0)
972 ACE_ERROR_RETURN
973 ((LM_ERROR,
974 ACE_TEXT ("Error: the address \"%s\" is not ")
975 ACE_TEXT ("a valid IPv4 address.\n"),
976 token),
977 -1);
978 ++number_of_ping_points;
979 ++counter;
981 break;
983 case 't':
984 repeats_seconds_timer = ACE_OS::atoi (get_opt.optarg);
985 break;
987 case 'w':
988 wait_echo_reply_timer = ACE_OS::atoi (get_opt.optarg);
989 break;
991 default:
992 // return print_usage (argc,argv);
993 break;
997 if (!number_of_ping_points)
999 ACE_ERROR_RETURN ((LM_ERROR,
1000 ACE_TEXT ("Error: no valid IPv4 addresses ")
1001 ACE_TEXT ("were provided, using -p option.\n")),
1002 -1);
1005 return 0;
1009 run_main (int argc, ACE_TCHAR *argv[])
1011 ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test"));
1013 #if defined (ACE_WIN32)
1014 SetConsoleCtrlHandler(&CtrlHandler, TRUE);
1015 #else /* #if defined (ACE_WIN32) */
1016 // Set a handler for SIGSEGV signal to call for abort.
1017 ACE_Sig_Action sa1 ((ACE_SignalHandler) sigsegv_handler, SIGSEGV);
1018 #endif /* #if defined (ACE_WIN32) */
1019 if (::parse_args (argc, argv) == -1)
1021 return -1;
1024 ACE_Reactor * main_reactor = 0;
1025 ACE_NEW_RETURN (main_reactor, ACE_Reactor, -1);
1027 (void) ACE_High_Res_Timer::global_scale_factor ();
1029 // Change the source of time in the reactor to the high-resolution
1030 // timer. Why does this test require such precision for a 1 second
1031 // timer is beyond me ... I think it is a cut&paste error.
1033 // The use of auto_ptr<> is optional, ACE uses dangerous memory
1034 // management idioms everywhere, I thought I could demonstrate how
1035 // to do it right in at least one test. Notice the lack of
1036 // ACE_NEW_RETURN, that monstrosity has no business in proper C++
1037 // code ...
1038 std::unique_ptr<ACE_Timer_Heap_Variable_Time_Source> tq(
1039 new ACE_Timer_Heap_Variable_Time_Source);
1040 // ... notice how the policy is in the derived timer queue type.
1041 // The abstract timer queue does not have a time policy ...
1042 tq->set_time_policy(&ACE_High_Res_Timer::gettimeofday_hr);
1043 // ... and then the timer queue is replaced. Strangely, the reactor
1044 // does *not* copy the timers, it just deletes the existing timer
1045 // queue ....
1046 main_reactor->timer_queue(tq.get());
1047 // ... the reactor does not assume ownership
1050 * Stop_Handler's is supposed to stop the activity of all
1051 * handlers by a SIGINT signal. We create and activate here an object of
1052 * Stop_Handler and pass an instance of reactor (main_reactor),
1053 * running demultiplexing event loop in the "main thread".
1055 Stop_Handler* stop_handler = 0;
1056 ACE_NEW_RETURN (stop_handler, Stop_Handler (main_reactor), -1);
1057 if (stop_handler->open () == -1)
1059 ACE_ERROR ((LM_ERROR,
1060 ACE_TEXT ("(%P|%t) %p\n"),
1061 ACE_TEXT ("main() - stop_handler->open")));
1062 ACE_OS::exit(-2);
1065 ACE_TCHAR *ping_status = 0;
1066 ACE_NEW_RETURN (ping_status, ACE_TCHAR[number_of_ping_points], -1);
1068 // wait_echo_reply_timer is in msec
1069 int seconds = 0;
1070 int milliseconds = 0;
1071 seconds = wait_echo_reply_timer / 1000;
1072 milliseconds = wait_echo_reply_timer % 1000;
1073 ACE_Time_Value const wait_timer (seconds, milliseconds);
1075 Echo_Handler *ping_handler = 0;
1076 ACE_NEW_RETURN (ping_handler, Echo_Handler, -1);
1078 if (ACE_OS::strlen (local_ip_to_bind))
1080 // We are willing to bind the raw-socket to a certain adapter,
1081 // probably because we are willing to check connectivity/etc
1082 // of the local adapter.
1083 ACE_INET_Addr local_adapter;
1084 local_adapter.set ((u_short) 0, local_ip_to_bind);
1085 if (ping_handler->open (main_reactor,
1086 wait_timer,
1087 ping_points_addrs,
1088 number_of_ping_points,
1089 ping_status,
1090 2, // max_attempts_number
1091 local_adapter) == -1)
1093 int res = 0;
1094 // If this process doesn't have privileges to open a raw socket, log
1095 // a warning instead of an error.
1096 if (errno == EPERM || errno == EACCES)
1098 ACE_ERROR ((LM_WARNING,
1099 ACE_TEXT ("(%P|%t) main() - ping_handler->open: ")
1100 ACE_TEXT ("insufficient privs to run this test\n")));
1102 else
1104 ACE_ERROR ((LM_ERROR,
1105 ACE_TEXT ("(%P|%t) %p\n"),
1106 ACE_TEXT ("main() - ping_handler->open")));
1107 res = -4;
1109 delete ping_handler;
1110 delete [] ping_status;
1111 delete main_reactor;
1112 delete stop_handler;
1114 ACE_END_TEST;
1115 return res;
1118 else
1120 // Binding to a local adapter is not of our interest. We just
1121 // are willing to check all these remote IPs, to monitor, that
1122 // they are alive.
1123 if (ping_handler->open (main_reactor,
1124 wait_timer,
1125 ping_points_addrs,
1126 number_of_ping_points,
1127 ping_status,
1128 2) == -1) // max_attempts_number
1130 int res = 0;
1131 if (errno == EPERM || errno == EACCES)
1133 ACE_ERROR ((LM_WARNING,
1134 ACE_TEXT ("(%P|%t) main() - ping_handler->open: ")
1135 ACE_TEXT ("insufficient privs to run this test\n")));
1137 else
1139 ACE_ERROR ((LM_ERROR,
1140 ACE_TEXT ("(%P|%t) %p\n"),
1141 ACE_TEXT ("main() - ping_handler->open")));
1142 res = -4;
1144 delete ping_handler;
1145 delete [] ping_status;
1146 delete main_reactor;
1147 delete stop_handler;
1149 ACE_END_TEST;
1150 return res;
1154 Repeats_Handler *repeats_handler = 0;
1155 ACE_NEW_RETURN (repeats_handler, Repeats_Handler, -1);
1156 if (repeats_handler->open (ping_handler,
1157 main_reactor,
1158 repeats_seconds_timer) == -1)
1160 ACE_ERROR ((LM_ERROR,
1161 ACE_TEXT ("(%P|%t) %p\n"),
1162 ACE_TEXT ("main() - repeats_handler->open")));
1164 delete repeats_handler;
1165 delete ping_handler;
1166 delete [] ping_status;
1167 delete main_reactor;
1168 delete stop_handler;
1170 ACE_END_TEST;
1171 return -4;
1174 stop_handler->register_handler (repeats_handler);
1175 stop_handler->register_handler (ping_handler);
1177 // Demultiplexing event loop of the main_reactor.
1178 while (main_reactor->reactor_event_loop_done () == 0)
1180 main_reactor->run_reactor_event_loop ();
1183 ACE_DEBUG ((LM_INFO,
1184 ACE_TEXT ("(%P|%t|%T) \"Network_Adapters_Test\" main() - ")
1185 ACE_TEXT ("out of reactor's loop.\n")));
1187 delete repeats_handler;
1188 delete ping_handler;
1189 delete [] ping_status;
1190 delete main_reactor;
1191 delete stop_handler;
1193 ACE_END_TEST;
1194 return 0;
1197 #else
1200 run_main (int, ACE_TCHAR *[])
1202 ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test"));
1204 ACE_DEBUG ((LM_INFO,
1205 ACE_TEXT ("(%P|%t|%T) \"Network_Adapters_Test\" main() - ")
1206 ACE_TEXT ("ICMP support not configured.\n")
1207 ACE_TEXT ("Define ACE_HAS_ICMP_SUPPORT = 1 in your config.h ")
1208 ACE_TEXT ("file to enable.\n")));
1210 ACE_END_TEST;
1212 return 0;
1215 #endif /* ACE_HAS_ICMP_SUPPORT == 1 */