// -*- c++ -*- // Generated by assa-genesis //------------------------------------------------------------------------------ // $Id: echoxdr_testc.cpp,v 1.12 2006/07/26 00:27:32 vlg Exp $ //------------------------------------------------------------------------------ // EchoXDR_Client_Test.cpp //------------------------------------------------------------------------------ // Copyright (c) 1999,2005 by Vladislav Grinchenko // // Permission to use, copy, modify, and distribute this software // and its documentation for any purpose and without fee is hereby // granted, provided that the above copyright notice appear in all // copies. The author makes no representations about the suitability // of this software for any purpose. It is provided "as is" without // express or implied warranty. //------------------------------------------------------------------------------ // Date: Jul 12, 1999 //------------------------------------------------------------------------------ static const char help_msg[]= " \n" " NAME: \n" " \n" " echoxdr_testc - test XDR encoding/decoding. \n" " \n" " DESCRIPTION: \n" " \n" " This is the client side of the test intended to exercise IPv4Socket \n" " class' I/O capabilities to transfer XDR-encoded basic data types. \n" " \n" " The test is two-stage: \n" " \n" " 1) Connect to the daytime server on [hostname] and read current time. \n" " \n" " 2) Connect to 'echoxdr_tests' server running on $ASSAPORT@localhost \n" " or $ASSAPORT@hostname and send/receive/compare data values of every \n" " basic type IPv4Socket can handle. \n" " \n" " If [hostname] is ommited, localhost is assumed. \n" " \n" " USAGE: \n" " \n" " shell> echoxdr_testc [OPTIONS] \n" " \n" " OPTIONS: \n" " \n" " --daytime-host NAME - Hostname of 'daytime' service \n" " --build-dir STRING - Directory where executables are located. \n" " \n" " -D, --log-file NAME - Write debug to NAME file \n" " -d, --log-stdout - Write debug to standard output \n" " -z, --log-size NUM - Maximum size debug file can reach (dfl: is 10Mb) \n" " \n" " -m, --mask MASK - Mask (default: ALL = 0x7fffffff) \n" " -p, --port NAME - The tcp/ip port NAME (default - procname) \n" " \n" " -h, --help - Print this messag \n" " -v, --version - Print version number \n"; //------------------------------------------------------------------------------ #if !defined (WIN32) #ifdef HAVE_CONFIG_H # include "config.h" #endif #include // uname(2) #include // gethostbyname(3) #include // getcwd(3) #include #include #include using std::string; #include #include #include #include #include #include #include #include using namespace ASSA; /******************************************************************************* Class EchoXDR_Client_Test *******************************************************************************/ class EchoXDR_Client_Test : public GenServer, public Singleton { public: EchoXDR_Client_Test (); virtual void init_service (); virtual void process_events (); int get_exit_value () const { return m_exit_value; } void set_exit_value (int v_) { m_exit_value = v_; } string get_build_dir () const { return m_build_dir; } private: int m_exit_value; // Return status of the process string m_daytime_host; string m_my_hostname; string m_build_dir; }; /* Useful definitions */ #define CLIENT EchoXDR_Client_Test::get_instance() #define REACTOR CLIENT->get_reactor() // Static declarations mandated by Singleton class ASSA_DECL_SINGLETON(EchoXDR_Client_Test); /******************************************************************************* Local helpers *******************************************************************************/ template void compare_and_report (T in_, T out_) { if (in_ == out_) { std::cout << " ok"; } else { std::cout << " error:\n"; std::cout << "\tdata in (lhs) = " << in_ << '\n' << "\tdata out (rhs) = " << out_ << std::endl; CLIENT->set_exit_value (1); } std::cout << std::endl; } void dump_var (const char* annotation_, std::string& var_) { MemDump::dump_to_log (APP, annotation_, var_.c_str (), var_.length ()); } template void dump_var (const char* annotation_, T& var_) { MemDump::dump_to_log (APP, annotation_, reinterpret_cast(&var_), sizeof (T)); } /******************************************************************************* Class EchoXDR_Client_Test member functions *******************************************************************************/ EchoXDR_Client_Test:: EchoXDR_Client_Test () : m_exit_value (0) { add_opt (0, "daytime-host", &m_daytime_host); add_opt (0, "build-dir", &m_build_dir); // ---Configuration--- rm_opt ('f', "config-file" ); rm_opt ('n', "instance" ); // ---Process bookkeeping--- rm_opt ('b', "daemon" ); rm_opt ('l', "pidfile" ); rm_opt ('L', "ommit-pidfile"); /*--- * Disable all debugging *---*/ // m_debug_mask = 0x0; m_log_file = "echoxdr_testc.log"; } void EchoXDR_Client_Test:: init_service () { trace("Client::init_service"); Log::disable_timestamp (); /* Get fully-quialified host name */ struct utsname u; ::uname (&u); struct hostent* hent_ptr; hent_ptr = ::gethostbyname (u.nodename); m_my_hostname = hent_ptr->h_name; DL((APP,"my_hostname = \"%s\"\n", m_my_hostname.c_str ())); /* Figure out what directory we have been started from. */ if (m_build_dir.length () == 0) { m_build_dir = ASSA::Utils::get_cwd_name (); } DL((APP,"build-dir = \"%s\"\n", m_build_dir.c_str ())); DL((APP,"Service \"%s\" has been initialized\n", get_cmdline_name ().c_str ())); } void EchoXDR_Client_Test:: process_events () { static const char self[]="Client::process_events"; trace(self); std::cout << "= Running echoxdr Test =\n"; //------------------------------------------------------------------------------ // Test 1: Connect to date server and get current time // // We try all possible combinations: // // No. Host Port Action Note // --- ---------------- ----------- ------------------------- ------------------ // 1 --daytime-host "daytime" connect() remote // --- ---------------- ----------- ------------------------- ------------------ // 2 gethostbyname(3) "daytime" connect() local // --- ---------------- ----------- ------------------------- ------------------ // 3 gethostbyname(3) $ASSAPORT fork()/exec()/connect() local replacmnt // --- ---------------- ----------- ------------------------- ------------------ // 4 gethostbyname(3) 10000 fork()/exec()/connect() local replacmnt //------------------------------------------------------------------------------ DL((APP,"===============================\n")); DL((APP,"| Test 1: |\n")); DL((APP,"| |\n")); DL((APP,"| Read time from daytime ... |\n")); DL((APP,"| |\n")); DL((APP,"===============================\n")); std::cout << ">>> Testing ability to read input from daytime ..." << std::flush; std::string assaport; char* ap; char page [4096]; IPv4Socket stream; std::vector address_list; DL((APP,"1. --daytime-host, daytime\n")); INETAddress dt_1 (m_daytime_host.c_str (), "daytime"); address_list.push_back (dt_1); DL((APP,"2. gethostbyname, daytime\n")); INETAddress dt_2 (m_my_hostname.c_str (), "daytime"); address_list.push_back (dt_2); if ((ap = ::getenv("ASSAPORT")) != 0) { assaport = ap; } if (assaport.length () == 0) { assaport = "10000"; } /* [$ASSAPORT|10000]@my-fully-quaified-host-name */ assaport += "@" + m_my_hostname; DL((APP,"3./4. gethostbyname, $ASSAPORT/%s\n", assaport.c_str ())); INETAddress dt_3 (assaport.c_str ()); address_list.push_back (dt_3); Assure_exit (stream.open (AF_INET)); /* * By default, IPv4Socket is in non-blocking mode. We switch * to the blocking mode to get blocking connection complete. * Otherwise, connect() returns EINPROGRESS. */ stream.turnOptionOff (Socket::nonblocking); std::string exec_name; int j = 0; int ret = 0; std::vector::iterator cit = address_list.begin (); while (cit != address_list.end ()) { DL((APP,"[%02d] Trying address: %d@%s\n", j+1, (*cit).getPort (), (*cit).getHostName ().c_str ())); (*cit).dump (); if (j == 2) { // fork daytime replacement DL((APP,"Starting daytime replacement server ...\n")); exec_name = CLIENT->get_build_dir () + "/daytime"; Fork f (Fork::KILL_ON_EXIT, Fork::IGNORE_STATUS); if (f.isChild ()) { ret = execlp (exec_name.c_str (), exec_name.c_str (), "--log-file=daytime.log", "--mask=0x2", "--one-shot", NULL); // point of no return if (ret == -1) { EL((ASSA::ASSAERR,"execlp(\"daytime\") failed\n")); } Assure_exit (false); } DL((APP,"Wait for daytime to come up\n")); ASSA::Utils::sleep_for_seconds (1); } if (stream.connect (*cit)) { DL((APP,"Connection established with daytime service.\n")); break; } j++, cit++; } if (cit == address_list.end ()) { std::cout << "Test failed\n"; exit (1); } while ( stream && stream.read (page, 4096) > 0 ) { DL((APP,"Got the date: \"%s\"\n", page)); } stream.close(); std::cout << " ok\n"; //------------------------------------------------------------------------------ // Test 2: Connect to echoxdr server, send base types, // receive replies and compare sent and received values //------------------------------------------------------------------------------ DL((APP,"===============================\n")); DL((APP,"| Test 2: |\n")); DL((APP,"| |\n")); DL((APP,"| Starting echoxdr server ... |\n")); DL((APP,"| |\n")); DL((APP,"===============================\n")); exec_name = CLIENT->get_build_dir () + "/echoxdr_tests"; Fork sf (Fork::KILL_ON_EXIT, Fork::IGNORE_STATUS); if (sf.isChild ()) { ret = execlp (exec_name.c_str (), exec_name.c_str (), "--log-file=echoxdr_tests.log", "--mask=0x7fffffff", "--port", assaport.c_str (), NULL); // point of no return if (ret == -1) { EL((ASSA::ASSAERR,"execlp(\"echoxdr_tests\") failed\n")); } exit (1); } DL((APP,"Wait for echoxdr server to come up\n")); ASSA::Utils::sleep_for_seconds (1); assert (stream.open (AF_INET)); stream.turnOptionOff (Socket::nonblocking); stream.connect (dt_3); DL((APP,"Connection established with echoxdr server\n")); bool b = true, br; /*----------------------------------------------------------------------*/ char c = 'G', cr; std::cout << ">>> Testing char c = \""<< c << "\" ..." << std::flush; dump_var ("char sent", c); stream << c << flush; stream >> cr; dump_var ("char received", cr); compare_and_report (c, cr); /*----------------------------------------------------------------------*/ // 01234578901234578901234578901 std::string s = "ASSA is a pretty cool library"; std::string sr; std::cout << ">>> Testing string = \""<< s << "\" ..." << std::flush; dump_var ("string sent", s); stream << s << flush; stream >> sr; dump_var ("string received", sr); compare_and_report (s, sr); /*----------------------------------------------------------------------*/ short sh = 120, shr; std::cout << ">>> Testing short sh = "<< sh <<" ..." << std::flush; dump_var ("short sent", sh); stream << sh << flush; stream >> shr; dump_var ("short received", shr); compare_and_report (sh, shr); /*----------------------------------------------------------------------*/ int i = -210, ir; std::cout << ">>> Testing int i="<< i << " ..." << std::flush; dump_var ("int sent", i); stream << i << flush; stream >> ir; dump_var ("int received", ir); compare_and_report (i, ir); /*----------------------------------------------------------------------*/ u_int ui = 32, uir; std::cout << ">>> Testing u_int ui="<< ui <<" ..."; dump_var ("u_int sent", ui); stream << ui << flush; stream >> uir; dump_var ("u_int received", uir); compare_and_report (ui, uir); /*----------------------------------------------------------------------*/ long l = INT_MIN + 1, lr; std::cout << ">>> Testing long l="<< l <<" ..."; dump_var ("long sent", l); stream << l << flush; stream >> lr; dump_var ("long received", lr); compare_and_report (l, lr); /*----------------------------------------------------------------------*/ u_long ul = INT_MAX - 1, ulr; std::cout << ">>> Testing u_long ul=" << ul << " ..."; dump_var ("u_long sent", ul); stream << ul << flush; stream >> ulr; dump_var ("u_long received", ulr); compare_and_report (ul, ulr); /*----------------------------------------------------------------------*/ float f = 123.4334453545, fr; std::cout << ">>> Testing float f=" << f << " ..."; dump_var ("float sent", f); stream << f << flush; stream >> fr; dump_var ("float received", fr); compare_and_report (f, fr); /*----------------------------------------------------------------------*/ double d = -123456678.234324234, dr; std::cout << ">>> Testing double d=" << d << " ..."; dump_var ("double sent", d); stream << d << flush; stream >> dr; dump_var ("double received", dr); compare_and_report (d, dr); /*----------------------------------------------------------------------*/ stream.close (); if (CLIENT->get_exit_value ()) { std::cout << "Test failed"; } else { std::cout << "Test passed"; } std::cout << std::endl; m_reactor.stopReactor (); DL((APP,"Service stopped!\n")); } #endif /* !defined WIN32 */ /******************************************************************************* Main *******************************************************************************/ int main (int argc, char* argv[]) { #if !defined (WIN32) static const char release[] = "VERSION"; int patch_level = 0; CLIENT->set_version (release, patch_level); CLIENT->set_author ("Vladislav Grinchenko"); CLIENT->set_flags (GenServer::RMLOG); CLIENT->init (&argc, argv, help_msg); CLIENT->init_service (); CLIENT->process_events (); return CLIENT->get_exit_value (); #endif /* !def WIN32 */ return 0; }