/*************************************************************************** * Copyright (C) 2004 by Intra2net AG * * info@intra2net.com * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif using namespace std; using namespace libt2n; using namespace CppUnit; // this is an evil hack to get access to real_write, don't ever do this in an app!!! class real_write_connection: public socket_server_connection { public: void real_write(const std::string& data) { socket_write(data); } }; class test_reconnect : public TestFixture { CPPUNIT_TEST_SUITE(test_reconnect); CPPUNIT_TEST(simple_reconnect); CPPUNIT_TEST(reconnect_with_close); CPPUNIT_TEST(reconnect_buffer_complete); CPPUNIT_TEST(reconnect_buffer_several_complete); CPPUNIT_TEST(reconnect_buffer_no_incomplete1); CPPUNIT_TEST(reconnect_buffer_no_incomplete2); CPPUNIT_TEST_SUITE_END(); pid_t child_pid; public: void setUp() { } void tearDown() { // make sure the server-child is dead before the next test runs kill(child_pid,SIGKILL); sleep(1); } void send_raw_socket(string hello_string, socket_server* ss, int conn_id) { socket_server_connection *ssc=dynamic_cast(ss->get_connection(conn_id)); // this is an evil hack to get access to real_write, don't ever do this in an app!!! real_write_connection *rwc=(real_write_connection*)ssc; rwc->real_write(hello_string); } void simple_reconnect() { switch(child_pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); time_t t0 = time(NULL); // max 10 sec while (time(NULL) < t0 + 10 ) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); if (data=="QUIT") break; if (data=="x") con->write(string().insert(0,100,'X')); else con->write(string().insert(0,100,'Y')); } } // don't call atexit and stuff _exit(0); } default: // parent { // don't kill us on broken pipe signal(SIGPIPE, SIG_IGN); // wait till server is up sleep(1); socket_client_connection sc("./socket"); sc.write("abc"); string data; while (!sc.get_packet(data)) sc.fill_buffer(1000000); sc.reconnect(); sc.write("x"); while (!sc.get_packet(data)) sc.fill_buffer(1000000); CPPUNIT_ASSERT_EQUAL(string().insert(0,100,'X'),data); } } } void reconnect_with_close() { switch(child_pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); time_t t0 = time(NULL); // max 10 sec while (time(NULL) < t0 + 10 ) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); if (data=="QUIT") break; if (data=="x") con->write(string().insert(0,100,'X')); else con->write(string().insert(0,100,'Y')); } } // don't call atexit and stuff _exit(0); } default: // parent { // don't kill us on broken pipe signal(SIGPIPE, SIG_IGN); // wait till server is up sleep(1); socket_client_connection sc("./socket"); sc.write("abc"); string data; while (!sc.get_packet(data)) sc.fill_buffer(1000000); sc.close(); // empty buffer sc.get_packet(data); sc.reconnect(); sc.write("x"); while (!sc.get_packet(data)) sc.fill_buffer(1000000); CPPUNIT_ASSERT_EQUAL(string().insert(0,100,'X'),data); } } } void reconnect_buffer_complete() { switch(child_pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); time_t t0 = time(NULL); // max 10 sec while (time(NULL) < t0 + 10 ) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); if (data=="QUIT") break; if (data=="x") con->write(string().insert(0,100,'X')); } } // don't call atexit and stuff _exit(0); } default: // parent { // don't kill us on broken pipe signal(SIGPIPE, SIG_IGN); // wait till server is up sleep(1); socket_client_connection sc("./socket"); sc.write("x"); string data; while (!sc.packet_available()) sc.fill_buffer(1000000); sc.reconnect(); CPPUNIT_ASSERT_EQUAL_MESSAGE("packet not there",true,sc.get_packet(data)); CPPUNIT_ASSERT_EQUAL_MESSAGE("data incorrect",string().insert(0,100,'X'),data); } } } void reconnect_buffer_several_complete() { const int packets=3; switch(child_pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); time_t t0 = time(NULL); // max 10 sec while (time(NULL) < t0 + 10 ) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); if (data=="QUIT") break; if (data=="x") { for (int i=0; iwrite(string().insert(0,100,'X')); } } } // don't call atexit and stuff _exit(0); } default: // parent { // don't kill us on broken pipe signal(SIGPIPE, SIG_IGN); // wait till server is up sleep(1); socket_client_connection sc("./socket"); sc.write("x"); // retrieve packets for 3 seconds time_t t0 = time(NULL); // max 3 sec while (time(NULL) < t0 + 3 ) sc.fill_buffer(1000000); // we now should have packets complete packets in the buffer sc.reconnect(); // are these packets still there? for (int i=0; i < packets; i++) { string data; ostringstream os; os << "packet " << i << " not there"; CPPUNIT_ASSERT_EQUAL_MESSAGE(os.str(),true,sc.get_packet(data)); os.str(""); os << "packet " << i << " incorrect"; CPPUNIT_ASSERT_EQUAL_MESSAGE(os.str(),string().insert(0,100,'X'),data); } } } } void reconnect_buffer_no_incomplete1() { switch(child_pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); time_t t0 = time(NULL); // max 10 sec while (time(NULL) < t0 + 10 ) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); if (data=="QUIT") break; if (data=="x") { con->write(string().insert(0,100,'X')); send_raw_socket("aaaab",&ss,cid); } } } // don't call atexit and stuff _exit(0); } default: // parent { // don't kill us on broken pipe signal(SIGPIPE, SIG_IGN); // wait till server is up sleep(1); socket_client_connection sc("./socket"); sc.write("x"); // retrieve packets for 3 seconds time_t t0 = time(NULL); // max 3 sec while (time(NULL) < t0 + 3 ) sc.fill_buffer(1000000); // we now should have one complete packet and some stuff in the buffer string data; sc.get_packet(data); CPPUNIT_ASSERT_EQUAL_MESSAGE("no incomplete packet",true,(sc.peek_packet(data))>0); sc.reconnect(); CPPUNIT_ASSERT_EQUAL_MESSAGE("incomplete packet not removed",0,(int)sc.peek_packet(data)); } } } void reconnect_buffer_no_incomplete2() { switch(child_pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); time_t t0 = time(NULL); // max 10 sec while (time(NULL) < t0 + 10 ) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); if (data=="QUIT") break; if (data=="x") { con->write(string().insert(0,100,'X')); string blob=string().insert(0,100,'Y'); // one byte will be missing... int size=blob.size()+1; char sizetransfer[sizeof(int)+1]; memcpy(sizetransfer,(void*)&size,sizeof(int)); sizetransfer[sizeof(int)+1]=0; string packet=string(sizetransfer)+blob; send_raw_socket(packet,&ss,cid); } } } // don't call atexit and stuff _exit(0); } default: // parent { // don't kill us on broken pipe signal(SIGPIPE, SIG_IGN); // wait till server is up sleep(1); socket_client_connection sc("./socket"); sc.write("x"); // retrieve packets for 3 seconds time_t t0 = time(NULL); // max 3 sec while (time(NULL) < t0 + 3 ) sc.fill_buffer(1000000); // we now should have one complete packet and some stuff in the buffer sc.reconnect(); string data; CPPUNIT_ASSERT_EQUAL_MESSAGE("packet not there",true,sc.get_packet(data)); CPPUNIT_ASSERT_EQUAL_MESSAGE("data incorrect",string().insert(0,100,'X'),data); CPPUNIT_ASSERT_EQUAL_MESSAGE("incomplete packet not removed",0,(int)sc.peek_packet(data)); } } } }; CPPUNIT_TEST_SUITE_REGISTRATION(test_reconnect);