libt2n: (gerd) fix client-connection-logic, finish wrappers, all tests are working...
authorGerd v. Egidy <gerd.von.egidy@intra2net.com>
Sun, 24 Aug 2008 21:41:21 +0000 (21:41 +0000)
committerGerd v. Egidy <gerd.von.egidy@intra2net.com>
Sun, 24 Aug 2008 21:41:21 +0000 (21:41 +0000)
16 files changed:
examples/minimalistic-client-stub.hxx
examples/minimalistic-client.cpp
src/client_wrapper.hxx
src/command_client.cpp
src/command_client.hxx
src/socket_client.cpp
src/socket_client.hxx
src/socket_handler.cpp
src/socket_wrapper.cpp
src/socket_wrapper.hxx
test/cmdgroup.cpp
test/hello.cpp
test/serialize.cpp
test/simplecmd.cpp
test/timeout.cpp
test/wrapper.cpp

index b17baca..7ad998d 100644 (file)
@@ -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)
index 35ef13c..9918c2e 100644 (file)
@@ -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;
 }
index 672308e..ebc9e25 100644 (file)
@@ -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<Client> stub(new Client(*(WrappedConnection->get_connection()),
+            std::auto_ptr<Client> 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<R>::type result;
+
+            // bind our Client-object and the local result
             detail::Call<R> 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<R>::type();
+            }
             return result;
         }
 
index 0f44203..8ccbf10 100644 (file)
@@ -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<callback_event_type>(0);
         e < __events_end;
         e=static_cast<callback_event_type>(static_cast<int>(e)+1))
     {
-        list<boost::function<void ()> > evcb=c.get_callback_list(e);
+        list<boost::function<void ()> > evcb=c->get_callback_list(e);
 
         for (list<boost::function<void ()> >::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);
index 1853e9c..841609c 100644 (file)
@@ -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);
 
index 1f5dccf..6b5b481 100644 (file)
@@ -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());
-
 }
 
 }
index c103cbb..cea491e 100644 (file)
@@ -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; }
 };
 
 }
index 7740780..dfaa23c 100644 (file)
@@ -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)
index d153716..ac88144 100644 (file)
@@ -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;
 }
 
 }
index 51c0693..da972a2 100644 (file)
@@ -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
index fc5952b..32f8c6d 100644 (file)
@@ -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);
index 80bfec6..b9e1489 100644 (file)
@@ -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(); }
index 02f8a6e..85a9b58 100644 (file)
@@ -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;
 
index eb4343c..42721ea 100644 (file)
@@ -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<testfunc_res*>(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<testfunc_res*>(rc.get_result())->get_data();
 
                 CPPUNIT_ASSERT_EQUAL(string().insert(0,100*1024,'y')+", testfunc() was here",ret);
+
+                kill(pid,SIGKILL);
             }
         }
     }
index 8bdfa31..6618ef6 100644 (file)
@@ -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);
     }
 };
 
index 062f9b4..c820531 100644 (file)
@@ -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<ConnectionWrapper>
+            (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<ConnectionWrapper>
+            (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<ConnectionWrapper>
+            (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<ConnectionWrapper>
+            (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<cmd_group_x> 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);