2 //=============================================================================
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
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"
30 #pragma warning(disable:4503)
33 int connection_accepted
= 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
,
46 int result
= ACCEPT_STRATEGY_BASE::open (local_addr
, restart
);
51 // If the error occurred due to the fact that the file descriptor
52 // limit was exhausted, then purge the connection cache of some
54 result
= this->out_of_sockets_handler ();
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
73 int reset_new_handle
= this->reactor_
->uses_event_associations ();
75 int result
= this->acceptor ().accept (svc_handler
->peer (), // stream
79 reset_new_handle
// reset new handler
85 ACE_TEXT ("Accept succeeded with handle %d\n"),
86 svc_handler
->get_handle ()));
90 // If the error occurred due to the fact that the file descriptor
91 // limit was exhausted, then purge the connection cache of some
93 if (0 != this->out_of_sockets_handler ())
96 ACE_TEXT ("out_of_sockets_handler")));
98 // Close down handler to avoid memory leaks.
99 svc_handler
->close (0);
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 ();
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 *)
130 ACE_DEBUG ((LM_DEBUG
,
131 ACE_TEXT ("opening Client_Svc_Handler %@ with handle %d\n"),
133 this->peer ().get_handle ()));
138 Client_Svc_Handler::close (u_long flags
)
140 ACE_DEBUG ((LM_DEBUG
,
141 ACE_TEXT ("Closing Client_Svc_Handler %@ with handle %d\n"),
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 *)
157 ACE_DEBUG ((LM_DEBUG
,
158 ACE_TEXT ("opening Server_Svc_Handler %@ with handle %d\n"),
160 this->peer ().get_handle ()));
162 return this->close ();
165 enum Caching_Strategy_Type
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;
186 static int iterations
= 200;
187 #endif /* ACE_WIN32 */
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 (),
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
,
204 ACE_ERROR_RETURN ((LM_ERROR
,
206 ACE_TEXT ("connection failed")),
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
);
225 while (connection_accepted
== 0)
226 result
= ACE_Reactor::instance ()->handle_events ();
228 connection_accepted
= 0;
230 ACE_UNUSED_ARG (result
);
234 test_connection_management (CACHING_STRATEGY
&caching_strategy
)
236 // Configure the Strategy Connector with a strategy that caches
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,
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
;
256 listen_one_time_acceptor
.open (ACE_sap_any_cast (const ACE_INET_Addr
&),
257 ACE_Reactor::instance (),
259 &listen_one_time_accept_strategy
);
262 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor open")));
266 result
= listen_one_time_acceptor
.acceptor ().get_local_addr (server_addr
);
269 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor getaddr")));
270 listen_one_time_acceptor
.close ();
274 for (int i
= 1; i
<= iterations
; ++i
)
276 ACE_DEBUG ((LM_DEBUG
,
277 ACE_TEXT ("%T iteration %d\n"),
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
285 ACCEPTOR listen_multiple_times_acceptor
;
289 // Bind acceptor to any port and then find out what the port
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
,
302 if (listen_multiple_times_acceptor
.acceptor ().get_local_addr (server_addr
) == -1)
304 ACE_ERROR ((LM_ERROR
,
306 ACE_TEXT ("get_local_addr")));
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")));
326 test_caching_strategy_type ()
328 CACHING_STRATEGY
*caching_strategy
= 0;
330 switch (caching_strategy_type
)
333 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
334 ACE_NEW (caching_strategy
,
335 NULL_CACHING_STRATEGY_ADAPTER
);
339 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
340 ACE_NEW (caching_strategy
,
341 LRU_CACHING_STRATEGY_ADAPTER
);
345 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
346 ACE_NEW (caching_strategy
,
347 LFU_CACHING_STRATEGY_ADAPTER
);
351 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
352 ACE_NEW (caching_strategy
,
353 FIFO_CACHING_STRATEGY_ADAPTER
);
356 case ACE_ALL
: // Just to remove warnings!
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"));
372 while ((cc
= get_opt ()) != -1)
379 listen_once
= ACE_OS::atoi (get_opt
.opt_arg ());
382 iterations
= ACE_OS::atoi (get_opt
.opt_arg ());
383 user_has_specified_iterations
= 1;
386 purge_percentage
= ACE_OS::atoi (get_opt
.opt_arg ());
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
;
402 keep_handles_available
= ACE_OS::atoi (get_opt
.opt_arg ());
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")));
424 run_main (int argc
, ACE_TCHAR
*argv
[])
427 int result
= parse_args (argc
, argv
);
431 #if defined (ACE_WIN32)
432 // Somehow, on Win32, the <listen once> option allows us to create
434 if (!user_has_specified_iterations
&&
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
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
)
467 caching_strategy_type
= ACE_LFU
;
468 test_caching_strategy_type ();
470 caching_strategy_type
= ACE_FIFO
;
471 test_caching_strategy_type ();
475 test_caching_strategy_type ();
478 ACE_LOG_MSG
->set_flags (ACE_Log_Msg::VERBOSE_LITE
);
485 #endif /* CACHED_ACCEPT_CONNECTION_TEST */