Squashed 'third_party/lksctp-tools/' content from commit 200eca7f1
Change-Id: I8f7575513f114b205178cac5c6b3706f3d725cb5
git-subtree-dir: third_party/lksctp-tools
git-subtree-split: 200eca7f1419b1ae53958b51e8551f7e7f6cd467
diff --git a/src/func_tests/test_sctp_sendrecvmsg.c b/src/func_tests/test_sctp_sendrecvmsg.c
new file mode 100644
index 0000000..ceccd5a
--- /dev/null
+++ b/src/func_tests/test_sctp_sendrecvmsg.c
@@ -0,0 +1,370 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2003
+ * Copyright (c) 2003 Intel Corp.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * To compile the v6 version, set the symbol TEST_V6 to 1.
+ *
+ * Written or modified by:
+ * Ardelle Fan <ardelle.fan@intel.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/* This is a basic functional test for the SCTP new library APIs
+ * sctp_sendmsg() and sctp_recvmsg(). test_timetolive.c is rewritten using
+ * these new APIs.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 10;
+int TST_CNT = 0;
+
+/* RCVBUF value, and indirectly RWND*2 */
+#define SMALL_RCVBUF 3000
+#define SMALL_MAXSEG 500
+/* This is extra data length to ensure rwnd closes */
+#define RWND_SLOP 100
+static char *fillmsg = NULL;
+static char *ttlmsg = "This should time out!\n";
+static char *nottlmsg = "This should NOT time out!\n";
+static char ttlfrag[SMALL_MAXSEG*3] = {0};
+static char *message = "Hello world\n";
+
+int main(int argc, char *argv[])
+{
+ int sk1, sk2;
+ sockaddr_storage_t loop1;
+ sockaddr_storage_t loop2;
+ sockaddr_storage_t msgname;
+ int error;
+ int pf_class;
+ uint32_t ppid;
+ uint32_t stream;
+ struct sctp_event_subscribe subscribe;
+ char *big_buffer;
+ int offset, msg_flags;
+ socklen_t msgname_len;
+ size_t buflen;
+ struct sctp_send_failed *ssf;
+ struct sctp_sndrcvinfo sinfo;
+ struct sctp_sndrcvinfo snd_sinfo;
+ sctp_assoc_t associd1;
+ socklen_t len, oldlen;
+ struct sctp_status gstatus;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Set some basic values which depend on the address family. */
+#if TEST_V6
+ pf_class = PF_INET6;
+
+ loop1.v6.sin6_family = AF_INET6;
+ loop1.v6.sin6_addr = in6addr_loopback;
+ loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v6.sin6_family = AF_INET6;
+ loop2.v6.sin6_addr = in6addr_loopback;
+ loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
+#else
+ pf_class = PF_INET;
+
+ loop1.v4.sin_family = AF_INET;
+ loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v4.sin_family = AF_INET;
+ loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
+#endif /* TEST_V6 */
+
+ /* Create the two endpoints which will talk to each other. */
+ sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ /* Set the MAXSEG to something smallish. */
+ {
+ int val = SMALL_MAXSEG;
+ test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
+ }
+
+ memset(&subscribe, 0, sizeof(subscribe));
+ subscribe.sctp_data_io_event = 1;
+ subscribe.sctp_association_event = 1;
+ subscribe.sctp_send_failure_event = 1;
+ test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
+ test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
+
+ /* Bind these sockets to the test ports. */
+ test_bind(sk1, &loop1.sa, sizeof(loop1));
+ test_bind(sk2, &loop2.sa, sizeof(loop2));
+
+ /*
+ * Set the RWND small so we can fill it up easily.
+ */
+ len = sizeof(int);
+ error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &oldlen, &len);
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
+ strerror(errno));
+
+ len = SMALL_RCVBUF; /* Really becomes 2xlen when set. */
+
+ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
+ if (error)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
+ strerror(errno));
+
+ /* Mark sk2 as being able to accept new associations. */
+ test_listen(sk2, 1);
+
+ /* Send the first message. This will create the association. */
+ ppid = rand();
+ stream = 1;
+ test_sctp_sendmsg(sk1, message, strlen(message) + 1,
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 0, 0);
+
+ tst_resm(TPASS, "sctp_sendmsg");
+
+ /* Get the communication up message on sk2. */
+ buflen = REALLY_BIG;
+ big_buffer = test_malloc(buflen);
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+#if 0
+ associd2 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id;
+#endif
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+
+ /* Get the communication up message on sk1. */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk1, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ associd1 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id;
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+
+ tst_resm(TPASS, "sctp_recvmsg SCTP_COMM_UP notification");
+
+ /* Get the first message which was sent. */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
+ strlen(message) + 1, MSG_EOR, stream, ppid);
+
+ tst_resm(TPASS, "sctp_recvmsg data");
+
+ /* Figure out how big to make our fillmsg */
+ len = sizeof(struct sctp_status);
+ memset(&gstatus,0,sizeof(struct sctp_status));
+ gstatus.sstat_assoc_id = associd1;
+ error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
+ strerror(errno));
+ tst_resm(TINFO, "creating a fillmsg of size %d",
+ gstatus.sstat_rwnd+RWND_SLOP);
+ fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
+
+ /* Send a fillmsg */
+ memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
+ fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
+ ppid++;
+ stream++;
+ test_sctp_sendmsg(sk1, fillmsg, gstatus.sstat_rwnd+RWND_SLOP,
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 0, 0);
+
+ /* Now send a message that will timeout. */
+ test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 2000, 0);
+
+ tst_resm(TPASS, "sctp_sendmsg with ttl");
+
+ /* Next send a message that won't time out. */
+ test_sctp_sendmsg(sk1, nottlmsg, strlen(nottlmsg) + 1,
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 0, 0);
+
+ tst_resm(TPASS, "sctp_sendmsg with zero ttl");
+
+ /* And finally a fragmented message that will time out. */
+ memset(ttlfrag, 48, sizeof(ttlfrag)); /* 48 is the ascii of '0' */
+ ttlfrag[sizeof(ttlfrag)-1] = '\0';
+ test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
+ (struct sockaddr *)&loop2, sizeof(loop2),
+ ppid, 0, stream, 2000, 0);
+
+ tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
+
+ /* Sleep waiting for the message to time out. */
+ tst_resm(TINFO, "** SLEEPING for 3 seconds **");
+ sleep(3);
+
+ /* Get the fillmsg. */
+ do {
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ } while (!(msg_flags & MSG_EOR));
+
+ /* Get the message that did NOT time out. */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
+ strlen(nottlmsg) + 1, MSG_EOR, stream, ppid);
+ if (0 != strncmp(big_buffer, nottlmsg, strlen(nottlmsg)))
+ tst_brkm(TBROK, tst_exit, "sctp_recvmsg: Wrong Message !!!");
+
+ tst_resm(TPASS, "sctp_recvmsg msg with zero ttl");
+
+ /* Get the SEND_FAILED notification for the message that DID
+ * time out.
+ */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk1, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_send_failed) +
+ strlen(ttlmsg) + 1,
+ SCTP_SEND_FAILED, 0);
+ ssf = (struct sctp_send_failed *)big_buffer;
+ if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
+ tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
+
+ tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for message with ttl");
+
+ offset = 0;
+
+ /* Get the SEND_FAILED notifications for the fragmented message that
+ * timed out.
+ */
+ do {
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk1, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_send_failed) +
+ SMALL_MAXSEG,
+ SCTP_SEND_FAILED, 0);
+ ssf = (struct sctp_send_failed *)big_buffer;
+ if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
+ SMALL_MAXSEG))
+ tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
+ offset += SMALL_MAXSEG;
+ } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST FRAG */
+
+ tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for fragmented message with "
+ "ttl");
+
+ snd_sinfo.sinfo_ppid = rand();
+ snd_sinfo.sinfo_flags = 0;
+ snd_sinfo.sinfo_stream = 2;
+ snd_sinfo.sinfo_timetolive = 0;
+ snd_sinfo.sinfo_assoc_id = associd1;
+ test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
+ MSG_NOSIGNAL);
+
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
+ strlen(message) + 1, MSG_EOR, snd_sinfo.sinfo_stream,
+ snd_sinfo.sinfo_ppid);
+
+ tst_resm(TPASS, "sctp_send");
+
+ /* Shut down the link. */
+ close(sk1);
+
+ /* Get the shutdown complete notification. */
+ buflen = REALLY_BIG;
+ msgname_len = sizeof(msgname);
+ msg_flags = 0;
+ error = test_sctp_recvmsg(sk2, big_buffer, buflen,
+ (struct sockaddr *)&msgname, &msgname_len,
+ &sinfo, &msg_flags);
+ test_check_buf_notification(big_buffer, error, msg_flags,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ close(sk2);
+
+ /* Indicate successful completion. */
+ return 0;
+}