/*************************************************************************** * Copyright (C) 2004 by Intra2net AG * * info@intra2net.com * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace CppUnit; using namespace libt2n; namespace reentrant { command_server *global_server = NULL; int fork_count = 3; int requests_per_child = 100; int all_requests = (2 << (fork_count-1)) * requests_per_child; int seen_client_requests = 0; string testfunc(const string& str) { string ret; ret=str+", testfunc() was here"; // call handle, eventually reentrant if (global_server) global_server->handle(10000); ++seen_client_requests; return ret; } class testfunc_res : public libt2n::result { private: string res; friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result); ar & BOOST_SERIALIZATION_NVP(res); } public: testfunc_res() { } testfunc_res(const string& str) { res=str; } string get_data() { return res; } }; class testfunc_cmd : public libt2n::command { private: string param; friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command); ar & BOOST_SERIALIZATION_NVP(param); } public: testfunc_cmd() { } testfunc_cmd(const string& str) { param=str; } libt2n::result* operator()() { return new testfunc_res(testfunc(param)); } }; } #include BOOST_CLASS_EXPORT(reentrant::testfunc_cmd) BOOST_CLASS_EXPORT(reentrant::testfunc_res) using namespace reentrant; class test_reentrant : public TestFixture { CPPUNIT_TEST_SUITE(test_reentrant); CPPUNIT_TEST(ReentrantServer); CPPUNIT_TEST_SUITE_END(); public: void setUp() { } void tearDown() { } void ReentrantServer() { switch(fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { // wait till server is up sleep(2); // hammer the server for (int i = 0; i < fork_count; i++) fork(); try { for (int i=0; i < requests_per_child; i++) { socket_client_connection sc("./socket"); // sc.set_logging(&cerr,debug); command_client cc(&sc); result_container rc; cc.send_command(new testfunc_cmd("hello"),rc); testfunc_res *res = dynamic_cast(rc.get_result()); if (res) { string ret = res->get_data(); if (ret != "hello, testfunc() was here") std::cout << "ERROR reentrant server testfunc_res failed, res: \"" << ret << "\"\n"; } else { std::cout << "ERROR result from reentrant server empty (" << rc.get_result() << ")\n"; } } } catch (exception &e) { cerr << "caught exception: " << e.what() << endl; } catch(...) { std::cerr << "exception in child. ignoring\n"; } // don't call atexit and stuff _exit(0); } default: // parent { // don't kill us on broken pipe signal(SIGPIPE, SIG_IGN); socket_server ss("./socket"); command_server cs(ss); global_server=&cs; // Wait until all requests have successed int safety_check = 0; while (seen_client_requests < all_requests) { ++safety_check; if (safety_check > 10) { std::cerr << "reached safety check, aborting.\n"; break; } long long maxtime=1000000; while(maxtime > 0) cs.handle(maxtime,&maxtime); } global_server = NULL; } // we are still alive, everything is ok CPPUNIT_ASSERT_EQUAL(all_requests, seen_client_requests); } } }; CPPUNIT_TEST_SUITE_REGISTRATION(test_reentrant);