diff options
Diffstat (limited to 'ACE/examples/IPC_SAP/SSL_SAP/SSL-client.cpp')
-rw-r--r-- | ACE/examples/IPC_SAP/SSL_SAP/SSL-client.cpp | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.cpp b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.cpp new file mode 100644 index 00000000000..539b97c931c --- /dev/null +++ b/ACE/examples/IPC_SAP/SSL_SAP/SSL-client.cpp @@ -0,0 +1,418 @@ +// $Id$ + +// This tests the features of the <ACE_SSL_SOCK_Connector> and +// <ACE_SSL_SOCK_Stream> classes. In addition, it can be used to test the +// oneway and twoway latency and throughput at the socket-level. This +// is useful as a baseline to compare against ORB-level performance +// for the same types of data. + +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_unistd.h" +#include "ace/INET_Addr.h" +#include "ace/Thread_Manager.h" +#include "ace/Singleton.h" +#include "ace/Get_Opt.h" +#include "ace/High_Res_Timer.h" + +#include "ace/SSL/SSL_SOCK_Connector.h" + +#include "SSL-client.h" + +ACE_RCSID(SSL_SAP, SSL_client, "$Id$") + +Options::Options (void) + : host_ (ACE_DEFAULT_SERVER_HOST), + port_ (ACE_DEFAULT_SERVER_PORT), + sleep_time_ (0, 0), // By default, don't sleep between calls. + threads_ (10), + message_len_ (0), + message_buf_ (0), + io_source_ (ACE_INVALID_HANDLE), // Defaults to using the generator. + iterations_ (10000), + oneway_ (1) // Make oneway calls the default. +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + , barrier_ (0) +#endif /* ACE_MT_SAFE */ +{ + ACE_OS::strcpy (quit_string_, "q"); +} + +Options::~Options (void) +{ + ACE_MT (delete this->barrier_); + delete [] this->message_buf_; +} + +// Options Singleton. +typedef ACE_Singleton<Options, ACE_SYNCH_RECURSIVE_MUTEX> OPTIONS; + +int +Options::init (void) +{ + // Check for default case. + if (this->message_len_ == 0) + this->message_len_ = ACE_OS::strlen ("TAO"); + + this->message_len_ += sizeof (ACE_UINT32); + + ACE_NEW_RETURN (this->message_buf_, + char[this->message_len_], + -1); + + // Copy the length into the beginning of the message. + ACE_UINT32 length = ntohl (this->message_len_); + ACE_OS::memcpy ((void *) this->message_buf_, + (void *) &length, + sizeof length); + + ACE_OS::memset ((void *) (this->message_buf_ + sizeof (ACE_UINT32)), + 'a', + this->message_len_ - sizeof (ACE_UINT32)); + + // Allocate the barrier with the correct count. + ACE_MT (ACE_NEW_RETURN (this->barrier_, + ACE_Barrier (this->threads_), + -1)); + return 0; +} + +size_t +Options::message_len (void) const +{ + return this->message_len_; +} + +const void * +Options::message_buf (void) const +{ + return this->message_buf_; +} + +ssize_t +Options::read (void *buf, size_t len, size_t &iteration) +{ + ACE_UNUSED_ARG (len); + + if (this->io_source_ == ACE_STDIN) + return ACE_OS::read (ACE_STDIN, buf, len); + else if (iteration >= this->iterations_) + return 0; + else + { + ACE_OS::memcpy (buf, + this->message_buf (), + len); + iteration++; + return len; + } +} + +int +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("2h:i:m:p:q:st:T:"), 1); + + for (int c; (c = getopt ()) != -1; ) + switch (c) + { + case '2': // Disable the oneway client. + this->oneway_ = 0; + break; + case 'h': + this->host_ = getopt.opt_arg (); + break; + case 'i': + this->iterations_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'm': + this->message_len_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'p': + this->port_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'q': + ACE_OS::strncpy (this->quit_string_, + ACE_TEXT_ALWAYS_CHAR (getopt.opt_arg ()), + QUIT_STRING_SIZE); + break; + case 's': + this->io_source_ = ACE_STDIN; + break; + case 't': + this->threads_ = (size_t) ACE_OS::atoi (getopt.opt_arg ()); + break; + case 'T': + this->sleep_time_.set (0, ACE_OS::atoi (getopt.opt_arg ())); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) usage: %n [-2] [-h <host>] ") + ACE_TEXT ("[-i iterations] [-m message-size] ") + ACE_TEXT ("[-p <port>] [-q <quit string>] ") + ACE_TEXT ("[-s] [-t <threads>] [-T <sleep_time>]\n")), + -1); + } + + return this->init (); +} + +u_short +Options::port (void) const +{ + return this->port_; +} + +const ACE_TCHAR * +Options::host (void) const +{ + return this->host_; +} + +const char * +Options::quit_string (void) const +{ + return this->quit_string_; +} + +size_t +Options::threads (void) const +{ + return this->threads_; +} + +const ACE_Time_Value & +Options::sleep_time (void) const +{ + return this->sleep_time_; +} + +char * +Options::shared_client_test (u_short port, + ACE_SSL_SOCK_Stream &cli_stream) +{ + ACE_INET_Addr remote_addr (port, this->host_); + + ACE_SSL_SOCK_Connector con; + + if (con.connect (cli_stream, + remote_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("connection failed")), + 0); + else + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) connected to %C at port %d\n"), + remote_addr.get_host_name (), + remote_addr.get_port_number ())); + + // Allocate the transmit buffer. + char *buf; + ACE_NEW_RETURN (buf, + char[this->message_len ()], + 0); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) waiting...\n"))); + + // Wait for all other threads to finish initialization. + ACE_MT (this->barrier_->wait ()); + return buf; +} +// Static function entry point to the oneway client service. + +void * +Options::oneway_client_test (void *) +{ + Options *options = OPTIONS::instance (); + ACE_SSL_SOCK_Stream cli_stream; + + // Add 1 to the port to trigger the oneway test! + char *request = options->shared_client_test (options->port () + 1, + cli_stream); + if (request == 0) + return 0; + + // This variable is allocated off the stack to obviate the need for + // locking. + size_t iteration = 0; + + // Keep track of return value. + size_t result = 0; + ACE_INT32 len = options->message_len (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting oneway transmission\n"))); + + // Perform oneway transmission of data to server (correctly handles + // "incomplete writes"). + + for (ssize_t r_bytes; + (r_bytes = options->read (request, len, iteration)) > 0; + // Transmit at the proper rate. + ACE_OS::sleep (options->sleep_time ())) + if (ACE_OS::memcmp (request, + options->quit_string (), + ACE_OS::strlen (options->quit_string ())) == 0) + break; + else if (cli_stream.send_n (request, r_bytes) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send_n"))); + result = size_t (-1); + break; + } + + // Close the connection. + cli_stream.close (); + + delete [] request; + return (void *) result; +} + +// Static function entry point to the twoway client service. + +void * +Options::twoway_client_test (void *) +{ + Options *options = OPTIONS::instance (); + + ACE_SSL_SOCK_Stream cli_stream; + + char *request = options->shared_client_test (options->port (), + cli_stream); + if (request == 0) + return 0; + + // This variable is allocated off the stack to obviate the need for + // locking. + size_t iteration = 0; + + // Keep track of return value. + size_t result = 0; + + // Timer business. + ACE_High_Res_Timer timer; + + ACE_INT32 len = options->message_len (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting twoway transmission\n"))); + + // Perform twoway transmission of data to server (correctly handles + // "incomplete writes"). + + for (ssize_t r_bytes; + (r_bytes = options->read (request, len, iteration)) > 0; + // Transmit at the proper rate. + ACE_OS::sleep (options->sleep_time ())) + if (ACE_OS::memcmp (request, + options->quit_string (), + ACE_OS::strlen (options->quit_string ())) == 0) + break; + + // Transmit <request> to the server. + else + { + // Note that we use the incremental feature of the + // <ACE_High_Res_Timer> so that we don't get "charged" for the + // <ACE_OS::sleep> used to control the rate at which requests + // are sent. + timer.start_incr (); + + if (cli_stream.send_n (request, r_bytes) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("send_n"))); + result = size_t (-1); + break; + } + // Receive the reply from the server. Normally, it just sends + // back 24 bytes, which is typical for an IIOP reply. + else if (cli_stream.recv (request, r_bytes) <= 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("recv"))); + result = size_t (-1); + break; + } + + timer.stop_incr (); + } + + ACE_Time_Value tv; + + timer.elapsed_time_incr (tv); + double real_time = tv.sec () * ACE_ONE_SECOND_IN_USECS + tv.usec (); + double messages_per_sec = + iteration * double (ACE_ONE_SECOND_IN_USECS) / real_time; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%t) messages = %d\n") + ACE_TEXT ("(%t) usec-per-message = %f\n") + ACE_TEXT ("(%t) messages-per-second = %0.00f\n"), + iteration, + real_time / double (iteration), + messages_per_sec < 0 ? 0 : messages_per_sec)); + + // Close the connection. + cli_stream.close (); + + delete [] request; + return (void *) result; +} + +ACE_THR_FUNC +Options::thr_func (void) +{ + if (this->oneway_ == 0) + return ACE_THR_FUNC (&Options::twoway_client_test); + else + return ACE_THR_FUNC (&Options::oneway_client_test); +} + +static int +run_client (void) +{ + // Raise the socket handle limit to the maximum. + ACE::set_handle_limit (); + +#if defined (ACE_HAS_THREADS) + if (ACE_Thread_Manager::instance ()->spawn_n ( + OPTIONS::instance ()->threads (), + OPTIONS::instance ()->thr_func ()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("spawn_n")), + 1); + else + ACE_Thread_Manager::instance ()->wait (); +#else + *(OPTIONS::instance ()->thr_func) (); +#endif /* ACE_HAS_THREADS */ + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + ACE_SSL_Context *context = ACE_SSL_Context::instance (); + + context->certificate ("./dummy.pem", SSL_FILETYPE_PEM); + context->private_key ("./key.pem", SSL_FILETYPE_PEM); + + // Initialize the logger. + ACE_LOG_MSG->open (argv[0]); + + if (OPTIONS::instance ()->parse_args (argc, argv) == -1) + return -1; + + // Run the client + run_client (); + + return 0; +} + |