diff options
author | dwcraig <dwcraig@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2004-10-06 16:14:22 +0000 |
---|---|---|
committer | dwcraig <dwcraig@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2004-10-06 16:14:22 +0000 |
commit | 670b477869572d5f90754d148e49610240fbad1f (patch) | |
tree | 10cf48cd25c00851bdc5f032413c96231a0bc200 | |
parent | 8812a69ed819c304b31badfec8226f73fcc908e1 (diff) | |
download | ATCD-670b477869572d5f90754d148e49610240fbad1f.tar.gz |
Add Association::abort() and a simple test case.
-rw-r--r-- | ace/SOCK_SEQPACK_Association.cpp | 27 | ||||
-rw-r--r-- | ace/SOCK_SEQPACK_Association.h | 6 | ||||
-rw-r--r-- | tests/SOCK_SEQPACK_SCTP_Test.cpp | 378 | ||||
-rw-r--r-- | tests/run_test.lst | 1 | ||||
-rw-r--r-- | tests/tests.mpc | 7 |
5 files changed, 419 insertions, 0 deletions
diff --git a/ace/SOCK_SEQPACK_Association.cpp b/ace/SOCK_SEQPACK_Association.cpp index 89fa0ba95eb..671da106056 100644 --- a/ace/SOCK_SEQPACK_Association.cpp +++ b/ace/SOCK_SEQPACK_Association.cpp @@ -39,6 +39,33 @@ ACE_SOCK_SEQPACK_Association::close (void) return ACE_SOCK::close (); } +// Developed according to the API discussed in 7.1.4 of +// draft-ietf-tsvwg-sctpsocket-09.txt to abruptly free a transport +// transport association's resources. +int +ACE_SOCK_SEQPACK_Association::abort (void) +{ + // + // setsockopt() SO_LINGER configures socket to reap immediately. + // Normal close then aborts the association. + // + linger slinger; + + slinger.l_onoff = 1; + slinger.l_linger = 0; + + if (-1 == ACE_OS::setsockopt (this->get_handle (), + SOL_SOCKET, + SO_LINGER, + ACE_reinterpret_cast (const char *, &slinger), + sizeof (linger))) + { + return -1; + } + + return this->close (); +} + int ACE_SOCK_SEQPACK_Association::get_local_addrs (ACE_INET_Addr *addrs, size_t &size) const { diff --git a/ace/SOCK_SEQPACK_Association.h b/ace/SOCK_SEQPACK_Association.h index 9f25a91e6f0..b2ea5896adb 100644 --- a/ace/SOCK_SEQPACK_Association.h +++ b/ace/SOCK_SEQPACK_Association.h @@ -174,6 +174,12 @@ public: * the close to avoid losing data). */ int close (void); + /** + * Abort the association according to RFC 2960 9.1 through the API + * in draft-ietf-tsvwg-sctpsocket-09 7.1.4. + */ + int abort (void); + // = Meta-type info typedef ACE_Multihomed_INET_Addr PEER_ADDR; diff --git a/tests/SOCK_SEQPACK_SCTP_Test.cpp b/tests/SOCK_SEQPACK_SCTP_Test.cpp new file mode 100644 index 00000000000..593516e9f3b --- /dev/null +++ b/tests/SOCK_SEQPACK_SCTP_Test.cpp @@ -0,0 +1,378 @@ +// $Id$ +// +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// SOCK_SEQPACK_SCTP_Test.cpp +// +// = DESCRIPTION +// Performs several tests on the ACE_SOCK_SEQPACK_Connector, +// ACE_SOCK_SEQPACK_Acceptor, and ACE_SOCK_SEQPACK_Association classes +// specifically for SCTP using the loopback interface. Attempts to +// replicate behavior of SOCK_Test.cpp, but integrating IPv6 tests +// directly. +// +// = AUTHOR +// Dave Craig <dwc@qualcomm.com> + +#include "test_config.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_select.h" +#include "ace/OS_NS_sys_wait.h" +#include "ace/SOCK_SEQPACK_Connector.h" +#include "ace/SOCK_SEQPACK_Acceptor.h" +#include "ace/Thread_Manager.h" +#include "ace/Handle_Set.h" + +#define TTCPPORT 5001 +#define BYTE_MESG 0xcd + +struct tdesc { + ACE_Thread_Semaphore *tsemap; + bool ipv6_test; +}; + +typedef struct tdesc tdesc_t; + +#ifdef ACE_WIN64 +// This arg is ignored on Windows and causes pointer truncation +// warnings on 64-bit compiled. +#define SELECT_WIDTH(x) 0 +#else +#define SELECT_WIDTH(x) (x) +#endif + +void * +Server (void *arg) +{ + ACE_SOCK_SEQPACK_Acceptor *AcceptorSocket = + ACE_reinterpret_cast (ACE_SOCK_SEQPACK_Acceptor *, arg); + + ACE_SOCK_SEQPACK_Association Stream; + + ACE_Handle_Set handle_set; + + const ACE_Time_Value def_timeout (ACE_DEFAULT_TIMEOUT); + + ACE_Time_Value tv (def_timeout); + + int select_width; + + int result; + + // + // Make sure AcceptorSocket is in nonblocking mode so as not to + // hang tests. + // + if (-1 == AcceptorSocket->enable (ACE_NONBLOCK)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("AcceptorSocket.enable (ACE_NONBLOCK)"))); + } + + // + // Set up select to wait for I/O events. + // + handle_set.reset (); + handle_set.set_bit (AcceptorSocket->get_handle ()); + + select_width = SELECT_WIDTH(int (AcceptorSocket->get_handle ()) + 1); + + result = ACE_OS::select(select_width, + handle_set, + 0, + 0, + &tv); + + ACE_ASSERT (tv == def_timeout); + + if (-1 == result) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("select")), + 0); + } + else if (0 == result) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("(%P|%t) select timed out, shutting down\n")), + 0); + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) waiting for client to connect\n"))); + + while (-1 != AcceptorSocket->accept (Stream)) { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) client connected\n"))); + + // + // Enable non-blocking I/O. + // + if (Stream.enable (ACE_NONBLOCK)) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("Stream.enable (ACE_NONBLOCK)")), + 0); + } + + char byte = BYTE_MESG; + + if (-1 == Stream.send_n (&byte, 1)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("Stream.send_n"))); + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) byte sent\n"))); + + // + // Ubruptly terminate the association. + // + if (-1 == Stream.abort ()) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("Association.abort"))); + } + + // + // Negative test: make sure that we cannot send on a closed association. + // + if (-1 != Stream.send_n (&byte, 1)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Negative test fail: Association") + ACE_TEXT(".send_n succeeded after abort()\n"))); + } + + } + + // + // Close server socket. + // + if (-1 == AcceptorSocket->close ()) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("AcceptorSocket.close"))); + } + + return NULL; +} + +void * +Client(void *arg) +{ + ACE_Multihomed_INET_Addr *ServerAddr = + ACE_reinterpret_cast (ACE_Multihomed_INET_Addr *, arg); + + ACE_SOCK_SEQPACK_Connector Connector; + + ACE_SOCK_SEQPACK_Association Stream; + + ACE_Time_Value tv (ACE_DEFAULT_TIMEOUT); + + char b; + size_t bytes; + + if (-1 == Connector.connect (Stream, + *ServerAddr, + &tv, + ACE_Addr::sap_any, + 1)) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p to %s:%d\n"), + ACE_TEXT ("Connector.connect"), + ServerAddr->get_host_name (), + ServerAddr->get_port_number ()), + 0); + } + + if (-1 == Stream.disable (ACE_NONBLOCK)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("Association.disable (ACE_NONBLOCK)"))); + } + + + if (-1 == Stream.recv_n (&b, 1, &tv, &bytes)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("Association.recv_n"))); + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Client received %d bytes\n"), + bytes)); + ACE_ASSERT(1 == bytes); + + // + // Give server a little time to abort the association. + // + ACE_OS::sleep(1); + + if (-1 != Stream.recv_n (&b, 1, &tv, &bytes)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Negative test failed Association") + ACE_TEXT (".recv_n succeeded after abort()\n"))); + } + + return NULL; +} + +// +// Spawn server and client threads and then wait until they complete the +// test. There must be a timeout on the wait, so executable does not hang the +// tests indefinitely. +// +int +spawn_test(bool ipv6_test) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) spawn_test started ipv6 %d\n"), + ipv6_test)); + + ACE_SOCK_SEQPACK_Acceptor AcceptorSocket; + + ACE_Multihomed_INET_Addr ServerAddr (TTCPPORT, +#ifdef ACE_HAS_IPV6 + (ipv6_test ? + ACE_IPV6_LOCALHOST : + ACE_LOCALHOST) +#else /* ! ACE_HAS_IPV6 */ + ACE_LOCALHOST +#endif /* ! ACE_HAS_IPV6 */ + ) + + if (-1 == AcceptorSocket.open (ServerAddr, + 1, +#ifdef ACE_HAS_IPV6 + (ipv6_test ? AF_INET6 : AF_INET), +#else /* ! ACE_HAS_IPV6 */ + AF_INET, +#endif /* ! ACE_HAS_IPV6 */ + ACE_DEFAULT_BACKLOG, + IPPROTO_SCTP)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("AcceptorSocket.open"))); + } + + if (-1 == AcceptorSocket.get_local_addr (ServerAddr)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("AcceptorSocket.get_local_addr"))); + } + + struct sockaddr_in inaddr; + + ServerAddr.get_addresses(&inaddr, 1); + + ACE_ASSERT ((TTCPPORT == ServerAddr.get_port_number ())); + ACE_ASSERT ((ipv6_test || INADDR_LOOPBACK == ServerAddr.get_ip_address ())); + ACE_ASSERT ((!ipv6_test || + ACE_Multihomed_INET_Addr(TTCPPORT, "::1") == ServerAddr)); + +#ifndef ACE_LACKS_FORK + switch (ACE_OS::fork ("child")) + { + case -1: + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p%a"), + ACE_TEXT ("fork failed"))); + break; + case 0: + Client (&ServerAddr); + exit (0); + break; + default: + Server (ACE_reinterpret_cast(void *, &AcceptorSocket)); + ACE_OS::wait (); + break; + } +#elif defined (ACE_HAS_THREADS) + if (-1 == ACE_Thread_Manager::instance ()->spawn + (Server, + ACE_reinterpret_cast(void *, &ServerSocket), + THR_NEW_LWP | THR_DETACHED)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p%a"), + ACE_TEXT ("thread create failed"))); + } + + if (-1 == ACE_Thread_Manager::instance ()->spawn + (Client, + ACE_reinterpret_cast(void *, &ServerAddr), + THR_NEW_LWP | THR_DETACHED)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p%a"), + ACE_TEXT ("thread create failed"))); + } + + ACE_Thread_Manager::instance ()->wait (); +#else /* ACE_LACKS_FORK && ! ACE_HAS_THREADS */ + ACE_ERROR ((LM_DEBUG, + ACE_TEXT ("(%P|%t) \n"), + ACE_TEXT ("only one thread may be run ") + ACE_TEXT ("in a process on this platform\n"))); +#endif /* ACE_LACKS_FORK && ! ACE_HAS_THREADS */ + + return 0; +} + +int +do_test(void) +{ + spawn_test(false); + +#ifdef ACE_HAS_IPV6 + spawn_test(true); +#endif + + return 0; +} + +int run_main (int argc, ACE_TCHAR *argv[]) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + ACE_START_TEST (ACE_TEXT ("SOCK_SEQPACK_SCTP")); + + // + // Check whether host OS has SCTP support before starting this test. + // If not, just pass because there is not a hope of testing + // SOCK_SEQPACK. + // + int status = 0; + +#ifdef ACE_HAS_SCTP + status = do_test(); +#else /* ! ACE_HAS_SCTP */ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT("SCTP not supported by ACE.\n") + ACE_TEXT("This test will not do anything.\n"))); +#endif /* ! ACE_HAS_SCTP */ + + ACE_END_TEST; + + return status; +} + diff --git a/tests/run_test.lst b/tests/run_test.lst index 31f98fa4959..50053cc1bd9 100644 --- a/tests/run_test.lst +++ b/tests/run_test.lst @@ -151,6 +151,7 @@ Proactor_Test_IPV6 SOCK_Send_Recv_Test_IPV6 SOCK_Dgram_Test SOCK_Dgram_Bcast_Test +SOCK_SEQPACK_SCTP_Test: !MSVC SOCK_Test_IPv6 Process_Strategy_Test: !chorus !LynxOS !VxWorks Recursive_Condition_Bug_Test: !ST diff --git a/tests/tests.mpc b/tests/tests.mpc index 3f095333743..51fb3c39002 100644 --- a/tests/tests.mpc +++ b/tests/tests.mpc @@ -1131,6 +1131,13 @@ project(SOCK_Dgram_Bcast_Test) : acetest { } } +project(SOCK_SEQPACK_SCTP_Test) : scetest { + exename = SOCK_SEQPACK_SCTP_Test + Source_Files { + SOCK_SEQPACK_SCTP_Test.cpp + } +} + project(QtReactor Test) : acetest, ace_qt, qt_moc { exename = QtReactor_Test requires += qt |