ACE+TAO-7_0_8
[ACE_TAO.git] / ACE / tests / Network_Adapters_Test.cpp
blobe42fc226182bc25a1396221a70f1bedb971e9423
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 ()
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
619 this->reactor ()->cancel_timer (this->handlers_to_stop_[i]);
620 this->reactor ()->remove_handler
621 (this->handlers_to_stop_[i],
622 ACE_Event_Handler::ALL_EVENTS_MASK
623 | ACE_Event_Handler::DONT_CALL);
625 catch (...)
627 ACE_ERROR ((LM_ERROR,
628 ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - ")
629 ACE_TEXT ("EXCEPTION CATCHED. Most probably ")
630 ACE_TEXT ("handler's pointer has been deleted.\n")));
632 this->handlers_to_stop_[i] = 0;
636 this->reactor ()->remove_handler (this->registered_signals_);
638 if (reactor ()->end_reactor_event_loop () == -1)
640 ACE_ERROR_RETURN ((LM_DEBUG,
641 ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal:%p\n"),
642 ACE_TEXT ("end_reactor_event_loop")),
643 -1);
646 ACE_DEBUG ((LM_INFO,
647 ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - completed.\n")));
648 return 0;
652 Stop_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask m)
654 ACE_DEBUG ((LM_INFO,
655 ACE_TEXT ("(%P|%t) Stop_Handler::handle_close - entered.\n")));
656 if (m == ACE_Event_Handler::SIGNAL_MASK)
657 return 0;
658 this->reactor ()->remove_handler (this,
659 ACE_Event_Handler::SIGNAL_MASK |
660 ACE_Event_Handler::DONT_CALL);
662 if (reactor ()->end_reactor_event_loop () == -1)
663 ACE_ERROR_RETURN ((LM_DEBUG,
664 ACE_TEXT ("Stop_Handler::handle_close: %p\n"),
665 ACE_TEXT ("end_reactor_event_loop")),
666 -1);
667 return 0;
671 Stop_Handler::handle_timeout (ACE_Time_Value const &,
672 void const *)
674 return 0;
677 // Register handler with us for stopping.
679 Stop_Handler::register_handler (ACE_Event_Handler *handler)
681 if (!handler)
682 ACE_ERROR_RETURN ((LM_ERROR,
683 ACE_TEXT ("(%P|%t) Stop_Handler::register_handler - ")
684 ACE_TEXT ("error, handler is a null pointer.\n")),
685 -1);
687 size_t index = 0;
689 for (index = 0;
690 (index < HANDLERS_TO_STOP_TABLE_SIZE &&
691 this->handlers_to_stop_[index]);
692 ++index)
695 if (index == HANDLERS_TO_STOP_TABLE_SIZE)
697 ACE_ERROR_RETURN ((LM_ERROR,
698 ACE_TEXT ("(%P|%t) Stop_Handler::register_handler ")
699 ACE_TEXT ("- error, no space in ")
700 ACE_TEXT ("handlers_to_stop_table.\nIncrease ")
701 ACE_TEXT ("HANDLERS_TO_STOP_TABLE_SIZE.\n")),
702 -1);
705 this->handlers_to_stop_[index] = handler;
706 return 0;
709 // Unregister handler, registered before with us for stopping.
711 Stop_Handler::unregister_handler (ACE_Event_Handler *handler)
713 if (!handler)
714 ACE_ERROR_RETURN ((LM_ERROR,
715 ACE_TEXT ("(%P|%t) Stop_Handler::unregister_handler - ")
716 ACE_TEXT ("error, handler is a null pointer.\n")),
717 -1);
719 size_t index = 0;
721 for (index = 0;
722 (index < HANDLERS_TO_STOP_TABLE_SIZE &&
723 handler != this->handlers_to_stop_[index]);
724 ++index)
727 size_t entrance = 0;
728 if (index == HANDLERS_TO_STOP_TABLE_SIZE)
729 ACE_ERROR_RETURN ((LM_ERROR,
730 ACE_TEXT ("(%P|%t) Stop_Handler::unregister_")
731 ACE_TEXT ("handler - error, the handler was not ")
732 ACE_TEXT ("found among registered handlers.\n")),
733 -1);
735 entrance = index;
736 // null the entrance. Nulled entrances cannot be destroyed
737 this->handlers_to_stop_[entrance] = 0;
739 return 0;
743 Repeats_Handler::Repeats_Handler ()
744 : check_handler_ (0),
745 seconds_timer_ (60),
746 counter_ (0)
750 Repeats_Handler::~Repeats_Handler ()
752 ACE_DEBUG ((LM_INFO,
753 ACE_TEXT ("(%P|%t) Repeats_Handler::~Repeats_Handler.\n")));
757 Repeats_Handler::open (Echo_Handler * check_handler,
758 ACE_Reactor * const reactor,
759 unsigned int seconds_timer)
761 if (!check_handler)
762 ACE_ERROR_RETURN ((LM_ERROR,
763 ACE_TEXT ("(%P|%t) Repeats_Handler::open - error: ")
764 ACE_TEXT ("NULL check_handler.\n")),
765 -1);
767 this->check_handler_ = check_handler;
769 if (!reactor)
770 ACE_ERROR_RETURN ((LM_ERROR,
771 ACE_TEXT ("(%P|%t) Stop_Handler::open - error: ")
772 ACE_TEXT ("NULL reactor.\n")),
773 -1);
775 this->reactor (reactor);
776 this->seconds_timer_ = seconds_timer;
778 if (this->reactor ()->schedule_timer (
779 this,
781 ACE_Time_Value (1),
782 ACE_Time_Value (this->seconds_timer_)) == -1)
783 ACE_ERROR_RETURN ((LM_ERROR,
784 ACE_TEXT ("(%P|%t) Repeats_Handler::open: %p\n"),
785 ACE_TEXT ("schedule_timer")),
786 -1);
787 return 0;
791 Repeats_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
793 ACE_DEBUG
794 ((LM_INFO,
795 ACE_TEXT ("(%P|%t) Repeats_Handler::handle_close - entered.\n")));
797 this->reactor ()->remove_handler (this,
798 ACE_Event_Handler::ALL_EVENTS_MASK |
799 ACE_Event_Handler::DONT_CALL);
800 return 0;
803 static int one_button_test = 0;
806 Repeats_Handler::handle_timeout (ACE_Time_Value const &,
807 void const *)
809 this->counter_++ ;
810 if (one_button_test && this->counter_ > 3)
812 ACE_OS::raise (SIGINT);
814 if (this->check_handler_)
816 return this->check_handler_->dispatch_echo_checks (true);
819 return -1;
822 // to create core on some UNIX platforms
823 #if defined (ACE_HAS_SIG_C_FUNC)
824 extern "C"
826 #endif /* #if defined (ACE_HAS_SIG_C_FUNC) */
828 #if ! defined (ACE_WIN32)
829 static void sigsegv_handler (int)
831 ACE_OS::abort ();
833 #endif /* #if ! defined (ACE_WIN32) */
835 #if defined (ACE_HAS_SIG_C_FUNC)
837 #endif /* #if defined (ACE_HAS_SIG_C_FUNC) */
839 #if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
840 static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
842 switch (fdwCtrlType)
844 case CTRL_C_EVENT:
845 case CTRL_BREAK_EVENT:
846 case CTRL_SHUTDOWN_EVENT:
847 case CTRL_CLOSE_EVENT:
848 case CTRL_LOGOFF_EVENT:
849 ACE_OS::raise (SIGINT);
850 return TRUE;
852 // Pass other signals to the next handler.
853 default:
854 return FALSE;
857 #endif /* #if defined (ACE_WIN32) */
859 #define MAX_NUMBER_OF_PING_POINTS 16
861 static int number_of_ping_points = 0;
862 static char ping_points_ips [MAX_NUMBER_OF_PING_POINTS][16];
863 static ACE_INET_Addr ping_points_addrs [MAX_NUMBER_OF_PING_POINTS];
864 static char local_ip_to_bind [16];
866 static int wait_echo_reply_timer = 500; // 500 ms to wait is the default
867 static int repeats_seconds_timer = 60; // 60 seconds between repeats
869 static int
870 is_ip_address_local (char const * const ip_to_bind)
872 ACE_INET_Addr *the_addr_array = 0;
873 size_t how_many = 0;
874 int rc = ACE::get_ip_interfaces (how_many, the_addr_array);
876 if (rc != 0)
877 ACE_ERROR_RETURN ((LM_ERROR,
878 ACE_TEXT ("is_ip_address_local: %p\n"),
879 ACE_TEXT ("ACE::get_ip_interfaces")),
880 -1);
882 if (how_many == 0)
883 ACE_ERROR_RETURN ((LM_ERROR,
884 ACE_TEXT ("is_ip_address_local: "),
885 ACE_TEXT ("No interfaces presently configured ")
886 ACE_TEXT ("in the kernel\n")),
887 -1);
889 // debugging messages
890 ACE_DEBUG ((LM_DEBUG,
891 ACE_TEXT ("is_ip_address_local () - there are %d interfaces\n"),
892 how_many));
894 for (size_t i = 0; i < how_many; ++i)
896 ACE_DEBUG ((LM_DEBUG,
897 ACE_TEXT ("\t%s\n"),
898 the_addr_array[i].get_host_addr ()));
901 for (size_t j = 0; j < how_many; ++j)
903 if (!ACE_OS::strcmp (the_addr_array[j].get_host_addr (), ip_to_bind))
905 return 0;
908 return -1;
911 static int
912 parse_args (int argc, ACE_TCHAR *argv[])
914 ACE_OS::memset (ping_points_ips, 0, sizeof ping_points_ips);
915 ACE_OS::memset (local_ip_to_bind, 0, sizeof local_ip_to_bind);
917 if (argc == 1) // one button test
919 one_button_test = 1;
920 repeats_seconds_timer = 2;
921 number_of_ping_points = 1;
923 ACE_OS::strncpy (ping_points_ips [0],
924 "127.0.0.1",
925 sizeof ping_points_ips [0]);
927 ping_points_addrs[0].set ((u_short) 0, ping_points_ips[0]);
928 return 0;
931 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("b:p:t:w:"));
932 int c, counter = 0;
933 ACE_INET_Addr b_temp_addr;
934 ACE_TCHAR *token = 0;
935 while ((c = get_opt ()) != EOF)
937 switch (c)
939 case 'b': // ip-address of the interface to bind to
940 ACE_OS::strncpy (local_ip_to_bind,
941 ACE_TEXT_ALWAYS_CHAR (get_opt.optarg),
942 sizeof local_ip_to_bind);
944 if (!ACE_OS::strlen (local_ip_to_bind) ||
945 b_temp_addr.set ((u_short)0, local_ip_to_bind) != 0)
947 ACE_ERROR ((LM_ERROR,
948 ACE_TEXT ("-b should be followed by a valid ")
949 ACE_TEXT ("IPv4 address.\n")));
950 // print_usage ();
951 return -1;
953 if (is_ip_address_local (local_ip_to_bind) == -1)
955 ACE_ERROR_RETURN ((LM_ERROR,
956 ACE_TEXT ("the -b address (%s) ")
957 ACE_TEXT ("is not a local ")
958 ACE_TEXT ("address of your computer.\n")
959 ACE_TEXT ("\tPlease correct it.\n"),
960 local_ip_to_bind),
961 -1);
963 break;
965 case 'p': // ping-point (target) ip-addresses, separated by ":'"
967 // tokenizing the string
968 for (token = ACE_OS::strtok (get_opt.optarg, ACE_TEXT (":"));
969 token != 0 && counter < MAX_NUMBER_OF_PING_POINTS;
970 token = ACE_OS::strtok (0, ACE_TEXT (":")))
972 if (ping_points_addrs[counter].set ((u_short)0, token) != 0)
973 ACE_ERROR_RETURN
974 ((LM_ERROR,
975 ACE_TEXT ("Error: the address \"%s\" is not ")
976 ACE_TEXT ("a valid IPv4 address.\n"),
977 token),
978 -1);
979 ++number_of_ping_points;
980 ++counter;
982 break;
984 case 't':
985 repeats_seconds_timer = ACE_OS::atoi (get_opt.optarg);
986 break;
988 case 'w':
989 wait_echo_reply_timer = ACE_OS::atoi (get_opt.optarg);
990 break;
992 default:
993 // return print_usage (argc,argv);
994 break;
999 if (!number_of_ping_points)
1001 ACE_ERROR_RETURN ((LM_ERROR,
1002 ACE_TEXT ("Error: no valid IPv4 addresses ")
1003 ACE_TEXT ("were provided, using -p option.\n")),
1004 -1);
1007 return 0;
1011 run_main (int argc, ACE_TCHAR *argv[])
1013 ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test"));
1015 #if defined (ACE_WIN32)
1016 #if !defined (ACE_HAS_WINCE)
1017 SetConsoleCtrlHandler(&CtrlHandler, TRUE);
1018 #endif
1019 #else /* #if defined (ACE_WIN32) */
1020 // Set a handler for SIGSEGV signal to call for abort.
1021 ACE_Sig_Action sa1 ((ACE_SignalHandler) sigsegv_handler, SIGSEGV);
1022 #endif /* #if defined (ACE_WIN32) */
1023 if (::parse_args (argc, argv) == -1)
1025 return -1;
1028 ACE_Reactor * main_reactor = 0;
1029 ACE_NEW_RETURN (main_reactor, ACE_Reactor, -1);
1031 (void) ACE_High_Res_Timer::global_scale_factor ();
1033 // Change the source of time in the reactor to the high-resolution
1034 // timer. Why does this test require such precision for a 1 second
1035 // timer is beyond me ... I think it is a cut&paste error.
1037 // The use of auto_ptr<> is optional, ACE uses dangerous memory
1038 // management idioms everywhere, I thought I could demonstrate how
1039 // to do it right in at least one test. Notice the lack of
1040 // ACE_NEW_RETURN, that monstrosity has no business in proper C++
1041 // code ...
1042 std::unique_ptr<ACE_Timer_Heap_Variable_Time_Source> tq(
1043 new ACE_Timer_Heap_Variable_Time_Source);
1044 // ... notice how the policy is in the derived timer queue type.
1045 // The abstract timer queue does not have a time policy ...
1046 tq->set_time_policy(&ACE_High_Res_Timer::gettimeofday_hr);
1047 // ... and then the timer queue is replaced. Strangely, the reactor
1048 // does *not* copy the timers, it just deletes the existing timer
1049 // queue ....
1050 main_reactor->timer_queue(tq.get());
1051 // ... the reactor does not assume ownership
1054 * Stop_Handler's is supposed to stop the activity of all
1055 * handlers by a SIGINT signal. We create and activate here an object of
1056 * Stop_Handler and pass an instance of reactor (main_reactor),
1057 * running demultiplexing event loop in the "main thread".
1059 Stop_Handler* stop_handler = 0;
1060 ACE_NEW_RETURN (stop_handler, Stop_Handler (main_reactor), -1);
1061 if (stop_handler->open () == -1)
1063 ACE_ERROR ((LM_ERROR,
1064 ACE_TEXT ("(%P|%t) %p\n"),
1065 ACE_TEXT ("main() - stop_handler->open")));
1066 ACE_OS::exit(-2);
1069 ACE_TCHAR *ping_status = 0;
1070 ACE_NEW_RETURN (ping_status, ACE_TCHAR[number_of_ping_points], -1);
1072 // wait_echo_reply_timer is in msec
1073 int seconds = 0;
1074 int milliseconds = 0;
1075 seconds = wait_echo_reply_timer / 1000;
1076 milliseconds = wait_echo_reply_timer % 1000;
1077 ACE_Time_Value const wait_timer (seconds, milliseconds);
1079 Echo_Handler *ping_handler = 0;
1080 ACE_NEW_RETURN (ping_handler, Echo_Handler, -1);
1082 if (ACE_OS::strlen (local_ip_to_bind))
1084 // We are willing to bind the raw-socket to a certain adapter,
1085 // probably because we are willing to check connectivity/etc
1086 // of the local adapter.
1087 ACE_INET_Addr local_adapter;
1088 local_adapter.set ((u_short) 0, local_ip_to_bind);
1089 if (ping_handler->open (main_reactor,
1090 wait_timer,
1091 ping_points_addrs,
1092 number_of_ping_points,
1093 ping_status,
1094 2, // max_attempts_number
1095 local_adapter) == -1)
1097 int res = 0;
1098 // If this process doesn't have privileges to open a raw socket, log
1099 // a warning instead of an error.
1100 if (errno == EPERM || errno == EACCES)
1102 ACE_ERROR ((LM_WARNING,
1103 ACE_TEXT ("(%P|%t) main() - ping_handler->open: ")
1104 ACE_TEXT ("insufficient privs to run this test\n")));
1106 else
1108 ACE_ERROR ((LM_ERROR,
1109 ACE_TEXT ("(%P|%t) %p\n"),
1110 ACE_TEXT ("main() - ping_handler->open")));
1111 res = -4;
1113 delete ping_handler;
1114 delete [] ping_status;
1115 delete main_reactor;
1116 delete stop_handler;
1118 ACE_END_TEST;
1119 return res;
1122 else
1124 // Binding to a local adapter is not of our interest. We just
1125 // are willing to check all these remote IPs, to monitor, that
1126 // they are alive.
1127 if (ping_handler->open (main_reactor,
1128 wait_timer,
1129 ping_points_addrs,
1130 number_of_ping_points,
1131 ping_status,
1132 2) == -1) // max_attempts_number
1134 int res = 0;
1135 if (errno == EPERM || errno == EACCES)
1137 ACE_ERROR ((LM_WARNING,
1138 ACE_TEXT ("(%P|%t) main() - ping_handler->open: ")
1139 ACE_TEXT ("insufficient privs to run this test\n")));
1141 else
1143 ACE_ERROR ((LM_ERROR,
1144 ACE_TEXT ("(%P|%t) %p\n"),
1145 ACE_TEXT ("main() - ping_handler->open")));
1146 res = -4;
1148 delete ping_handler;
1149 delete [] ping_status;
1150 delete main_reactor;
1151 delete stop_handler;
1153 ACE_END_TEST;
1154 return res;
1158 Repeats_Handler *repeats_handler = 0;
1159 ACE_NEW_RETURN (repeats_handler, Repeats_Handler, -1);
1160 if (repeats_handler->open (ping_handler,
1161 main_reactor,
1162 repeats_seconds_timer) == -1)
1164 ACE_ERROR ((LM_ERROR,
1165 ACE_TEXT ("(%P|%t) %p\n"),
1166 ACE_TEXT ("main() - repeats_handler->open")));
1168 delete repeats_handler;
1169 delete ping_handler;
1170 delete [] ping_status;
1171 delete main_reactor;
1172 delete stop_handler;
1174 ACE_END_TEST;
1175 return -4;
1178 stop_handler->register_handler (repeats_handler);
1179 stop_handler->register_handler (ping_handler);
1181 // Demultiplexing event loop of the main_reactor.
1182 while (main_reactor->reactor_event_loop_done () == 0)
1184 main_reactor->run_reactor_event_loop ();
1187 ACE_DEBUG ((LM_INFO,
1188 ACE_TEXT ("(%P|%t|%T) \"Network_Adapters_Test\" main() - ")
1189 ACE_TEXT ("out of reactor's loop.\n")));
1191 delete repeats_handler;
1192 delete ping_handler;
1193 delete [] ping_status;
1194 delete main_reactor;
1195 delete stop_handler;
1197 ACE_END_TEST;
1198 return 0;
1201 #else
1204 run_main (int, ACE_TCHAR *[])
1206 ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test"));
1208 ACE_DEBUG ((LM_INFO,
1209 ACE_TEXT ("(%P|%t|%T) \"Network_Adapters_Test\" main() - ")
1210 ACE_TEXT ("ICMP support not configured.\n")
1211 ACE_TEXT ("Define ACE_HAS_ICMP_SUPPORT = 1 in your config.h ")
1212 ACE_TEXT ("file to enable.\n")));
1214 ACE_END_TEST;
1216 return 0;
1219 #endif /* ACE_HAS_ICMP_SUPPORT == 1 */