Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / tests / Cached_Accept_Conn_Test.cpp
blob71c07ca733c762bae1b8c535bd0ab794ad5a44af
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 int connection_accepted = 0;
34 int debug = 0;
36 template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1>
37 Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::Accept_Strategy (CACHED_CONNECT_STRATEGY &caching_connect_strategy)
38 : caching_connect_strategy_ (caching_connect_strategy)
42 template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
43 Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::open (const ACE_PEER_ACCEPTOR_ADDR &local_addr,
44 bool restart)
46 int result = ACCEPT_STRATEGY_BASE::open (local_addr, restart);
48 if (result == 0)
49 return result;
51 // If the error occurred due to the fact that the file descriptor
52 // limit was exhausted, then purge the connection cache of some
53 // entries.
54 result = this->out_of_sockets_handler ();
55 if (result == -1)
56 return -1;
58 // If we are able to purge, try again.
59 return ACCEPT_STRATEGY_BASE::open (local_addr, restart);
62 template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
63 Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::accept_svc_handler (SVC_HANDLER *svc_handler)
65 // Stop the event loop.
66 connection_accepted = 1;
68 // Try to find out if the implementation of the reactor that we are
69 // using requires us to reset the event association for the newly
70 // created handle. This is because the newly created handle will
71 // inherit the properties of the listen handle, including its event
72 // associations.
73 int reset_new_handle = this->reactor_->uses_event_associations ();
75 int result = this->acceptor ().accept (svc_handler->peer (), // stream
76 0, // remote address
77 0, // timeout
78 1, // restart
79 reset_new_handle // reset new handler
81 if (result == 0)
83 if (debug)
84 ACE_DEBUG ((LM_DEBUG,
85 ACE_TEXT ("Accept succeeded with handle %d\n"),
86 svc_handler->get_handle ()));
87 return result;
90 // If the error occurred due to the fact that the file descriptor
91 // limit was exhausted, then purge the connection cache of some
92 // entries.
93 if (0 != this->out_of_sockets_handler ())
94 ACE_ERROR ((LM_ERROR,
95 ACE_TEXT ("%p\n"),
96 ACE_TEXT ("out_of_sockets_handler")));
98 // Close down handler to avoid memory leaks.
99 svc_handler->close (0);
100 return -1;
103 template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
104 Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::out_of_sockets_handler ()
106 if (ACE::out_of_handles (errno))
108 // Close connections which are cached by explicitly purging the
109 // connection cache maintained by the connector.
110 ACE_DEBUG ((LM_DEBUG,
111 ACE_TEXT ("Purging connections from Connection Cache...\n")));
113 return this->caching_connect_strategy_.purge_connections ();
116 return -1;
119 using ACCEPT_STRATEGY = Accept_Strategy<Server_Svc_Handler, ACE_SOCK_Acceptor>;
121 Client_Svc_Handler::Client_Svc_Handler (ACE_Thread_Manager *t)
122 : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
127 Client_Svc_Handler::open (void *)
129 if (debug)
130 ACE_DEBUG ((LM_DEBUG,
131 ACE_TEXT ("opening Client_Svc_Handler %@ with handle %d\n"),
132 this,
133 this->peer ().get_handle ()));
134 return 0;
138 Client_Svc_Handler::close (u_long flags)
140 ACE_DEBUG ((LM_DEBUG,
141 ACE_TEXT ("Closing Client_Svc_Handler %@ with handle %d\n"),
142 this,
143 this->peer ().get_handle ()));
144 return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::close (flags);
148 Server_Svc_Handler::Server_Svc_Handler (ACE_Thread_Manager *t)
149 : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
154 Server_Svc_Handler::open (void *)
156 if (debug)
157 ACE_DEBUG ((LM_DEBUG,
158 ACE_TEXT ("opening Server_Svc_Handler %@ with handle %d\n"),
159 this,
160 this->peer ().get_handle ()));
162 return this->close ();
165 enum Caching_Strategy_Type
167 ACE_LFU,
168 ACE_FIFO,
169 ACE_LRU,
170 ACE_NULL,
171 ACE_ALL
174 // Default number of clients/servers.
175 static int listen_once = 1;
176 static int user_has_specified_iterations = 0;
177 static size_t keep_handles_available = 100;
178 static double purge_percentage = 20;
179 static Caching_Strategy_Type caching_strategy_type = ACE_ALL;
181 // On Win32, the handle gobbling doesn't work. Therefore, we need
182 // more iterations to get to the handle limit.
183 #if defined (ACE_WIN32)
184 static int iterations = 2000;
185 #else
186 static int iterations = 200;
187 #endif /* ACE_WIN32 */
190 static int
191 cached_connect (STRATEGY_CONNECTOR &con,
192 const ACE_INET_Addr &server_addr)
194 // This will make sure we get the host information correct.
195 ACE_INET_Addr remote_addr (server_addr.get_port_number (),
196 ACE_LOCALHOST);
198 // Perform a blocking connect to the server using the Strategy
199 // Connector with a connection caching strategy.
200 Client_Svc_Handler *svc_handler = 0;
201 int result = con.connect (svc_handler,
202 remote_addr);
203 if (result == -1)
204 ACE_ERROR_RETURN ((LM_ERROR,
205 ACE_TEXT ("%p\n"),
206 ACE_TEXT ("connection failed")),
207 -1);
208 else
209 if (debug)
210 ACE_DEBUG ((LM_DEBUG,
211 ACE_TEXT ("Connection successful to server at port %d!\n"),
212 remote_addr.get_port_number ()));
214 // Reset Svc_Handler state.
215 svc_handler->recycle_state (ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE);
217 return 0;
220 static void
221 server ()
223 int result = 1;
225 while (connection_accepted == 0)
226 result = ACE_Reactor::instance ()->handle_events ();
228 connection_accepted = 0;
230 ACE_UNUSED_ARG (result);
233 static void
234 test_connection_management (CACHING_STRATEGY &caching_strategy)
236 // Configure the Strategy Connector with a strategy that caches
237 // connection.
238 CACHED_CONNECT_STRATEGY caching_connect_strategy (caching_strategy);
240 NULL_CREATION_STRATEGY creation_strategy;
241 NULL_ACTIVATION_STRATEGY activation_strategy;
243 STRATEGY_CONNECTOR strategy_connector (0,
244 &creation_strategy,
245 &caching_connect_strategy,
246 &activation_strategy);
248 // Connect strategy is required by the <out_of_sockets_handler>.
249 ACCEPT_STRATEGY listen_one_time_accept_strategy (caching_connect_strategy);
251 // If <listen_once> is true, only one Acceptor is used for the test.
252 ACCEPTOR listen_one_time_acceptor;
253 ACE_INET_Addr server_addr;
255 int result =
256 listen_one_time_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &),
257 ACE_Reactor::instance (),
259 &listen_one_time_accept_strategy);
260 if (result != 0)
262 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor open")));
263 return;
266 result = listen_one_time_acceptor.acceptor ().get_local_addr (server_addr);
267 if (result != 0)
269 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor getaddr")));
270 listen_one_time_acceptor.close ();
271 return;
274 for (int i = 1; i <= iterations; ++i)
276 ACE_DEBUG ((LM_DEBUG,
277 ACE_TEXT ("%T iteration %d\n"),
278 i));
280 // Connect strategy is required by the <out_of_sockets_handler>.
281 ACCEPT_STRATEGY listen_multiple_times_accept_strategy (caching_connect_strategy);
283 // If <listen_once> is false, one Acceptor is used for every
284 // iteration.
285 ACCEPTOR listen_multiple_times_acceptor;
287 if (!listen_once)
289 // Bind acceptor to any port and then find out what the port
290 // was.
291 if (listen_multiple_times_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &),
292 ACE_Reactor::instance (),
294 &listen_multiple_times_accept_strategy) == -1)
296 ACE_ERROR ((LM_ERROR,
297 ACE_TEXT ("%p\n"),
298 ACE_TEXT ("open")));
299 break;
302 if (listen_multiple_times_acceptor.acceptor ().get_local_addr (server_addr) == -1)
304 ACE_ERROR ((LM_ERROR,
305 ACE_TEXT ("%p\n"),
306 ACE_TEXT ("get_local_addr")));
307 break;
312 if (debug)
313 ACE_DEBUG ((LM_DEBUG,
314 ACE_TEXT ("starting server at port %d\n"),
315 server_addr.get_port_number ()));
317 // Run the cached blocking test.
318 if (-1 == cached_connect (strategy_connector, server_addr))
319 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("cached_connect")));
320 else
321 server ();
325 void
326 test_caching_strategy_type ()
328 CACHING_STRATEGY *caching_strategy = 0;
330 switch (caching_strategy_type)
332 case ACE_NULL:
333 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
334 ACE_NEW (caching_strategy,
335 NULL_CACHING_STRATEGY_ADAPTER);
336 break;
338 case ACE_LRU:
339 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
340 ACE_NEW (caching_strategy,
341 LRU_CACHING_STRATEGY_ADAPTER);
342 break;
344 case ACE_LFU:
345 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
346 ACE_NEW (caching_strategy,
347 LFU_CACHING_STRATEGY_ADAPTER);
348 break;
350 case ACE_FIFO:
351 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
352 ACE_NEW (caching_strategy,
353 FIFO_CACHING_STRATEGY_ADAPTER);
354 break;
356 case ACE_ALL: // Just to remove warnings!
357 break;
360 caching_strategy->purge_percent (purge_percentage);
361 test_connection_management (*caching_strategy);
362 delete caching_strategy;
366 parse_args (int argc, ACE_TCHAR *argv[])
368 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("l:i:p:c:a:d"));
370 int cc;
372 while ((cc = get_opt ()) != -1)
373 switch (cc)
375 case 'd':
376 debug = 1;
377 break;
378 case 'l':
379 listen_once = ACE_OS::atoi (get_opt.opt_arg ());
380 break;
381 case 'i':
382 iterations = ACE_OS::atoi (get_opt.opt_arg ());
383 user_has_specified_iterations = 1;
384 break;
385 case 'p':
386 purge_percentage = ACE_OS::atoi (get_opt.opt_arg ());
387 break;
388 case 'c':
389 // Note that if null caching strategy is used then this test
390 // will fail if the number of servers exceed number of open
391 // files allowed for the process.
392 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("null")) == 0)
393 caching_strategy_type = ACE_NULL;
394 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lru")) == 0)
395 caching_strategy_type = ACE_LRU;
396 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lfu")) == 0)
397 caching_strategy_type = ACE_LFU;
398 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("fifo")) == 0)
399 caching_strategy_type = ACE_FIFO;
400 break;
401 case 'a':
402 keep_handles_available = ACE_OS::atoi (get_opt.opt_arg ());
403 break;
404 case '?':
405 case 'h':
406 default:
407 ACE_ERROR ((LM_ERROR,
408 ACE_TEXT ("usage: %s ")
409 ACE_TEXT ("[-t (timeout)] ")
410 ACE_TEXT ("[-c (caching strategy: lru / lfu / fifo / null [default = all])] ")
411 ACE_TEXT ("[-i (iterations)] ")
412 ACE_TEXT ("[-l (listen once)] ")
413 ACE_TEXT ("[-d (addition debugging output)] ")
414 ACE_TEXT ("[-p (purge percent)] ")
415 ACE_TEXT ("[-a (keep handles available)] "),
416 ACE_TEXT ("Cached_Accept_Conn_Test")));
417 return -1;
420 return 0;
424 run_main (int argc, ACE_TCHAR *argv[])
426 // Validate options.
427 int result = parse_args (argc, argv);
428 if (result != 0)
429 return result;
431 #if defined (ACE_WIN32)
432 // Somehow, on Win32, the <listen once> option allows us to create
433 // more handles.
434 if (!user_has_specified_iterations &&
435 listen_once)
436 iterations *= 2;
437 #endif /* ACE_WIN32 */
439 // Start the test only if options are valid.
440 ACE_START_TEST (ACE_TEXT ("Cached_Accept_Conn_Test"));
442 // Remove the extra debugging attributes from Log_Msg output.
443 ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
445 // The reactor's constructor changes the handle limit for the
446 // process.
447 ACE_Reactor::instance ();
449 // Consume all handles in the process, leaving us
450 // <keep_handles_available> to play with.
451 ACE_Handle_Gobbler handle_gobbler;
452 if (0 != handle_gobbler.consume_handles (keep_handles_available))
453 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("handle_gobbler")));
455 // Do we need to test all the strategies. Note, that the less
456 // useful null strategy is ignored in this case.
457 if (caching_strategy_type == ACE_ALL)
459 caching_strategy_type = ACE_LRU;
460 test_caching_strategy_type ();
462 // Default iterations are too many; if the user hasn't specified
463 // otherwise, we'll shrink the iterations for LFU and FIFO.
464 if (!user_has_specified_iterations)
465 iterations /= 100;
467 caching_strategy_type = ACE_LFU;
468 test_caching_strategy_type ();
470 caching_strategy_type = ACE_FIFO;
471 test_caching_strategy_type ();
473 else
475 test_caching_strategy_type ();
478 ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
480 ACE_END_TEST;
481 return 0;
485 #endif /* CACHED_ACCEPT_CONNECTION_TEST */