Doxygen changes
[ACE_TAO.git] / ACE / tests / Cached_Accept_Conn_Test.cpp
blob909e5cf31cb16efe49ce8d5b721df47192546303
2 //=============================================================================
3 /**
4 * @file Cached_Accept_Conn_Test.cpp
6 * The test illustrates how the <ACE_Strategy_Connector> works by
7 * showing how you can cache connections on the client using
8 * different caching strategies. Also how connections can be purged
9 * explicitly and implicitly if needed from the connection cache
10 * maintained by the connector. The <ACE_Strategy_Acceptor> can also
11 * explicitly purge connections from the process CONNECTION CACHE on
12 * demand.
14 * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
16 //=============================================================================
19 #ifndef CACHED_ACCEPT_CONNECTION_TEST
20 #define CACHED_ACCEPT_CONNECTION_TEST
22 #include "test_config.h"
24 #include "Cached_Accept_Conn_Test.h"
26 #include "ace/OS_NS_string.h"
27 #include "ace/Get_Opt.h"
29 #if defined(_MSC_VER)
30 #pragma warning(disable:4503)
31 #endif /* _MSC_VER */
33 // Note: To keep both sunCC5.0 without debugging symbols and gcc2.7.3
34 // happy, it was necessary to have the definitions of the methods of
35 // the Accept_Strategy before the instantiations.
37 // HPUX doesn't accept these declaration after their usage.
39 // For some strange reason this must *not* be static since otherwise
40 // certain versions of SunC++ will not link properly.
41 int connection_accepted = 0;
43 // For some strange reason this must *not* be static since otherwise
44 // certain versions of SunC++ will not link properly.
45 int debug = 0;
47 template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1>
48 Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::Accept_Strategy (CACHED_CONNECT_STRATEGY &caching_connect_strategy)
49 : caching_connect_strategy_ (caching_connect_strategy)
53 template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
54 Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::open (const ACE_PEER_ACCEPTOR_ADDR &local_addr,
55 bool restart)
57 int result = ACCEPT_STRATEGY_BASE::open (local_addr, restart);
59 if (result == 0)
60 return result;
62 // If the error occurred due to the fact that the file descriptor
63 // limit was exhausted, then purge the connection cache of some
64 // entries.
65 result = this->out_of_sockets_handler ();
66 if (result == -1)
67 return -1;
69 // If we are able to purge, try again.
70 return ACCEPT_STRATEGY_BASE::open (local_addr, restart);
73 template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
74 Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::accept_svc_handler (SVC_HANDLER *svc_handler)
76 // Stop the event loop.
77 connection_accepted = 1;
79 // Try to find out if the implementation of the reactor that we are
80 // using requires us to reset the event association for the newly
81 // created handle. This is because the newly created handle will
82 // inherit the properties of the listen handle, including its event
83 // associations.
84 int reset_new_handle = this->reactor_->uses_event_associations ();
86 int result = this->acceptor ().accept (svc_handler->peer (), // stream
87 0, // remote address
88 0, // timeout
89 1, // restart
90 reset_new_handle // reset new handler
92 if (result == 0)
94 if (debug)
95 ACE_DEBUG ((LM_DEBUG,
96 ACE_TEXT ("Accept succeeded with handle %d\n"),
97 svc_handler->get_handle ()));
98 return result;
101 // If the error occurred due to the fact that the file descriptor
102 // limit was exhausted, then purge the connection cache of some
103 // entries.
104 if (0 != this->out_of_sockets_handler ())
105 ACE_ERROR ((LM_ERROR,
106 ACE_TEXT ("%p\n"),
107 ACE_TEXT ("out_of_sockets_handler")));
109 // Close down handler to avoid memory leaks.
110 svc_handler->close (0);
111 return -1;
114 template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
115 Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::out_of_sockets_handler (void)
117 if (ACE::out_of_handles (errno))
119 // Close connections which are cached by explicitly purging the
120 // connection cache maintained by the connector.
121 ACE_DEBUG ((LM_DEBUG,
122 ACE_TEXT ("Purging connections from Connection Cache...\n")));
124 return this->caching_connect_strategy_.purge_connections ();
127 return -1;
130 typedef Accept_Strategy<Server_Svc_Handler, ACE_SOCK_ACCEPTOR>
131 ACCEPT_STRATEGY;
133 Client_Svc_Handler::Client_Svc_Handler (ACE_Thread_Manager *t)
134 : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
139 Client_Svc_Handler::open (void *)
141 if (debug)
142 ACE_DEBUG ((LM_DEBUG,
143 ACE_TEXT ("opening Client_Svc_Handler %@ with handle %d\n"),
144 this,
145 this->peer ().get_handle ()));
146 return 0;
150 Client_Svc_Handler::close (u_long flags)
152 ACE_DEBUG ((LM_DEBUG,
153 ACE_TEXT ("Closing Client_Svc_Handler %@ with handle %d\n"),
154 this,
155 this->peer ().get_handle ()));
156 return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::close (flags);
160 Server_Svc_Handler::Server_Svc_Handler (ACE_Thread_Manager *t)
161 : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
166 Server_Svc_Handler::open (void *)
168 if (debug)
169 ACE_DEBUG ((LM_DEBUG,
170 ACE_TEXT ("opening Server_Svc_Handler %@ with handle %d\n"),
171 this,
172 this->peer ().get_handle ()));
174 return this->close ();
177 enum Caching_Strategy_Type
179 ACE_LFU,
180 ACE_FIFO,
181 ACE_LRU,
182 ACE_NULL,
183 ACE_ALL
186 // Default number of clients/servers.
187 static int listen_once = 1;
188 static int user_has_specified_iterations = 0;
189 static size_t keep_handles_available = 100;
190 static double purge_percentage = 20;
191 static Caching_Strategy_Type caching_strategy_type = ACE_ALL;
193 // On Win32, the handle gobbling doesn't work. Therefore, we need
194 // more iterations to get to the handle limit.
195 #if defined (ACE_WIN32)
196 static int iterations = 2000;
197 #else
198 static int iterations = 200;
199 #endif /* ACE_WIN32 */
202 static int
203 cached_connect (STRATEGY_CONNECTOR &con,
204 const ACE_INET_Addr &server_addr)
206 // This will make sure we get the host information correct.
207 ACE_INET_Addr remote_addr (server_addr.get_port_number (),
208 ACE_LOCALHOST);
210 // Perform a blocking connect to the server using the Strategy
211 // Connector with a connection caching strategy.
212 Client_Svc_Handler *svc_handler = 0;
213 int result = con.connect (svc_handler,
214 remote_addr);
215 if (result == -1)
216 ACE_ERROR_RETURN ((LM_ERROR,
217 ACE_TEXT ("%p\n"),
218 ACE_TEXT ("connection failed")),
219 -1);
220 else
221 if (debug)
222 ACE_DEBUG ((LM_DEBUG,
223 ACE_TEXT ("Connection successful to server at port %d!\n"),
224 remote_addr.get_port_number ()));
226 // Reset Svc_Handler state.
227 svc_handler->recycle_state (ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE);
229 return 0;
232 static void
233 server (void)
235 int result = 1;
237 while (connection_accepted == 0)
238 result = ACE_Reactor::instance ()->handle_events ();
240 connection_accepted = 0;
242 ACE_UNUSED_ARG (result);
245 static void
246 test_connection_management (CACHING_STRATEGY &caching_strategy)
248 // Configure the Strategy Connector with a strategy that caches
249 // connection.
250 CACHED_CONNECT_STRATEGY caching_connect_strategy (caching_strategy);
252 NULL_CREATION_STRATEGY creation_strategy;
253 NULL_ACTIVATION_STRATEGY activation_strategy;
255 STRATEGY_CONNECTOR strategy_connector (0,
256 &creation_strategy,
257 &caching_connect_strategy,
258 &activation_strategy);
260 // Connect strategy is required by the <out_of_sockets_handler>.
261 ACCEPT_STRATEGY listen_one_time_accept_strategy (caching_connect_strategy);
263 // If <listen_once> is true, only one Acceptor is used for the test.
264 ACCEPTOR listen_one_time_acceptor;
265 ACE_INET_Addr server_addr;
267 int result =
268 listen_one_time_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &),
269 ACE_Reactor::instance (),
271 &listen_one_time_accept_strategy);
272 if (result != 0)
274 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor open")));
275 return;
278 result = listen_one_time_acceptor.acceptor ().get_local_addr (server_addr);
279 if (result != 0)
281 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor getaddr")));
282 listen_one_time_acceptor.close ();
283 return;
286 for (int i = 1; i <= iterations; ++i)
288 ACE_DEBUG ((LM_DEBUG,
289 ACE_TEXT ("%T iteration %d\n"),
290 i));
292 // Connect strategy is required by the <out_of_sockets_handler>.
293 ACCEPT_STRATEGY listen_multiple_times_accept_strategy (caching_connect_strategy);
295 // If <listen_once> is false, one Acceptor is used for every
296 // iteration.
297 ACCEPTOR listen_multiple_times_acceptor;
299 if (!listen_once)
301 // Bind acceptor to any port and then find out what the port
302 // was.
303 if (listen_multiple_times_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &),
304 ACE_Reactor::instance (),
306 &listen_multiple_times_accept_strategy) == -1)
308 ACE_ERROR ((LM_ERROR,
309 ACE_TEXT ("%p\n"),
310 ACE_TEXT ("open")));
311 break;
314 if (listen_multiple_times_acceptor.acceptor ().get_local_addr (server_addr) == -1)
316 ACE_ERROR ((LM_ERROR,
317 ACE_TEXT ("%p\n"),
318 ACE_TEXT ("get_local_addr")));
319 break;
324 if (debug)
325 ACE_DEBUG ((LM_DEBUG,
326 ACE_TEXT ("starting server at port %d\n"),
327 server_addr.get_port_number ()));
329 // Run the cached blocking test.
330 if (-1 == cached_connect (strategy_connector, server_addr))
331 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("cached_connect")));
332 else
333 server ();
337 void
338 test_caching_strategy_type (void)
340 CACHING_STRATEGY *caching_strategy = 0;
342 switch (caching_strategy_type)
344 case ACE_NULL:
345 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
346 ACE_NEW (caching_strategy,
347 NULL_CACHING_STRATEGY_ADAPTER);
348 break;
350 case ACE_LRU:
351 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
352 ACE_NEW (caching_strategy,
353 LRU_CACHING_STRATEGY_ADAPTER);
354 break;
356 case ACE_LFU:
357 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
358 ACE_NEW (caching_strategy,
359 LFU_CACHING_STRATEGY_ADAPTER);
360 break;
362 case ACE_FIFO:
363 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
364 ACE_NEW (caching_strategy,
365 FIFO_CACHING_STRATEGY_ADAPTER);
366 break;
368 case ACE_ALL: // Just to remove warnings!
369 break;
372 caching_strategy->purge_percent (purge_percentage);
373 test_connection_management (*caching_strategy);
374 delete caching_strategy;
378 parse_args (int argc, ACE_TCHAR *argv[])
380 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("l:i:p:c:a:d"));
382 int cc;
384 while ((cc = get_opt ()) != -1)
385 switch (cc)
387 case 'd':
388 debug = 1;
389 break;
390 case 'l':
391 listen_once = ACE_OS::atoi (get_opt.opt_arg ());
392 break;
393 case 'i':
394 iterations = ACE_OS::atoi (get_opt.opt_arg ());
395 user_has_specified_iterations = 1;
396 break;
397 case 'p':
398 purge_percentage = ACE_OS::atoi (get_opt.opt_arg ());
399 break;
400 case 'c':
401 // Note that if null caching strategy is used then this test
402 // will fail if the number of servers exceed number of open
403 // files allowed for the process.
404 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("null")) == 0)
405 caching_strategy_type = ACE_NULL;
406 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lru")) == 0)
407 caching_strategy_type = ACE_LRU;
408 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lfu")) == 0)
409 caching_strategy_type = ACE_LFU;
410 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("fifo")) == 0)
411 caching_strategy_type = ACE_FIFO;
412 break;
413 case 'a':
414 keep_handles_available = ACE_OS::atoi (get_opt.opt_arg ());
415 break;
416 case '?':
417 case 'h':
418 default:
419 ACE_ERROR ((LM_ERROR,
420 ACE_TEXT ("usage: %s ")
421 ACE_TEXT ("[-t (timeout)] ")
422 ACE_TEXT ("[-c (caching strategy: lru / lfu / fifo / null [default = all])] ")
423 ACE_TEXT ("[-i (iterations)] ")
424 ACE_TEXT ("[-l (listen once)] ")
425 ACE_TEXT ("[-d (addition debugging output)] ")
426 ACE_TEXT ("[-p (purge percent)] ")
427 ACE_TEXT ("[-a (keep handles available)] "),
428 ACE_TEXT ("Cached_Accept_Conn_Test")));
429 return -1;
432 return 0;
436 run_main (int argc, ACE_TCHAR *argv[])
438 // Validate options.
439 int result = parse_args (argc, argv);
440 if (result != 0)
441 return result;
443 #if defined (ACE_WIN32)
444 // Somehow, on Win32, the <listen once> option allows us to create
445 // more handles.
446 if (!user_has_specified_iterations &&
447 listen_once)
448 iterations *= 2;
449 #endif /* ACE_WIN32 */
451 // Start the test only if options are valid.
452 ACE_START_TEST (ACE_TEXT ("Cached_Accept_Conn_Test"));
454 // Remove the extra debugging attributes from Log_Msg output.
455 ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
457 // The reactor's constructor changes the handle limit for the
458 // process.
459 ACE_Reactor::instance ();
461 // Consume all handles in the process, leaving us
462 // <keep_handles_available> to play with.
463 ACE_Handle_Gobbler handle_gobbler;
464 if (0 != handle_gobbler.consume_handles (keep_handles_available))
465 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("handle_gobbler")));
467 // Do we need to test all the strategies. Note, that the less
468 // useful null strategy is ignored in this case.
469 if (caching_strategy_type == ACE_ALL)
471 caching_strategy_type = ACE_LRU;
472 test_caching_strategy_type ();
474 // Default iterations are too many; if the user hasn't specified
475 // otherwise, we'll shrink the iterations for LFU and FIFO.
476 if (!user_has_specified_iterations)
477 iterations /= 100;
479 caching_strategy_type = ACE_LFU;
480 test_caching_strategy_type ();
482 caching_strategy_type = ACE_FIFO;
483 test_caching_strategy_type ();
485 else
487 test_caching_strategy_type ();
490 ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
492 ACE_END_TEST;
493 return 0;
497 #endif /* CACHED_ACCEPT_CONNECTION_TEST */