//============================================================================= /** * @file Conn_Test.cpp * * $Id$ * * This is a test of the and * classes. The test forks processes or spawns threads (depending * upon the platform) and then executes client and server allowing * them to connect and exchange data. The test also illustrates * how the works by showing how you can * cache connections on the client. * * * @author Douglas C. Schmidt * @author Chris Cleeland * @author and Irfan Pyarali */ //============================================================================= #include "test_config.h" #include "ace/SOCK_Connector.h" #include "ace/LOCK_SOCK_Acceptor.h" #include "ace/Acceptor.h" #include "ace/Handle_Set.h" #include "ace/Connector.h" #include "ace/Auto_Ptr.h" #include "ace/Get_Opt.h" #include "ace/Process_Mutex.h" #include "ace/Signal.h" #include "Conn_Test.h" #include "ace/Barrier.h" #include "ace/OS_NS_signal.h" #include "ace/OS_NS_sys_select.h" #include "ace/OS_NS_sys_wait.h" #include "ace/OS_NS_unistd.h" #include "ace/os_include/os_netdb.h" static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz"; // This test doesn't work well using fork() on MacOS X. So we // will force it to use threads instead. #if defined (__APPLE__) # define ACE_LACKS_FORK #endif /* __APPLE__ */ // The following works around bugs with some operating systems, which // don't allow multiple threads/process to call accept() on the same // listen-mode port/socket. Also, note that since timed accept is // implemented using select(), and we use timed accepts with threads, // we need a real lock when using timed accepts even if the OS has // thread-safe accept. // #if defined (ACE_LACKS_FORK) # if defined (ACE_HAS_THREADS) # include "ace/Thread_Mutex.h" typedef ACE_Thread_Mutex ACCEPTOR_LOCKING; # else # include "ace/Null_Mutex.h" typedef ACE_Null_Mutex ACCEPTOR_LOCKING; # endif /* ACE_HAS_THREADS */ #else # if defined (ACE_HAS_THREAD_SAFE_ACCEPT) # include "ace/Null_Mutex.h" typedef ACE_Null_Mutex ACCEPTOR_LOCKING; # else # include "ace/Process_Mutex.h" typedef ACE_Process_Mutex ACCEPTOR_LOCKING; # endif /* ACE_HAS_THREAD_SAFE_ACCEPT */ #endif /* ACE_LACKS_FORK */ typedef ACE_Oneshot_Acceptor > ACCEPTOR; typedef ACE_Connector CONNECTOR; typedef ACE_Strategy_Connector STRAT_CONNECTOR; typedef ACE_NOOP_Creation_Strategy NULL_CREATION_STRATEGY; typedef ACE_NOOP_Concurrency_Strategy NULL_ACTIVATION_STRATEGY; typedef ACE_Cached_Connect_Strategy CACHED_CONNECT_STRATEGY; #define CACHED_CONNECT_STRATEGY ACE_Cached_Connect_Strategy #define REFCOUNTED_HASH_RECYCLABLE_ADDR ACE_Refcounted_Hash_Recyclable // Default number of clients/servers. #if defined (ACE_HAS_PHARLAP) // PharLap is, by default, resource contrained. Test for something that works // on the default configuration. static int n_servers = 2; static int n_clients = 4; #else static int n_servers = 5; static int n_clients = 5; #endif /* ACE_HAS_PHARLAP */ static int n_client_iterations = 3; Svc_Handler::Svc_Handler (ACE_Thread_Manager *) { } int Svc_Handler::open (void *) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) opening Svc_Handler %@ with handle %d\n"), this, this->peer ().get_handle ())); // Enable non-blocking I/O. if (this->peer ().enable (ACE_NONBLOCK) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("enable")), -1); return 0; } int Svc_Handler::recycle (void *) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) recycling Svc_Handler %@ with handle %d\n"), this, this->peer ().get_handle ())); return 0; } void Svc_Handler::send_data (void) { // Send data to server. for (const char *c = ACE_ALPHABET; *c != '\0'; c++) if (this->peer ().send_n (c, 1) == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("send_n"))); } void Svc_Handler::recv_data (void) { ACE_SOCK_Stream &new_stream = this->peer (); ACE_Handle_Set handle_set; handle_set.set_bit (new_stream.get_handle ()); const char *t = ACE_ALPHABET; // Read data from client (terminate on error). for (ssize_t r_bytes; ;) { // Since we're in non-blocking mode we need to use