1 /* SCTP kernel Implementation
2 * (C) Copyright IBM Corp. 2003
3 * Copyright (c) 2003 Intel Corp.
5 * The SCTP implementation is free software;
6 * you can redistribute it and/or modify it under the terms of
7 * the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * The SCTP implementation is distributed in the hope that it
12 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
13 * ************************
14 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 * See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU CC; see the file COPYING. If not, write to
19 * the Free Software Foundation, 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
22 * Please send any bug reports or fixes you make to the
24 * lksctp developers <lksctp-developers@lists.sourceforge.net>
26 * Or submit a bug report through the following website:
27 * http://www.sf.net/projects/lksctp
29 * Any bugs reported to us we will try to fix... any fixes shared will
30 * be incorporated into the next SCTP release.
32 * Written or modified by:
33 * To compile the v6 version, set the symbol TEST_V6 to 1.
35 * Written or modified by:
36 * Ardelle Fan <ardelle.fan@intel.com>
37 * Sridhar Samudrala <sri@us.ibm.com>
40 /* This is a basic functional test for the SCTP new library APIs
41 * sctp_sendmsg() and sctp_recvmsg(). test_timetolive.c is rewritten using
49 #include <sys/types.h>
50 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <sys/errno.h>
55 #include <netinet/sctp.h>
58 char *TCID = __FILE__;
62 /* RCVBUF value, and indirectly RWND*2 */
63 #define SMALL_RCVBUF 3000
64 #define SMALL_MAXSEG 100
65 /* This is extra data length to ensure rwnd closes */
67 static char *fillmsg = NULL;
68 static char *ttlmsg = "This should time out!\n";
69 static char *nottlmsg = "This should NOT time out!\n";
70 static char ttlfrag[SMALL_MAXSEG*3] = {0};
71 static char *message = "Hello world\n";
73 int main(int argc, char *argv[])
76 sockaddr_storage_t loop1;
77 sockaddr_storage_t loop2;
78 sockaddr_storage_t msgname;
80 int pf_class, af_family;
83 struct sctp_event_subscribe subscribe;
85 int offset, msg_flags;
86 socklen_t msgname_len;
88 struct sctp_send_failed *ssf;
89 struct sctp_sndrcvinfo sinfo;
90 struct sctp_sndrcvinfo snd_sinfo;
91 sctp_assoc_t associd1, associd2;
93 struct sctp_status gstatus;
95 /* Rather than fflush() throughout the code, set stdout to
98 setvbuf(stdout, NULL, _IONBF, 0);
100 /* Set some basic values which depend on the address family. */
103 af_family = AF_INET6;
105 loop1.v6.sin6_family = AF_INET6;
106 loop1.v6.sin6_addr = in6addr_loopback;
107 loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
109 loop2.v6.sin6_family = AF_INET6;
110 loop2.v6.sin6_addr = in6addr_loopback;
111 loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
116 loop1.v4.sin_family = AF_INET;
117 loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
118 loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
120 loop2.v4.sin_family = AF_INET;
121 loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
122 loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
125 /* Create the two endpoints which will talk to each other. */
126 sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
127 sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
129 /* Set the MAXSEG to something smallish. */
131 int val = SMALL_MAXSEG;
132 test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
135 memset(&subscribe, 0, sizeof(subscribe));
136 subscribe.sctp_data_io_event = 1;
137 subscribe.sctp_association_event = 1;
138 subscribe.sctp_send_failure_event = 1;
139 test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
140 test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
142 /* Bind these sockets to the test ports. */
143 test_bind(sk1, &loop1.sa, sizeof(loop1));
144 test_bind(sk2, &loop2.sa, sizeof(loop2));
147 * Set the RWND small so we can fill it up easily.
148 * then reset RCVBUF to avoid frame droppage
151 error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &oldlen, &len);
154 tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
157 len = SMALL_RCVBUF; /* Really becomes 2xlen when set. */
159 error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
161 tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
164 /* Mark sk2 as being able to accept new associations. */
167 /* Send the first message. This will create the association. */
170 test_sctp_sendmsg(sk1, message, strlen(message) + 1,
171 (struct sockaddr *)&loop2, sizeof(loop2),
172 ppid, 0, stream, 0, 0);
174 tst_resm(TPASS, "sctp_sendmsg");
176 /* Get the communication up message on sk2. */
178 big_buffer = test_malloc(buflen);
179 msgname_len = sizeof(msgname);
180 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
181 (struct sockaddr *)&msgname, &msgname_len,
183 associd2 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id;
184 test_check_buf_notification(big_buffer, error, msg_flags,
185 sizeof(struct sctp_assoc_change),
186 SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
189 /* restore the rcvbuffer size for the receiving socket */
190 error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &oldlen,
194 tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
197 /* Get the communication up message on sk1. */
199 msgname_len = sizeof(msgname);
200 error = test_sctp_recvmsg(sk1, big_buffer, buflen,
201 (struct sockaddr *)&msgname, &msgname_len,
203 associd1 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id;
204 test_check_buf_notification(big_buffer, error, msg_flags,
205 sizeof(struct sctp_assoc_change),
206 SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
208 tst_resm(TPASS, "sctp_recvmsg SCTP_COMM_UP notification");
210 /* Get the first message which was sent. */
212 msgname_len = sizeof(msgname);
213 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
214 (struct sockaddr *)&msgname, &msgname_len,
216 test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
217 strlen(message) + 1, MSG_EOR, stream, ppid);
219 tst_resm(TPASS, "sctp_recvmsg data");
221 /* Figure out how big to make our fillmsg */
222 len = sizeof(struct sctp_status);
223 memset(&gstatus,0,sizeof(struct sctp_status));
224 gstatus.sstat_assoc_id = associd1;
225 error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
228 tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
230 tst_resm(TINFO, "creating a fillmsg of size %d",
231 gstatus.sstat_rwnd+RWND_SLOP);
232 fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
235 memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
236 fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
239 test_sctp_sendmsg(sk1, fillmsg, gstatus.sstat_rwnd+RWND_SLOP,
240 (struct sockaddr *)&loop2, sizeof(loop2),
241 ppid, 0, stream, 0, 0);
243 /* Now send a message that will timeout. */
244 test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
245 (struct sockaddr *)&loop2, sizeof(loop2),
246 ppid, 0, stream, 2000, 0);
248 tst_resm(TPASS, "sctp_sendmsg with ttl");
250 /* Next send a message that won't time out. */
251 test_sctp_sendmsg(sk1, nottlmsg, strlen(nottlmsg) + 1,
252 (struct sockaddr *)&loop2, sizeof(loop2),
253 ppid, 0, stream, 0, 0);
255 tst_resm(TPASS, "sctp_sendmsg with zero ttl");
257 /* And finally a fragmented message that will time out. */
258 memset(ttlfrag, '0', sizeof(ttlfrag));
259 ttlfrag[sizeof(ttlfrag)-1] = '\0';
260 test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
261 (struct sockaddr *)&loop2, sizeof(loop2),
262 ppid, 0, stream, 2000, 0);
264 tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
266 /* Sleep waiting for the message to time out. */
267 tst_resm(TINFO, "** SLEEPING for 3 seconds **");
270 /* Get the fillmsg. */
273 msgname_len = sizeof(msgname);
274 test_sctp_recvmsg(sk2, big_buffer, buflen,
275 (struct sockaddr *)&msgname, &msgname_len,
277 } while (!(msg_flags & MSG_EOR));
279 /* Get the message that did NOT time out. */
281 msgname_len = sizeof(msgname);
282 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
283 (struct sockaddr *)&msgname, &msgname_len,
285 test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
286 strlen(nottlmsg) + 1, MSG_EOR, stream, ppid);
287 if (0 != strncmp(big_buffer, nottlmsg, strlen(nottlmsg)))
288 tst_brkm(TBROK, tst_exit, "sctp_recvmsg: Wrong Message !!!");
290 tst_resm(TPASS, "sctp_recvmsg msg with zero ttl");
292 /* Get the SEND_FAILED notification for the message that DID
296 msgname_len = sizeof(msgname);
297 error = test_sctp_recvmsg(sk1, big_buffer, buflen,
298 (struct sockaddr *)&msgname, &msgname_len,
300 test_check_buf_notification(big_buffer, error, msg_flags,
301 sizeof(struct sctp_send_failed) +
303 SCTP_SEND_FAILED, 0);
304 ssf = (struct sctp_send_failed *)big_buffer;
305 if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
306 tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
308 tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for message with ttl");
312 /* Get the SEND_FAILED notifications for the fragmented message that
317 msgname_len = sizeof(msgname);
318 error = test_sctp_recvmsg(sk1, big_buffer, buflen,
319 (struct sockaddr *)&msgname, &msgname_len,
321 test_check_buf_notification(big_buffer, error, msg_flags,
322 sizeof(struct sctp_send_failed) +
324 SCTP_SEND_FAILED, 0);
325 ssf = (struct sctp_send_failed *)big_buffer;
326 if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
328 tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
329 offset += SMALL_MAXSEG;
330 } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST FRAG */
332 tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for fragmented message with "
335 snd_sinfo.sinfo_ppid = rand();
336 snd_sinfo.sinfo_flags = 0;
337 snd_sinfo.sinfo_stream = 2;
338 snd_sinfo.sinfo_timetolive = 0;
339 snd_sinfo.sinfo_assoc_id = associd1;
340 test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
344 msgname_len = sizeof(msgname);
345 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
346 (struct sockaddr *)&msgname, &msgname_len,
348 test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
349 strlen(message) + 1, MSG_EOR, snd_sinfo.sinfo_stream,
350 snd_sinfo.sinfo_ppid);
352 tst_resm(TPASS, "sctp_send");
354 /* Shut down the link. */
357 /* Get the shutdown complete notification. */
359 msgname_len = sizeof(msgname);
360 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
361 (struct sockaddr *)&msgname, &msgname_len,
363 test_check_buf_notification(big_buffer, error, msg_flags,
364 sizeof(struct sctp_assoc_change),
365 SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
369 /* Indicate successful completion. */