Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / ACE / tests / Network_Adapters_Test.cpp
blob395b49cf1177a3f3ea48d5aa0c3f02bfa2bf7728
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 "ace/Auto_Ptr.h"
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 (void)
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 (void)
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 (void)
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 (void) 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 (void)
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 (void)
549 ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%P|%t) Stop_Handler::~Stop_Handler.\n")));
553 Stop_Handler::open (void)
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,
587 siginfo_t * ,
588 ucontext_t *)
590 ACE_DEBUG ((LM_DEBUG,
591 ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal - started.\n")));
592 if (! --this->counter_)
594 ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n-- Stop_Handler::handle_signal --- ")
595 ACE_TEXT ("SIGNAL %d RECEIVED -----------.\n"),
596 signum));
597 return reactor ()->notify (this, ACE_Event_Handler::READ_MASK);
599 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal - ")
600 ACE_TEXT ("finished.\n")));
601 return 0;
605 Stop_Handler::handle_input (ACE_HANDLE handle)
607 ACE_UNUSED_ARG (handle);
609 ACE_DEBUG ((LM_INFO,
610 ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - entered\n")));
612 for (size_t i = 0; i < HANDLERS_TO_STOP_TABLE_SIZE; ++i)
614 // remove from the reactor's tables all non-null entries
615 if (this->handlers_to_stop_[i])
617 #if defined ACE_HAS_EXCEPTIONS
619 // protect from deleted pointer
622 #endif // ACE_HAS_EXCEPTIONS
624 this->reactor ()->cancel_timer (this->handlers_to_stop_[i]);
625 this->reactor ()->remove_handler
626 (this->handlers_to_stop_[i],
627 ACE_Event_Handler::ALL_EVENTS_MASK
628 | ACE_Event_Handler::DONT_CALL);
629 #if defined ACE_HAS_EXCEPTIONS
631 catch (...)
633 ACE_ERROR ((LM_ERROR,
634 ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - ")
635 ACE_TEXT ("EXCEPTION CATCHED. Most probably ")
636 ACE_TEXT ("handler's pointer has been deleted.\n")));
638 #endif // ACE_HAS_EXCEPTIONS
639 this->handlers_to_stop_[i] = 0;
643 this->reactor ()->remove_handler (this->registered_signals_);
645 if (reactor ()->end_reactor_event_loop () == -1)
647 ACE_ERROR_RETURN ((LM_DEBUG,
648 ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal:%p\n"),
649 ACE_TEXT ("end_reactor_event_loop")),
650 -1);
653 ACE_DEBUG ((LM_INFO,
654 ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - completed.\n")));
655 return 0;
659 Stop_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask m)
661 ACE_DEBUG ((LM_INFO,
662 ACE_TEXT ("(%P|%t) Stop_Handler::handle_close - entered.\n")));
663 if (m == ACE_Event_Handler::SIGNAL_MASK)
664 return 0;
665 this->reactor ()->remove_handler (this,
666 ACE_Event_Handler::SIGNAL_MASK |
667 ACE_Event_Handler::DONT_CALL);
669 if (reactor ()->end_reactor_event_loop () == -1)
670 ACE_ERROR_RETURN ((LM_DEBUG,
671 ACE_TEXT ("Stop_Handler::handle_close: %p\n"),
672 ACE_TEXT ("end_reactor_event_loop")),
673 -1);
674 return 0;
678 Stop_Handler::handle_timeout (ACE_Time_Value const &,
679 void const *)
681 return 0;
684 // Register handler with us for stopping.
686 Stop_Handler::register_handler (ACE_Event_Handler *handler)
688 if (!handler)
689 ACE_ERROR_RETURN ((LM_ERROR,
690 ACE_TEXT ("(%P|%t) Stop_Handler::register_handler - ")
691 ACE_TEXT ("error, handler is a null pointer.\n")),
692 -1);
694 size_t index = 0;
696 for (index = 0;
697 (index < HANDLERS_TO_STOP_TABLE_SIZE &&
698 this->handlers_to_stop_[index]);
699 ++index)
702 if (index == HANDLERS_TO_STOP_TABLE_SIZE)
704 ACE_ERROR_RETURN ((LM_ERROR,
705 ACE_TEXT ("(%P|%t) Stop_Handler::register_handler ")
706 ACE_TEXT ("- error, no space in ")
707 ACE_TEXT ("handlers_to_stop_table.\nIncrease ")
708 ACE_TEXT ("HANDLERS_TO_STOP_TABLE_SIZE.\n")),
709 -1);
712 this->handlers_to_stop_[index] = handler;
713 return 0;
716 // Unregister handler, registered before with us for stopping.
718 Stop_Handler::unregister_handler (ACE_Event_Handler *handler)
720 if (!handler)
721 ACE_ERROR_RETURN ((LM_ERROR,
722 ACE_TEXT ("(%P|%t) Stop_Handler::unregister_handler - ")
723 ACE_TEXT ("error, handler is a null pointer.\n")),
724 -1);
726 size_t index = 0;
728 for (index = 0;
729 (index < HANDLERS_TO_STOP_TABLE_SIZE &&
730 handler != this->handlers_to_stop_[index]);
731 ++index)
734 size_t entrance = 0;
735 if (index == HANDLERS_TO_STOP_TABLE_SIZE)
736 ACE_ERROR_RETURN ((LM_ERROR,
737 ACE_TEXT ("(%P|%t) Stop_Handler::unregister_")
738 ACE_TEXT ("handler - error, the handler was not ")
739 ACE_TEXT ("found among registered handlers.\n")),
740 -1);
742 entrance = index;
743 // null the entrance. Nulled entrances cannot be destroyed
744 this->handlers_to_stop_[entrance] = 0;
746 return 0;
750 Repeats_Handler::Repeats_Handler (void)
751 : check_handler_ (0),
752 seconds_timer_ (60),
753 counter_ (0)
757 Repeats_Handler::~Repeats_Handler (void)
759 ACE_DEBUG ((LM_INFO,
760 ACE_TEXT ("(%P|%t) Repeats_Handler::~Repeats_Handler.\n")));
764 Repeats_Handler::open (Echo_Handler * check_handler,
765 ACE_Reactor * const reactor,
766 unsigned int seconds_timer)
768 if (!check_handler)
769 ACE_ERROR_RETURN ((LM_ERROR,
770 ACE_TEXT ("(%P|%t) Repeats_Handler::open - error: ")
771 ACE_TEXT ("NULL check_handler.\n")),
772 -1);
774 this->check_handler_ = check_handler;
776 if (!reactor)
777 ACE_ERROR_RETURN ((LM_ERROR,
778 ACE_TEXT ("(%P|%t) Stop_Handler::open - error: ")
779 ACE_TEXT ("NULL reactor.\n")),
780 -1);
782 this->reactor (reactor);
783 this->seconds_timer_ = seconds_timer;
785 if (this->reactor ()->schedule_timer (
786 this,
788 ACE_Time_Value (1),
789 ACE_Time_Value (this->seconds_timer_)) == -1)
790 ACE_ERROR_RETURN ((LM_ERROR,
791 ACE_TEXT ("(%P|%t) Repeats_Handler::open: %p\n"),
792 ACE_TEXT ("schedule_timer")),
793 -1);
794 return 0;
798 Repeats_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
800 ACE_DEBUG
801 ((LM_INFO,
802 ACE_TEXT ("(%P|%t) Repeats_Handler::handle_close - entered.\n")));
804 this->reactor ()->remove_handler (this,
805 ACE_Event_Handler::ALL_EVENTS_MASK |
806 ACE_Event_Handler::DONT_CALL);
807 return 0;
810 static int one_button_test = 0;
813 Repeats_Handler::handle_timeout (ACE_Time_Value const &,
814 void const *)
816 this->counter_++ ;
817 if (one_button_test && this->counter_ > 3)
819 ACE_OS::raise (SIGINT);
821 if (this->check_handler_)
823 return this->check_handler_->dispatch_echo_checks (true);
826 return -1;
829 // to create core on some UNIX platforms
830 #if defined (ACE_HAS_SIG_C_FUNC)
831 extern "C"
833 #endif /* #if defined (ACE_HAS_SIG_C_FUNC) */
835 #if ! defined (ACE_WIN32)
836 static void sigsegv_handler (int)
838 ACE_OS::abort ();
840 #endif /* #if ! defined (ACE_WIN32) */
842 #if defined (ACE_HAS_SIG_C_FUNC)
844 #endif /* #if defined (ACE_HAS_SIG_C_FUNC) */
846 #if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
847 static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
849 switch (fdwCtrlType)
851 case CTRL_C_EVENT:
852 case CTRL_BREAK_EVENT:
853 case CTRL_SHUTDOWN_EVENT:
854 case CTRL_CLOSE_EVENT:
855 case CTRL_LOGOFF_EVENT:
856 ACE_OS::raise (SIGINT);
857 return TRUE;
859 // Pass other signals to the next handler.
860 default:
861 return FALSE;
864 #endif /* #if defined (ACE_WIN32) */
866 #define MAX_NUMBER_OF_PING_POINTS 16
868 static int number_of_ping_points = 0;
869 static char ping_points_ips [MAX_NUMBER_OF_PING_POINTS][16];
870 static ACE_INET_Addr ping_points_addrs [MAX_NUMBER_OF_PING_POINTS];
871 static char local_ip_to_bind [16];
873 static int wait_echo_reply_timer = 500; // 500 ms to wait is the default
874 static int repeats_seconds_timer = 60; // 60 seconds between repeats
876 static int
877 is_ip_address_local (char const * const ip_to_bind)
879 ACE_INET_Addr *the_addr_array = 0;
880 size_t how_many = 0;
881 int rc = ACE::get_ip_interfaces (how_many, the_addr_array);
883 if (rc != 0)
884 ACE_ERROR_RETURN ((LM_ERROR,
885 ACE_TEXT ("is_ip_address_local: %p\n"),
886 ACE_TEXT ("ACE::get_ip_interfaces")),
887 -1);
889 if (how_many == 0)
890 ACE_ERROR_RETURN ((LM_ERROR,
891 ACE_TEXT ("is_ip_address_local: "),
892 ACE_TEXT ("No interfaces presently configured ")
893 ACE_TEXT ("in the kernel\n")),
894 -1);
896 // debugging messages
897 ACE_DEBUG ((LM_DEBUG,
898 ACE_TEXT ("is_ip_address_local () - there are %d interfaces\n"),
899 how_many));
901 for (size_t i = 0; i < how_many; ++i)
903 ACE_DEBUG ((LM_DEBUG,
904 ACE_TEXT ("\t%s\n"),
905 the_addr_array[i].get_host_addr ()));
908 for (size_t j = 0; j < how_many; ++j)
910 if (!ACE_OS::strcmp (the_addr_array[j].get_host_addr (), ip_to_bind))
912 return 0;
915 return -1;
918 static int
919 parse_args (int argc, ACE_TCHAR *argv[])
921 ACE_OS::memset (ping_points_ips, 0, sizeof ping_points_ips);
922 ACE_OS::memset (local_ip_to_bind, 0, sizeof local_ip_to_bind);
924 if (argc == 1) // one button test
926 one_button_test = 1;
927 repeats_seconds_timer = 2;
928 number_of_ping_points = 1;
930 ACE_OS::strncpy (ping_points_ips [0],
931 "127.0.0.1",
932 sizeof ping_points_ips [0]);
934 ping_points_addrs[0].set ((u_short) 0, ping_points_ips[0]);
935 return 0;
938 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("b:p:t:w:"));
939 int c, counter = 0;
940 ACE_INET_Addr b_temp_addr;
941 ACE_TCHAR *token = 0;
942 while ((c = get_opt ()) != EOF)
944 switch (c)
946 case 'b': // ip-address of the interface to bind to
947 ACE_OS::strncpy (local_ip_to_bind,
948 ACE_TEXT_ALWAYS_CHAR (get_opt.optarg),
949 sizeof local_ip_to_bind);
951 if (!ACE_OS::strlen (local_ip_to_bind) ||
952 b_temp_addr.set ((u_short)0, local_ip_to_bind) != 0)
954 ACE_ERROR ((LM_ERROR,
955 ACE_TEXT ("-b should be followed by a valid ")
956 ACE_TEXT ("IPv4 address.\n")));
957 // print_usage ();
958 return -1;
960 if (is_ip_address_local (local_ip_to_bind) == -1)
962 ACE_ERROR_RETURN ((LM_ERROR,
963 ACE_TEXT ("the -b address (%s) ")
964 ACE_TEXT ("is not a local ")
965 ACE_TEXT ("address of your computer.\n")
966 ACE_TEXT ("\tPlease correct it.\n"),
967 local_ip_to_bind),
968 -1);
970 break;
972 case 'p': // ping-point (target) ip-addresses, separated by ":'"
974 // tokenizing the string
975 for (token = ACE_OS::strtok (get_opt.optarg, ACE_TEXT (":"));
976 token != 0 && counter < MAX_NUMBER_OF_PING_POINTS;
977 token = ACE_OS::strtok (0, ACE_TEXT (":")))
979 if (ping_points_addrs[counter].set ((u_short)0, token) != 0)
980 ACE_ERROR_RETURN
981 ((LM_ERROR,
982 ACE_TEXT ("Error: the address \"%s\" is not ")
983 ACE_TEXT ("a valid IPv4 address.\n"),
984 token),
985 -1);
986 ++number_of_ping_points;
987 ++counter;
989 break;
991 case 't':
992 repeats_seconds_timer = ACE_OS::atoi (get_opt.optarg);
993 break;
995 case 'w':
996 wait_echo_reply_timer = ACE_OS::atoi (get_opt.optarg);
997 break;
999 default:
1000 // return print_usage (argc,argv);
1001 break;
1006 if (!number_of_ping_points)
1008 ACE_ERROR_RETURN ((LM_ERROR,
1009 ACE_TEXT ("Error: no valid IPv4 addresses ")
1010 ACE_TEXT ("were provided, using -p option.\n")),
1011 -1);
1014 return 0;
1018 run_main (int argc, ACE_TCHAR *argv[])
1020 ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test"));
1022 #if defined (ACE_WIN32)
1023 #if !defined (ACE_HAS_WINCE)
1024 SetConsoleCtrlHandler(&CtrlHandler, TRUE);
1025 #endif
1026 #else /* #if defined (ACE_WIN32) */
1027 // Set a handler for SIGSEGV signal to call for abort.
1028 ACE_Sig_Action sa1 ((ACE_SignalHandler) sigsegv_handler, SIGSEGV);
1029 #endif /* #if defined (ACE_WIN32) */
1030 if (::parse_args (argc, argv) == -1)
1032 return -1;
1035 ACE_Reactor * main_reactor = 0;
1036 ACE_NEW_RETURN (main_reactor, ACE_Reactor, -1);
1038 (void) ACE_High_Res_Timer::global_scale_factor ();
1040 // Change the source of time in the reactor to the high-resolution
1041 // timer. Why does this test require such precision for a 1 second
1042 // timer is beyond me ... I think it is a cut&paste error.
1044 // The use of auto_ptr<> is optional, ACE uses dangerous memory
1045 // management idioms everywhere, I thought I could demonstrate how
1046 // to do it right in at least one test. Notice the lack of
1047 // ACE_NEW_RETURN, that monstrosity has no business in proper C++
1048 // code ...
1049 auto_ptr<ACE_Timer_Heap_Variable_Time_Source> tq(
1050 new ACE_Timer_Heap_Variable_Time_Source);
1051 // ... notice how the policy is in the derived timer queue type.
1052 // The abstract timer queue does not have a time policy ...
1053 tq->set_time_policy(&ACE_High_Res_Timer::gettimeofday_hr);
1054 // ... and then the timer queue is replaced. Strangely, the reactor
1055 // does *not* copy the timers, it just deletes the existing timer
1056 // queue ....
1057 main_reactor->timer_queue(tq.get());
1058 // ... the reactor does not assume ownership
1061 * Stop_Handler's is supposed to stop the activity of all
1062 * handlers by a SIGINT signal. We create and activate here an object of
1063 * Stop_Handler and pass an instance of reactor (main_reactor),
1064 * running demultiplexing event loop in the "main thread".
1066 Stop_Handler* stop_handler = 0;
1067 ACE_NEW_RETURN (stop_handler, Stop_Handler (main_reactor), -1);
1068 if (stop_handler->open () == -1)
1070 ACE_ERROR ((LM_ERROR,
1071 ACE_TEXT ("(%P|%t) %p\n"),
1072 ACE_TEXT ("main() - stop_handler->open")));
1073 ACE_OS::exit(-2);
1076 ACE_TCHAR *ping_status = 0;
1077 ACE_NEW_RETURN (ping_status, ACE_TCHAR[number_of_ping_points], -1);
1079 // wait_echo_reply_timer is in msec
1080 int seconds = 0;
1081 int milliseconds = 0;
1082 seconds = wait_echo_reply_timer / 1000;
1083 milliseconds = wait_echo_reply_timer % 1000;
1084 ACE_Time_Value const wait_timer (seconds, milliseconds);
1086 Echo_Handler *ping_handler = 0;
1087 ACE_NEW_RETURN (ping_handler, Echo_Handler, -1);
1089 if (ACE_OS::strlen (local_ip_to_bind))
1091 // We are willing to bind the raw-socket to a certain adapter,
1092 // probably because we are willing to check connectivity/etc
1093 // of the local adapter.
1094 ACE_INET_Addr local_adapter;
1095 local_adapter.set ((u_short) 0, local_ip_to_bind);
1096 if (ping_handler->open (main_reactor,
1097 wait_timer,
1098 ping_points_addrs,
1099 number_of_ping_points,
1100 ping_status,
1101 2, // max_attempts_number
1102 local_adapter) == -1)
1104 int res = 0;
1105 // If this process doesn't have privileges to open a raw socket, log
1106 // a warning instead of an error.
1107 if (errno == EPERM || errno == EACCES)
1109 ACE_ERROR ((LM_WARNING,
1110 ACE_TEXT ("(%P|%t) main() - ping_handler->open: ")
1111 ACE_TEXT ("insufficient privs to run this test\n")));
1113 else
1115 ACE_ERROR ((LM_ERROR,
1116 ACE_TEXT ("(%P|%t) %p\n"),
1117 ACE_TEXT ("main() - ping_handler->open")));
1118 res = -4;
1120 delete ping_handler;
1121 delete [] ping_status;
1122 delete main_reactor;
1123 delete stop_handler;
1125 ACE_END_TEST;
1126 return res;
1129 else
1131 // Binding to a local adapter is not of our interest. We just
1132 // are willing to check all these remote IPs, to monitor, that
1133 // they are alive.
1134 if (ping_handler->open (main_reactor,
1135 wait_timer,
1136 ping_points_addrs,
1137 number_of_ping_points,
1138 ping_status,
1139 2) == -1) // max_attempts_number
1141 int res = 0;
1142 if (errno == EPERM || errno == EACCES)
1144 ACE_ERROR ((LM_WARNING,
1145 ACE_TEXT ("(%P|%t) main() - ping_handler->open: ")
1146 ACE_TEXT ("insufficient privs to run this test\n")));
1148 else
1150 ACE_ERROR ((LM_ERROR,
1151 ACE_TEXT ("(%P|%t) %p\n"),
1152 ACE_TEXT ("main() - ping_handler->open")));
1153 res = -4;
1155 delete ping_handler;
1156 delete [] ping_status;
1157 delete main_reactor;
1158 delete stop_handler;
1160 ACE_END_TEST;
1161 return res;
1165 Repeats_Handler *repeats_handler = 0;
1166 ACE_NEW_RETURN (repeats_handler, Repeats_Handler, -1);
1167 if (repeats_handler->open (ping_handler,
1168 main_reactor,
1169 repeats_seconds_timer) == -1)
1171 ACE_ERROR ((LM_ERROR,
1172 ACE_TEXT ("(%P|%t) %p\n"),
1173 ACE_TEXT ("main() - repeats_handler->open")));
1175 delete repeats_handler;
1176 delete ping_handler;
1177 delete [] ping_status;
1178 delete main_reactor;
1179 delete stop_handler;
1181 ACE_END_TEST;
1182 return -4;
1185 stop_handler->register_handler (repeats_handler);
1186 stop_handler->register_handler (ping_handler);
1188 // Demultiplexing event loop of the main_reactor.
1189 while (main_reactor->reactor_event_loop_done () == 0)
1191 main_reactor->run_reactor_event_loop ();
1194 ACE_DEBUG ((LM_INFO,
1195 ACE_TEXT ("(%P|%t|%T) \"Network_Adapters_Test\" main() - ")
1196 ACE_TEXT ("out of reactor's loop.\n")));
1198 delete repeats_handler;
1199 delete ping_handler;
1200 delete [] ping_status;
1201 delete main_reactor;
1202 delete stop_handler;
1204 ACE_END_TEST;
1205 return 0;
1208 #else
1211 run_main (int, ACE_TCHAR *[])
1213 ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test"));
1215 ACE_DEBUG ((LM_INFO,
1216 ACE_TEXT ("(%P|%t|%T) \"Network_Adapters_Test\" main() - ")
1217 ACE_TEXT ("ICMP support not configured.\n")
1218 ACE_TEXT ("Define ACE_HAS_ICMP_SUPPORT = 1 in your config.h ")
1219 ACE_TEXT ("file to enable.\n")));
1221 ACE_END_TEST;
1223 return 0;
1226 #endif /* ACE_HAS_ICMP_SUPPORT == 1 */