summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordwcraig <dwcraig@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2004-10-06 16:14:22 +0000
committerdwcraig <dwcraig@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2004-10-06 16:14:22 +0000
commit670b477869572d5f90754d148e49610240fbad1f (patch)
tree10cf48cd25c00851bdc5f032413c96231a0bc200
parent8812a69ed819c304b31badfec8226f73fcc908e1 (diff)
downloadATCD-670b477869572d5f90754d148e49610240fbad1f.tar.gz
Add Association::abort() and a simple test case.
-rw-r--r--ace/SOCK_SEQPACK_Association.cpp27
-rw-r--r--ace/SOCK_SEQPACK_Association.h6
-rw-r--r--tests/SOCK_SEQPACK_SCTP_Test.cpp378
-rw-r--r--tests/run_test.lst1
-rw-r--r--tests/tests.mpc7
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