From fb3345ada7ea94225b78994fd50e3de693a2a3d5 Mon Sep 17 00:00:00 2001 From: Gerd v. Egidy Date: Sun, 24 Aug 2008 21:41:21 +0000 Subject: [PATCH] libt2n: (gerd) fix client-connection-logic, finish wrappers, all tests are working now, some polishing & docu missing --- examples/minimalistic-client-stub.hxx | 2 +- examples/minimalistic-client.cpp | 2 +- src/client_wrapper.hxx | 16 +++- src/command_client.cpp | 32 ++++--- src/command_client.hxx | 6 +- src/socket_client.cpp | 49 ++++++---- src/socket_client.hxx | 5 + src/socket_handler.cpp | 1 + src/socket_wrapper.cpp | 62 ++++++++----- src/socket_wrapper.hxx | 26 ++++- test/cmdgroup.cpp | 4 +- test/hello.cpp | 14 ++-- test/serialize.cpp | 2 +- test/simplecmd.cpp | 15 ++- test/timeout.cpp | 46 +++++---- test/wrapper.cpp | 170 ++++++++++++++++++++++++++++++--- 16 files changed, 337 insertions(+), 115 deletions(-) diff --git a/examples/minimalistic-client-stub.hxx b/examples/minimalistic-client-stub.hxx index b17baca..7ad998d 100644 --- a/examples/minimalistic-client-stub.hxx +++ b/examples/minimalistic-client-stub.hxx @@ -8,7 +8,7 @@ class cmd_group_example_client : public libt2n::command_client { public: - cmd_group_example_client(libt2n::client_connection &_c, + cmd_group_example_client(libt2n::client_connection *_c, long long _command_timeout_usec=command_timeout_usec_default, long long _hello_timeout_usec=hello_timeout_usec_default) : libt2n::command_client(_c,_command_timeout_usec,_hello_timeout_usec) diff --git a/examples/minimalistic-client.cpp b/examples/minimalistic-client.cpp index 35ef13c..9918c2e 100644 --- a/examples/minimalistic-client.cpp +++ b/examples/minimalistic-client.cpp @@ -27,7 +27,7 @@ int main(int argc, char** argv) extended_type_info_test(); libt2n::socket_client_connection sc("./socket"); - cmd_group_example_client cc(sc); + cmd_group_example_client cc(&sc); return (cc.testfunc("hello")=="hello, testfunc() was here") ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/client_wrapper.hxx b/src/client_wrapper.hxx index 672308e..ebc9e25 100644 --- a/src/client_wrapper.hxx +++ b/src/client_wrapper.hxx @@ -59,9 +59,10 @@ class ConnectionWrapper virtual client_connection* get_connection()=0; - virtual void handle(command_client* stubBase, boost::function< void() > f) + virtual bool handle(command_client* stubBase, boost::function< void() > f) { f(); + return true; } long long get_command_timeout_usec(void) @@ -179,7 +180,7 @@ class T2nSingletonWrapper : public T2nSingletonWrapperMessages if (WrappedConnection.get() == NULL) throw std::logic_error(NotInitializedMessage); - std::auto_ptr stub(new Client(*(WrappedConnection->get_connection()), + std::auto_ptr stub(new Client(WrappedConnection->get_connection(), WrappedConnection->get_command_timeout_usec(), WrappedConnection->get_hello_timeout_usec())); @@ -193,8 +194,17 @@ class T2nSingletonWrapper : public T2nSingletonWrapperMessages ensure_singleton_there(); typename detail::TypeWrap::type result; + + // bind our Client-object and the local result detail::Call call( boost::bind( f, SingletonObject->Stub.get()), result ); - WrappedConnection->handle(SingletonObject->Stub.get(),call); + + // let the wrapper-handler call the fully-bound function + if (!WrappedConnection->handle(SingletonObject->Stub.get(),call)) + { + // create an result with default-constructor if the handler could not + // successfully do a call but no exception occured + result=typename detail::TypeWrap::type(); + } return result; } diff --git a/src/command_client.cpp b/src/command_client.cpp index 0f44203..8ccbf10 100644 --- a/src/command_client.cpp +++ b/src/command_client.cpp @@ -39,21 +39,23 @@ using namespace std; namespace libt2n { -command_client::command_client(client_connection& _c, long long _command_timeout_usec, long long _hello_timeout_usec) +command_client::command_client(client_connection* _c, long long _command_timeout_usec, long long _hello_timeout_usec) : c(_c) { command_timeout_usec=_command_timeout_usec; hello_timeout_usec=_hello_timeout_usec; // for reconnects - c.add_callback(new_connection,bind(&command_client::read_hello, boost::ref(*this))); + c->add_callback(new_connection,bind(&command_client::read_hello, boost::ref(*this))); - read_hello(); + // don't expect hello from an always closed connection (like dummy_client_connection) + if (!c->is_closed()) + read_hello(); } /** @brief replace the connection currently in use with a new one - @param _c reference of the new connection + @param _c pointer to the new connection @note the old connection must still be valid when this method is called, it can safely be deleted after this method returned @@ -61,17 +63,17 @@ command_client::command_client(client_connection& _c, long long _command_timeout @note all callbacks registered on the old connection will be copied over to the new one */ -void command_client::replace_connection(client_connection& _c) +void command_client::replace_connection(client_connection* _c) { // copy all callbacks registered on the old connection for(callback_event_type e=static_cast(0); e < __events_end; e=static_cast(static_cast(e)+1)) { - list > evcb=c.get_callback_list(e); + list > evcb=c->get_callback_list(e); for (list >::iterator i=evcb.begin(); i != evcb.end(); i++) - _c.add_callback(e,*i); + _c->add_callback(e,*i); } // replace the connection @@ -85,8 +87,8 @@ std::string command_client::read_packet(const long long &usec_timeout) string resultpacket; bool got_packet=false; long long my_timeout=usec_timeout; - while(!(got_packet=c.get_packet(resultpacket)) && my_timeout > 0 && !c.is_closed()) - c.fill_buffer(my_timeout,&my_timeout); + while(!(got_packet=c->get_packet(resultpacket)) && my_timeout > 0 && !c->is_closed()) + c->fill_buffer(my_timeout,&my_timeout); if (!got_packet) throw t2n_transfer_error("timeout exceeded"); @@ -99,11 +101,11 @@ void command_client::read_hello() string resultpacket; bool got_packet=false; long long my_timeout=hello_timeout_usec; - while(!(got_packet=c.get_packet(resultpacket)) && my_timeout > 0 && !c.is_closed()) + while(!(got_packet=c->get_packet(resultpacket)) && my_timeout > 0 && !c->is_closed()) { - c.fill_buffer(my_timeout,&my_timeout); + c->fill_buffer(my_timeout,&my_timeout); - c.peek_packet(resultpacket); + c->peek_packet(resultpacket); check_hello(resultpacket); // will throw before timeout if wrong data received } @@ -209,14 +211,14 @@ void command_client::send_command(command* cmd, result_container &res) { throw; } std::ostream* ostr; - if ((ostr=c.get_logstream(fulldebug))!=NULL) + if ((ostr=c->get_logstream(fulldebug))!=NULL) { (*ostr) << "sending command, decoded data: " << std::endl; boost::archive::xml_oarchive xo(*ostr); xo << BOOST_SERIALIZATION_NVP(cc); } - c.write(ofs.str()); + c->write(ofs.str()); istringstream ifs(read_packet(command_timeout_usec)); boost::archive::binary_iarchive ia(ifs); @@ -234,7 +236,7 @@ void command_client::send_command(command* cmd, result_container &res) catch(...) { throw; } - if ((ostr=c.get_logstream(fulldebug))!=NULL) + if ((ostr=c->get_logstream(fulldebug))!=NULL) { (*ostr) << "received result, decoded data: " << std::endl; boost::archive::xml_oarchive xo(*ostr); diff --git a/src/command_client.hxx b/src/command_client.hxx index 1853e9c..841609c 100644 --- a/src/command_client.hxx +++ b/src/command_client.hxx @@ -33,7 +33,7 @@ class command_client static const long long hello_timeout_usec_default=30000000; private: - client_connection &c; + client_connection *c; long long hello_timeout_usec; long long command_timeout_usec; @@ -43,12 +43,12 @@ class command_client bool check_hello(const std::string& hellostr); public: - command_client(client_connection& _c, + command_client(client_connection* _c, long long _command_timeout_usec=command_timeout_usec_default, long long _hello_timeout_usec=hello_timeout_usec_default); virtual ~command_client() {} - void replace_connection(client_connection& _c); + void replace_connection(client_connection* _c); void send_command(command* cmd, result_container &res); diff --git a/src/socket_client.cpp b/src/socket_client.cpp index 1f5dccf..6b5b481 100644 --- a/src/socket_client.cpp +++ b/src/socket_client.cpp @@ -44,6 +44,7 @@ using namespace std; namespace libt2n { +/// returns a closed connection if connection could not be established, call get_last_error_msg() for details socket_client_connection::socket_client_connection(int _port, const std::string& _server, long long _connect_timeout_usec, int _max_retries, std::ostream *_logstream, log_level_values _log_level) @@ -57,11 +58,22 @@ socket_client_connection::socket_client_connection(int _port, const std::string& set_logging(_logstream,_log_level); - tcp_connect(max_retries); + try + { + tcp_connect(max_retries); + } + catch (t2n_communication_error &e) + { + lastErrorMsg=e.what(); + LOGSTREAM(debug,"tcp connect error: " << lastErrorMsg); + close(); + } - do_callbacks(new_connection); + if (!connection::is_closed()) + do_callbacks(new_connection); } +/// returns a closed connection if connection could not be established, call get_last_error_msg() for details socket_client_connection::socket_client_connection(const std::string& _path, long long _connect_timeout_usec, int _max_retries, std::ostream *_logstream, log_level_values _log_level) @@ -74,9 +86,19 @@ socket_client_connection::socket_client_connection(const std::string& _path, set_logging(_logstream,_log_level); - unix_connect(max_retries); + try + { + unix_connect(max_retries); + } + catch (t2n_communication_error &e) + { + lastErrorMsg=e.what(); + LOGSTREAM(debug,"unix connect error: " << lastErrorMsg); + close(); + } - do_callbacks(new_connection); + if (!connection::is_closed()) + do_callbacks(new_connection); } void socket_client_connection::tcp_connect(int max_retries) @@ -114,7 +136,7 @@ void socket_client_connection::tcp_connect(int max_retries) tcp_connect(max_retries-1); } else - LOGSTREAM(debug,"no more retries left after connect error"); + throw t2n_connect_error("no more retries left after connect error"); } } @@ -142,7 +164,7 @@ void socket_client_connection::unix_connect(int max_retries) unix_connect(max_retries-1); } else - LOGSTREAM(debug,"no more retries left after connect error"); + throw t2n_connect_error("no more retries left after connect error"); } } @@ -183,25 +205,16 @@ void socket_client_connection::connect_with_timeout(struct sockaddr *sock_addr,u ret < 0 && errno==EINTR); if (ret < 0) - { - LOGSTREAM(debug,"connect_with_timeout(): select error: " << strerror(errno)); throw t2n_connect_error(string("connect() error (select): ")+strerror(errno)); - } socklen_t sopt=sizeof(int); int valopt; ret=getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &sopt); if (ret < 0 || valopt) - { - LOGSTREAM(debug,"connect_with_timeout(): getsockopt error: " << strerror(errno)); throw t2n_connect_error(string("connect() error (getsockopt): ")+strerror(errno)); - } } else - { - LOGSTREAM(debug,"connect_with_timeout(): error: " << strerror(errno)); throw t2n_connect_error(string("connect() error: ")+strerror(errno)); - } } LOGSTREAM(debug,"connect_with_timeout(): success"); @@ -217,6 +230,8 @@ void socket_client_connection::close() } /** @brief try to reconnect the current connection with the same connection credentials (host and port or path) + + @note will throw an exeption if reconnecting not possible */ void socket_client_connection::reconnect() { @@ -232,12 +247,10 @@ void socket_client_connection::reconnect() else if (type == unix_s) unix_connect(max_retries); - LOGSTREAM(debug,"reconnect(): basic connection established"); - + // connection is open now, otherwise an execption would have been thrown reopen(); LOGSTREAM(debug,"reconnect() done, client_connection::is_closed() now " << client_connection::is_closed()); - } } diff --git a/src/socket_client.hxx b/src/socket_client.hxx index c103cbb..cea491e 100644 --- a/src/socket_client.hxx +++ b/src/socket_client.hxx @@ -51,6 +51,8 @@ class socket_client_connection : public client_connection, public socket_handler std::string server; int port; + std::string lastErrorMsg; + protected: std::ostream* get_logstream(log_level_values level) @@ -81,6 +83,9 @@ class socket_client_connection : public client_connection, public socket_handler void close(); void reconnect(); + + std::string get_last_error_msg(void) + { return lastErrorMsg; } }; } diff --git a/src/socket_handler.cpp b/src/socket_handler.cpp index 7740780..dfaa23c 100644 --- a/src/socket_handler.cpp +++ b/src/socket_handler.cpp @@ -221,6 +221,7 @@ bool socket_handler::fill_buffer(std::string& buffer) char socket_buffer[recv_buffer_size]; int nbytes = read (sock, socket_buffer, recv_buffer_size); + if (nbytes < 0) { if (errno == EAGAIN) diff --git a/src/socket_wrapper.cpp b/src/socket_wrapper.cpp index d153716..ac88144 100644 --- a/src/socket_wrapper.cpp +++ b/src/socket_wrapper.cpp @@ -40,7 +40,7 @@ client_connection* BasicSocketWrapper::get_connection(void) return c.get(); } -void ReconnectSocketWrapper::handle(command_client* stubBase, boost::function< void() > f) +bool ReconnectSocketWrapper::handle(command_client* stubBase, boost::function< void() > f) { int tries=0; @@ -55,7 +55,7 @@ void ReconnectSocketWrapper::handle(command_client* stubBase, boost::function< v f(); // we were successful - return; + return true; } catch(t2n_connect_error &e) { @@ -78,44 +78,58 @@ void ReconnectSocketWrapper::handle(command_client* stubBase, boost::function< v tries++; } + + return false; } client_connection* ReconnectIgnoreFailureSocketWrapper::get_connection(void) { - client_connection* tmp; + client_connection* tmp=BasicSocketWrapper::get_connection(); - try - { - tmp=BasicSocketWrapper::get_connection(); - } - catch(t2n_connect_error &e) + if (tmp->is_closed()) { - // TODO: return some kind of dummy connection - } - catch(...) - { - throw; + // throw away the closed connection... + c.reset(); + // ...return the dummy one instead + tmp=&dc; } return tmp; } -void ReconnectIgnoreFailureSocketWrapper::handle(command_client* stubBase, boost::function< void() > f) +bool ReconnectIgnoreFailureSocketWrapper::handle(command_client* stubBase, boost::function< void() > f) { - // TODO: check for dummy connection and try to establish a real one - - try + if (!connection_established()) { - ReconnectSocketWrapper::handle(stubBase,f); - } - catch(t2n_communication_error &e) - { - // ignore + // dummy connection is in place: try to establish a real one + client_connection* tmp=get_connection(); + + if (tmp != &dc) + { + // success! we've got a real connection + stubBase->replace_connection(tmp); + } } - catch(...) + + // only try to handle the call if we've got a real connection + if (connection_established()) { - throw; + try + { + ReconnectSocketWrapper::handle(stubBase,f); + return true; + } + catch(t2n_communication_error &e) + { + // ignore + } + catch(...) + { + throw; + } } + + return false; } } diff --git a/src/socket_wrapper.hxx b/src/socket_wrapper.hxx index 51c0693..da972a2 100644 --- a/src/socket_wrapper.hxx +++ b/src/socket_wrapper.hxx @@ -62,6 +62,9 @@ class BasicSocketWrapper : public ConnectionWrapper { } client_connection* get_connection(void); + + bool connection_established(void) + { return (c.get() != NULL); } }; class ReconnectSocketWrapper : public BasicSocketWrapper @@ -79,12 +82,29 @@ class ReconnectSocketWrapper : public BasicSocketWrapper : BasicSocketWrapper(_path,_connect_timeout_usec,_max_retries) { } - void handle(command_client* stubBase, boost::function< void() > f); + bool handle(command_client* stubBase, boost::function< void() > f); }; +class dummy_client_connection : public client_connection +{ + private: + void real_write(const std::string& data) + { } + + public: + dummy_client_connection() + : client_connection() + { close(); } + + bool fill_buffer(long long usec_timeout=-1, long long *usec_timeout_remaining=NULL) + { return false; } +}; class ReconnectIgnoreFailureSocketWrapper : public ReconnectSocketWrapper { + private: + dummy_client_connection dc; + public: ReconnectIgnoreFailureSocketWrapper(int _port, const std::string& _server="127.0.0.1", long long _connect_timeout_usec=socket_client_connection::connect_timeout_usec_default, @@ -99,11 +119,9 @@ class ReconnectIgnoreFailureSocketWrapper : public ReconnectSocketWrapper { } client_connection* get_connection(void); - void handle(command_client* stubBase, boost::function< void() > f); + bool handle(command_client* stubBase, boost::function< void() > f); }; - - } #endif diff --git a/test/cmdgroup.cpp b/test/cmdgroup.cpp index fc5952b..32f8c6d 100644 --- a/test/cmdgroup.cpp +++ b/test/cmdgroup.cpp @@ -206,7 +206,7 @@ class test_cmdgroup : public TestFixture // wait till server is up sleep(1); socket_client_connection sc("./socket"); - command_client cc(sc); + command_client cc(&sc); result_container rc; cc.send_command(new testfunc4a_cmd("hello"),rc); @@ -249,7 +249,7 @@ class test_cmdgroup : public TestFixture // wait till server is up sleep(1); socket_client_connection sc("./socket"); - command_client cc(sc); + command_client cc(&sc); result_container rc; cc.send_command(new testfunc4a_cmd("hello"),rc); diff --git a/test/hello.cpp b/test/hello.cpp index 80bfec6..b9e1489 100644 --- a/test/hello.cpp +++ b/test/hello.cpp @@ -118,7 +118,7 @@ class test_hello : public TestFixture // wait till server is up sleep(1); socket_client_connection sc("./socket"); - command_client cc(sc); + command_client cc(&sc); } } } @@ -164,7 +164,7 @@ class test_hello : public TestFixture try { - command_client cc(sc); + command_client cc(&sc); } catch(t2n_version_mismatch &e) { errormsg=e.what(); } @@ -221,7 +221,7 @@ class test_hello : public TestFixture try { - command_client cc(sc); + command_client cc(&sc); } catch(t2n_version_mismatch &e) { errormsg=e.what(); } @@ -277,7 +277,7 @@ class test_hello : public TestFixture try { - command_client cc(sc); + command_client cc(&sc); } catch(t2n_version_mismatch &e) { errormsg=e.what(); } @@ -342,7 +342,7 @@ class test_hello : public TestFixture try { - command_client cc(sc); + command_client cc(&sc); } catch(t2n_version_mismatch &e) { errormsg=e.what(); } @@ -396,7 +396,7 @@ class test_hello : public TestFixture try { - command_client cc(sc); + command_client cc(&sc); } catch(t2n_version_mismatch &e) { errormsg=e.what(); } @@ -450,7 +450,7 @@ class test_hello : public TestFixture try { - command_client cc(sc); + command_client cc(&sc); } catch(t2n_version_mismatch &e) { errormsg=e.what(); } diff --git a/test/serialize.cpp b/test/serialize.cpp index 02f8a6e..85a9b58 100644 --- a/test/serialize.cpp +++ b/test/serialize.cpp @@ -156,7 +156,7 @@ class test_serialize : public TestFixture // wait till server is up sleep(1); socket_client_connection sc("./socket"); - command_client cc(sc); + command_client cc(&sc); string errormsg; diff --git a/test/simplecmd.cpp b/test/simplecmd.cpp index eb4343c..42721ea 100644 --- a/test/simplecmd.cpp +++ b/test/simplecmd.cpp @@ -162,7 +162,7 @@ class test_simplecmd : public TestFixture sleep(1); socket_client_connection sc("./socket"); sc.set_logging(&cerr,debug); - command_client cc(sc); + command_client cc(&sc); result_container rc; cc.send_command(new testfunc_cmd("hello"),rc); @@ -172,6 +172,7 @@ class test_simplecmd : public TestFixture CPPUNIT_ASSERT_EQUAL(string("hello, testfunc() was here"),ret); } } + kill(pid,SIGKILL); } void SimpleException() @@ -206,7 +207,7 @@ class test_simplecmd : public TestFixture sleep(1); socket_client_connection sc("./socket"); sc.set_logging(&cerr,debug); - command_client cc(sc); + command_client cc(&sc); result_container rc; cc.send_command(new testfunc_cmd("throw"),rc); @@ -223,6 +224,8 @@ class test_simplecmd : public TestFixture { throw; } CPPUNIT_ASSERT_EQUAL(string("throw me around"),ret); + + kill(pid,SIGKILL); } } } @@ -258,7 +261,7 @@ class test_simplecmd : public TestFixture // wait till server is up sleep(1); socket_client_connection sc("./socket"); - command_client cc(sc); + command_client cc(&sc); result_container rc; cc.send_command(new testfunc_cmd("big"),rc); @@ -266,6 +269,8 @@ class test_simplecmd : public TestFixture string ret=dynamic_cast(rc.get_result())->get_data(); CPPUNIT_ASSERT_EQUAL(string().insert(0,100*1024,'x'),ret); + + kill(pid,SIGKILL); } } } @@ -301,7 +306,7 @@ class test_simplecmd : public TestFixture // wait till server is up sleep(1); socket_client_connection sc("./socket"); - command_client cc(sc); + command_client cc(&sc); result_container rc; cc.send_command(new testfunc_cmd(string().insert(0,100*1024,'y')),rc); @@ -309,6 +314,8 @@ class test_simplecmd : public TestFixture string ret=dynamic_cast(rc.get_result())->get_data(); CPPUNIT_ASSERT_EQUAL(string().insert(0,100*1024,'y')+", testfunc() was here",ret); + + kill(pid,SIGKILL); } } } diff --git a/test/timeout.cpp b/test/timeout.cpp index 8bdfa31..6618ef6 100644 --- a/test/timeout.cpp +++ b/test/timeout.cpp @@ -206,17 +206,9 @@ class test_timeout : public TestFixture string errormsg; - try - { - socket_client_connection sc("./socket"); - command_client cc(sc,1000000,1000000); - } - catch(t2n_transfer_error &e) - { errormsg=e.what(); } - catch(...) - { throw; } + socket_client_connection sc("./socket"); - CPPUNIT_ASSERT_EQUAL(string("error reading from socket : Invalid argument"),errormsg); + CPPUNIT_ASSERT_EQUAL(true,sc.connection::is_closed()); } } } @@ -257,7 +249,7 @@ class test_timeout : public TestFixture try { - command_client cc(sc,1000000,1000000); + command_client cc(&sc,1000000,1000000); } catch(t2n_transfer_error &e) { errormsg=e.what(); } @@ -265,6 +257,8 @@ class test_timeout : public TestFixture { throw; } CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg); + + kill(pid,SIGKILL); } } } @@ -318,7 +312,7 @@ class test_timeout : public TestFixture try { - command_client cc(sc,1000000,1000000); + command_client cc(&sc,1000000,1000000); } catch(t2n_transfer_error &e) { errormsg=e.what(); } @@ -326,6 +320,8 @@ class test_timeout : public TestFixture { throw; } CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg); + + kill(pid,SIGKILL); } } } @@ -370,7 +366,7 @@ class test_timeout : public TestFixture sleep(1); socket_client_connection sc("./socket"); - command_client cc(sc,1000000,1000000); + command_client cc(&sc,1000000,1000000); result_container rc; string errormsg; @@ -385,6 +381,8 @@ class test_timeout : public TestFixture { throw; } CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg); + + kill(pid,SIGKILL); } } } @@ -444,7 +442,7 @@ class test_timeout : public TestFixture sleep(1); socket_client_connection sc("./socket"); - command_client cc(sc,1000000,1000000); + command_client cc(&sc,1000000,1000000); result_container rc; string errormsg; @@ -459,6 +457,8 @@ class test_timeout : public TestFixture { throw; } CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg); + + kill(pid,SIGKILL); } } } @@ -511,15 +511,17 @@ class test_timeout : public TestFixture { throw; } CPPUNIT_ASSERT_EQUAL(string("write() returned Broken pipe"),errormsg); + + kill(pid,SIGKILL); } } } void DisconnectOnRead() { - pid_t pid; + pid_t pid1, pid2; - switch(pid=fork()) + switch(pid1=fork()) { case -1: { @@ -563,7 +565,7 @@ class test_timeout : public TestFixture // are we still alive and able to process data? - switch(pid=fork()) + switch(pid2=fork()) { case -1: { @@ -603,13 +605,15 @@ class test_timeout : public TestFixture } } } + kill(pid1,SIGKILL); + kill(pid2,SIGKILL); } void BreakAccept() { - pid_t pid; + pid_t pid1,pid2; - switch(pid=fork()) + switch(pid1=fork()) { case -1: { @@ -653,7 +657,7 @@ class test_timeout : public TestFixture // are we still alive and able to process data? - switch(pid=fork()) + switch(pid2=fork()) { case -1: { @@ -693,6 +697,8 @@ class test_timeout : public TestFixture } } } + kill(pid1,SIGKILL); + kill(pid2,SIGKILL); } }; diff --git a/test/wrapper.cpp b/test/wrapper.cpp index 062f9b4..c820531 100644 --- a/test/wrapper.cpp +++ b/test/wrapper.cpp @@ -188,7 +188,7 @@ BOOST_CLASS_EXPORT(getserverlog_cmd) class cmd_group_x_client : public command_client { public: - cmd_group_x_client(libt2n::client_connection &_c, + cmd_group_x_client(libt2n::client_connection *_c, long long _command_timeout_usec=command_timeout_usec_default, long long _hello_timeout_usec=hello_timeout_usec_default) : libt2n::command_client(_c,_command_timeout_usec,_hello_timeout_usec) @@ -233,9 +233,10 @@ class test_wrapper : public TestFixture CPPUNIT_TEST(double_use_with_close); CPPUNIT_TEST(reconnect_after_close); CPPUNIT_TEST(reconnect_not_possible); + CPPUNIT_TEST(ignore_server_disconnect); + CPPUNIT_TEST(ignore_handler_reconnects); // TODO: missing tests: -// ignore: init, use, server die, ignore // ignore: init, no server, ignore // ignore: init, no server, ignore, server ok, connect? @@ -243,11 +244,14 @@ class test_wrapper : public TestFixture public: + pid_t child_pid; + void setUp() { - pid_t pid; + close_server=false; + kill_server=false; - switch(pid=fork()) + switch(child_pid=fork()) { case -1: { @@ -258,7 +262,7 @@ class test_wrapper : public TestFixture // child { int i=0; - while(i < 15 && !kill_server) + while(i < 10 && !kill_server) { close_server=false; @@ -267,7 +271,7 @@ class test_wrapper : public TestFixture ss.set_logging(&logstream,debug); // max 10 sec - for (; !close_server && !kill_server && i < 15; i++) + for (; !close_server && !kill_server && i < 10; i++) cs.handle(1000000); } @@ -286,7 +290,16 @@ class test_wrapper : public TestFixture } void tearDown() - { } + { + // make sure the server-child is dead before the next test runs + kill(child_pid,SIGKILL); + sleep(1); + } + + void no_init_exception() + { + CPPUNIT_ASSERT_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),std::logic_error); + } void simple_wrap() { @@ -298,11 +311,6 @@ class test_wrapper : public TestFixture CPPUNIT_ASSERT_EQUAL(2,i); } - void no_init_exception() - { - CPPUNIT_ASSERT_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),std::logic_error); - } - void double_use() { // only one connection used? @@ -376,7 +384,145 @@ class test_wrapper : public TestFixture CPPUNIT_ASSERT_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),t2n_communication_error); } + void ignore_server_disconnect() + { + wraptype::set_connection(auto_ptr + (new ReconnectIgnoreFailureSocketWrapper("./socket"))); + + // the server doens't like the beast + t2n_exec(&cmd_group_x_client::serverfunc)(666); + + int i=t2n_exec(&cmd_group_x_client::serverfunc)(1); + + // result is constructed with default constructor on error-and-ignore -> i=0 + + CPPUNIT_ASSERT_EQUAL(0,i); + } + + void ignore_handler_reconnects() + { + wraptype::set_connection(auto_ptr + (new ReconnectIgnoreFailureSocketWrapper("./socket"))); + + wraptype::get_connection_wrapper()->set_command_timeout_usec(3000000); + wraptype::get_connection_wrapper()->set_hello_timeout_usec(3000000); + + // 42 closes connection on the server side + t2n_exec(&cmd_group_x_client::serverfunc)(42); + + string out=t2n_exec(&cmd_group_x_client::getserverlog)(); + + // count the number of times that "new connection accepted" appears in the server log + string::size_type p=0; + int cnt=0; + while ((p=out.find("new connection accepted",p))++ != string::npos) + cnt++; + + CPPUNIT_ASSERT_EQUAL(2,cnt); + } + + }; CPPUNIT_TEST_SUITE_REGISTRATION(test_wrapper); + + +class test_wrapper_noserver : public TestFixture +{ + CPPUNIT_TEST_SUITE(test_wrapper_noserver); + + CPPUNIT_TEST(ignore_noserver); + CPPUNIT_TEST(ignore_finds_lateserver); + + CPPUNIT_TEST_SUITE_END(); + + public: + + pid_t child_pid; + + void setUp() + { } + + void tearDown() + { } + + void ignore_noserver() + { + wraptype::set_connection(auto_ptr + (new ReconnectIgnoreFailureSocketWrapper("./socket"))); + + // wraptype::get_connection_wrapper()->set_logging(&cerr,debug); + + // there is no server + + int i=t2n_exec(&cmd_group_x_client::serverfunc)(1); + + // result is constructed with default constructor on error-and-ignore -> i=0 + + CPPUNIT_ASSERT_EQUAL(0,i); + } + + void ignore_finds_lateserver() + { + wraptype::set_connection(auto_ptr + (new ReconnectIgnoreFailureSocketWrapper("./socket"))); + + // there is no server + t2n_exec(&cmd_group_x_client::serverfunc)(1); + + // launch a server + + close_server=false; + kill_server=false; + + switch(child_pid=fork()) + { + case -1: + { + CPPUNIT_FAIL("fork error"); + break; + } + case 0: + // child + { + int i=0; + while(i < 10 && !kill_server) + { + close_server=false; + + socket_server ss("./socket"); + group_command_server cs(ss); + ss.set_logging(&logstream,debug); + + // max 10 sec + for (; !close_server && !kill_server && i < 10; i++) + cs.handle(1000000); + } + + // don't call atexit and stuff + _exit(0); + } + + default: + // parent + { + // wait till server is up + sleep(1); + } + } + + // server should be active + int i=t2n_exec(&cmd_group_x_client::serverfunc)(1); + + CPPUNIT_ASSERT_EQUAL(2,i); + + // make sure the server-child is dead before the next test runs + kill(child_pid,SIGKILL); + sleep(1); + } + + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(test_wrapper_noserver); -- 1.7.1