From 91730468439e21dcf8d275d0f70d803c20ccaa7c Mon Sep 17 00:00:00 2001 From: Gerd v. Egidy Date: Sat, 28 Oct 2006 00:57:25 +0000 Subject: [PATCH] libt2n: (gerd) client callbacks --- src/client.cpp | 40 +++++++++++++++- src/client.hxx | 16 ++++++ src/socket_client.cpp | 2 + test/callback.cpp | 127 +++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 176 insertions(+), 9 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 2ce213b..96b2554 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -25,11 +25,49 @@ namespace libt2n { client_connection::client_connection() - : connection() + : connection(), callbacks(__events_end) { set_logging(NULL,none); } +client_connection::~client_connection() +{ + // we want the connection_closed callbacks to be called before + close(); + + do_callbacks(connection_deleted); +} + +void client_connection::close() +{ + if (!is_closed()) + { + connection::close(); + do_callbacks(connection_closed); + } +} + +/** @brief add a callback + + @param event event the function will be called at + @param func functor (see boost function) that will be called + + @example use boost::bind to bind to member functions and parameters like this: + int this example 17 is a fixed parameter that is always added to the call + c.add_callback(connection_closed,bind(&my_class::func_to_call_back, boost::ref(*this), 17)); +*/ +void client_connection::add_callback(callback_event_type event, const boost::function& func) +{ + callbacks[event].push_back(func); +} + +void client_connection::do_callbacks(callback_event_type event) +{ + std::list >::iterator i,ie=callbacks[event].end(); + for (i=callbacks[event].begin(); i != ie; i++) + (*i)(); +} + /// get pointer to logging stream, returns NULL if no logging needed std::ostream* client_connection::get_logstream(log_level_values level) { diff --git a/src/client.hxx b/src/client.hxx index 91c17b9..c639bb1 100644 --- a/src/client.hxx +++ b/src/client.hxx @@ -20,6 +20,10 @@ #define __LIBT2N_CLIENT #include +#include +#include + +#include #include "connection.hxx" #include "types.hxx" @@ -35,12 +39,24 @@ class client_connection : public connection log_level_values log_level; std::ostream *logstream; + /// vector initialized for all callback-types, all elements in each list will be called + std::vector > > callbacks; + + protected: + void do_callbacks(callback_event_type event); + public: client_connection(); + virtual ~client_connection(); + + void close(); + void set_logging(std::ostream *_logstream, log_level_values _log_level); std::ostream* get_logstream(log_level_values level); + + void add_callback(callback_event_type event, const boost::function& func); }; } diff --git a/src/socket_client.cpp b/src/socket_client.cpp index 7406f28..067b033 100644 --- a/src/socket_client.cpp +++ b/src/socket_client.cpp @@ -109,6 +109,8 @@ void socket_client_connection::connect() throw t2n_connect_error(string("invalid connection type")); set_socket_options(sock); + + do_callbacks(new_connection); } void socket_client_connection::close() diff --git a/test/callback.cpp b/test/callback.cpp index beb0c77..9d4c7d1 100644 --- a/test/callback.cpp +++ b/test/callback.cpp @@ -33,10 +33,12 @@ class test_callback : public TestFixture { CPPUNIT_TEST_SUITE(test_callback); - CPPUNIT_TEST(NewConnCallback); - CPPUNIT_TEST(ConnClosedCallback); - CPPUNIT_TEST(ConnDeletedCallback); - CPPUNIT_TEST(CallbackOrder); + CPPUNIT_TEST(ServerNewConnCallback); + CPPUNIT_TEST(ServerConnClosedCallback); + CPPUNIT_TEST(ServerConnDeletedCallback); + CPPUNIT_TEST(ServerCallbackOrder); + CPPUNIT_TEST(ClientConnClosedCallback); + CPPUNIT_TEST(ClientConnDeletedCallback); CPPUNIT_TEST_SUITE_END(); @@ -63,7 +65,7 @@ class test_callback : public TestFixture callback_done[ev]=true; } - void NewConnCallback() + void ServerNewConnCallback() { pid_t pid; @@ -124,7 +126,7 @@ class test_callback : public TestFixture } } - void ConnClosedCallback() + void ServerConnClosedCallback() { pid_t pid; @@ -185,7 +187,7 @@ class test_callback : public TestFixture } } - void ConnDeletedCallback() + void ServerConnDeletedCallback() { pid_t pid; @@ -249,7 +251,7 @@ class test_callback : public TestFixture } } - void CallbackOrder() + void ServerCallbackOrder() { pid_t pid; @@ -332,6 +334,115 @@ class test_callback : public TestFixture } } + void ClientConnClosedCallback() + { + pid_t pid; + + switch(pid=fork()) + { + case -1: + { + CPPUNIT_FAIL("fork error"); + break; + } + case 0: + // child + { + socket_server ss("./socket"); + + // max 3 sec + for (int i=0; i < 3; i++) + { + ss.fill_buffer(1000000); + + string data; + unsigned int cid; + if(ss.get_packet(data,cid)) + break; + } + // don't call atexit and stuff + _exit(0); + } + + default: + // parent + { + string data; + // wait till server is up + sleep(1); + + socket_client_connection sc("./socket"); + + sc.add_callback(connection_closed,bind(&test_callback::callback_func, boost::ref(*this), connection_closed, 0)); + + sc.write("ABC"); + + // wait half a sec + sc.fill_buffer(500000); + sc.get_packet(data); + + CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[new_connection])); + CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_closed])); + CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_deleted])); + } + } + } + + void ClientConnDeletedCallback() + { + pid_t pid; + + switch(pid=fork()) + { + case -1: + { + CPPUNIT_FAIL("fork error"); + break; + } + case 0: + // child + { + socket_server ss("./socket"); + + // max 3 sec + for (int i=0; i < 3; i++) + { + ss.fill_buffer(1000000); + + string data; + unsigned int cid; + if(ss.get_packet(data,cid)) + break; + } + // don't call atexit and stuff + _exit(0); + } + + default: + // parent + { + string data; + // wait till server is up + sleep(1); + + { + socket_client_connection sc("./socket"); + + sc.add_callback(connection_deleted,bind(&test_callback::callback_func, boost::ref(*this), connection_deleted, 0)); + + sc.write("ABC"); + + // wait half a sec + sc.fill_buffer(500000); + sc.get_packet(data); + } + + CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[new_connection])); + CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_closed])); + CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_deleted])); + } + } + } }; CPPUNIT_TEST_SUITE_REGISTRATION(test_callback); -- 1.7.1