blob: ceccd5a3bd52f2deb03e8326cb915b6f14942190 [file] [log] [blame]
Austin Schuh8d0a2852019-12-28 22:54:28 -08001/* SCTP kernel Implementation
2 * (C) Copyright IBM Corp. 2003
3 * Copyright (c) 2003 Intel Corp.
4 *
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)
9 * any later version.
10 *
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.
16 *
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.
21 *
22 * Please send any bug reports or fixes you make to the
23 * email address(es):
24 * lksctp developers <lksctp-developers@lists.sourceforge.net>
25 *
26 * Or submit a bug report through the following website:
27 * http://www.sf.net/projects/lksctp
28 *
29 * Any bugs reported to us we will try to fix... any fixes shared will
30 * be incorporated into the next SCTP release.
31 *
32 * Written or modified by:
33 * To compile the v6 version, set the symbol TEST_V6 to 1.
34 *
35 * Written or modified by:
36 * Ardelle Fan <ardelle.fan@intel.com>
37 * Sridhar Samudrala <sri@us.ibm.com>
38 */
39
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
42 * these new APIs.
43 */
44
45#include <stdio.h>
46#include <unistd.h>
47#include <stdlib.h>
48#include <string.h>
49#include <sys/types.h>
50#include <sys/socket.h>
51#include <sys/uio.h>
52#include <netinet/in.h>
53#include <errno.h>
54#include <netinet/sctp.h>
55#include <sctputil.h>
56
57char *TCID = __FILE__;
58int TST_TOTAL = 10;
59int TST_CNT = 0;
60
61/* RCVBUF value, and indirectly RWND*2 */
62#define SMALL_RCVBUF 3000
63#define SMALL_MAXSEG 500
64/* This is extra data length to ensure rwnd closes */
65#define RWND_SLOP 100
66static char *fillmsg = NULL;
67static char *ttlmsg = "This should time out!\n";
68static char *nottlmsg = "This should NOT time out!\n";
69static char ttlfrag[SMALL_MAXSEG*3] = {0};
70static char *message = "Hello world\n";
71
72int main(int argc, char *argv[])
73{
74 int sk1, sk2;
75 sockaddr_storage_t loop1;
76 sockaddr_storage_t loop2;
77 sockaddr_storage_t msgname;
78 int error;
79 int pf_class;
80 uint32_t ppid;
81 uint32_t stream;
82 struct sctp_event_subscribe subscribe;
83 char *big_buffer;
84 int offset, msg_flags;
85 socklen_t msgname_len;
86 size_t buflen;
87 struct sctp_send_failed *ssf;
88 struct sctp_sndrcvinfo sinfo;
89 struct sctp_sndrcvinfo snd_sinfo;
90 sctp_assoc_t associd1;
91 socklen_t len, oldlen;
92 struct sctp_status gstatus;
93
94 /* Rather than fflush() throughout the code, set stdout to
95 * be unbuffered.
96 */
97 setvbuf(stdout, NULL, _IONBF, 0);
98
99 /* Set some basic values which depend on the address family. */
100#if TEST_V6
101 pf_class = PF_INET6;
102
103 loop1.v6.sin6_family = AF_INET6;
104 loop1.v6.sin6_addr = in6addr_loopback;
105 loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
106
107 loop2.v6.sin6_family = AF_INET6;
108 loop2.v6.sin6_addr = in6addr_loopback;
109 loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
110#else
111 pf_class = PF_INET;
112
113 loop1.v4.sin_family = AF_INET;
114 loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
115 loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
116
117 loop2.v4.sin_family = AF_INET;
118 loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
119 loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
120#endif /* TEST_V6 */
121
122 /* Create the two endpoints which will talk to each other. */
123 sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
124 sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
125
126 /* Set the MAXSEG to something smallish. */
127 {
128 int val = SMALL_MAXSEG;
129 test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
130 }
131
132 memset(&subscribe, 0, sizeof(subscribe));
133 subscribe.sctp_data_io_event = 1;
134 subscribe.sctp_association_event = 1;
135 subscribe.sctp_send_failure_event = 1;
136 test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
137 test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
138
139 /* Bind these sockets to the test ports. */
140 test_bind(sk1, &loop1.sa, sizeof(loop1));
141 test_bind(sk2, &loop2.sa, sizeof(loop2));
142
143 /*
144 * Set the RWND small so we can fill it up easily.
145 */
146 len = sizeof(int);
147 error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &oldlen, &len);
148
149 if (error)
150 tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
151 strerror(errno));
152
153 len = SMALL_RCVBUF; /* Really becomes 2xlen when set. */
154
155 error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
156 if (error)
157 tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
158 strerror(errno));
159
160 /* Mark sk2 as being able to accept new associations. */
161 test_listen(sk2, 1);
162
163 /* Send the first message. This will create the association. */
164 ppid = rand();
165 stream = 1;
166 test_sctp_sendmsg(sk1, message, strlen(message) + 1,
167 (struct sockaddr *)&loop2, sizeof(loop2),
168 ppid, 0, stream, 0, 0);
169
170 tst_resm(TPASS, "sctp_sendmsg");
171
172 /* Get the communication up message on sk2. */
173 buflen = REALLY_BIG;
174 big_buffer = test_malloc(buflen);
175 msgname_len = sizeof(msgname);
176 msg_flags = 0;
177 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
178 (struct sockaddr *)&msgname, &msgname_len,
179 &sinfo, &msg_flags);
180#if 0
181 associd2 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id;
182#endif
183 test_check_buf_notification(big_buffer, error, msg_flags,
184 sizeof(struct sctp_assoc_change),
185 SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
186
187
188 /* Get the communication up message on sk1. */
189 buflen = REALLY_BIG;
190 msgname_len = sizeof(msgname);
191 msg_flags = 0;
192 error = test_sctp_recvmsg(sk1, big_buffer, buflen,
193 (struct sockaddr *)&msgname, &msgname_len,
194 &sinfo, &msg_flags);
195 associd1 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id;
196 test_check_buf_notification(big_buffer, error, msg_flags,
197 sizeof(struct sctp_assoc_change),
198 SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
199
200 tst_resm(TPASS, "sctp_recvmsg SCTP_COMM_UP notification");
201
202 /* Get the first message which was sent. */
203 buflen = REALLY_BIG;
204 msgname_len = sizeof(msgname);
205 msg_flags = 0;
206 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
207 (struct sockaddr *)&msgname, &msgname_len,
208 &sinfo, &msg_flags);
209 test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
210 strlen(message) + 1, MSG_EOR, stream, ppid);
211
212 tst_resm(TPASS, "sctp_recvmsg data");
213
214 /* Figure out how big to make our fillmsg */
215 len = sizeof(struct sctp_status);
216 memset(&gstatus,0,sizeof(struct sctp_status));
217 gstatus.sstat_assoc_id = associd1;
218 error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
219
220 if (error)
221 tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
222 strerror(errno));
223 tst_resm(TINFO, "creating a fillmsg of size %d",
224 gstatus.sstat_rwnd+RWND_SLOP);
225 fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
226
227 /* Send a fillmsg */
228 memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
229 fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
230 ppid++;
231 stream++;
232 test_sctp_sendmsg(sk1, fillmsg, gstatus.sstat_rwnd+RWND_SLOP,
233 (struct sockaddr *)&loop2, sizeof(loop2),
234 ppid, 0, stream, 0, 0);
235
236 /* Now send a message that will timeout. */
237 test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
238 (struct sockaddr *)&loop2, sizeof(loop2),
239 ppid, 0, stream, 2000, 0);
240
241 tst_resm(TPASS, "sctp_sendmsg with ttl");
242
243 /* Next send a message that won't time out. */
244 test_sctp_sendmsg(sk1, nottlmsg, strlen(nottlmsg) + 1,
245 (struct sockaddr *)&loop2, sizeof(loop2),
246 ppid, 0, stream, 0, 0);
247
248 tst_resm(TPASS, "sctp_sendmsg with zero ttl");
249
250 /* And finally a fragmented message that will time out. */
251 memset(ttlfrag, 48, sizeof(ttlfrag)); /* 48 is the ascii of '0' */
252 ttlfrag[sizeof(ttlfrag)-1] = '\0';
253 test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
254 (struct sockaddr *)&loop2, sizeof(loop2),
255 ppid, 0, stream, 2000, 0);
256
257 tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
258
259 /* Sleep waiting for the message to time out. */
260 tst_resm(TINFO, "** SLEEPING for 3 seconds **");
261 sleep(3);
262
263 /* Get the fillmsg. */
264 do {
265 buflen = REALLY_BIG;
266 msgname_len = sizeof(msgname);
267 msg_flags = 0;
268 test_sctp_recvmsg(sk2, big_buffer, buflen,
269 (struct sockaddr *)&msgname, &msgname_len,
270 &sinfo, &msg_flags);
271 } while (!(msg_flags & MSG_EOR));
272
273 /* Get the message that did NOT time out. */
274 buflen = REALLY_BIG;
275 msgname_len = sizeof(msgname);
276 msg_flags = 0;
277 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
278 (struct sockaddr *)&msgname, &msgname_len,
279 &sinfo, &msg_flags);
280 test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
281 strlen(nottlmsg) + 1, MSG_EOR, stream, ppid);
282 if (0 != strncmp(big_buffer, nottlmsg, strlen(nottlmsg)))
283 tst_brkm(TBROK, tst_exit, "sctp_recvmsg: Wrong Message !!!");
284
285 tst_resm(TPASS, "sctp_recvmsg msg with zero ttl");
286
287 /* Get the SEND_FAILED notification for the message that DID
288 * time out.
289 */
290 buflen = REALLY_BIG;
291 msgname_len = sizeof(msgname);
292 msg_flags = 0;
293 error = test_sctp_recvmsg(sk1, big_buffer, buflen,
294 (struct sockaddr *)&msgname, &msgname_len,
295 &sinfo, &msg_flags);
296 test_check_buf_notification(big_buffer, error, msg_flags,
297 sizeof(struct sctp_send_failed) +
298 strlen(ttlmsg) + 1,
299 SCTP_SEND_FAILED, 0);
300 ssf = (struct sctp_send_failed *)big_buffer;
301 if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
302 tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
303
304 tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for message with ttl");
305
306 offset = 0;
307
308 /* Get the SEND_FAILED notifications for the fragmented message that
309 * timed out.
310 */
311 do {
312 buflen = REALLY_BIG;
313 msgname_len = sizeof(msgname);
314 msg_flags = 0;
315 error = test_sctp_recvmsg(sk1, big_buffer, buflen,
316 (struct sockaddr *)&msgname, &msgname_len,
317 &sinfo, &msg_flags);
318 test_check_buf_notification(big_buffer, error, msg_flags,
319 sizeof(struct sctp_send_failed) +
320 SMALL_MAXSEG,
321 SCTP_SEND_FAILED, 0);
322 ssf = (struct sctp_send_failed *)big_buffer;
323 if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
324 SMALL_MAXSEG))
325 tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
326 offset += SMALL_MAXSEG;
327 } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST FRAG */
328
329 tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for fragmented message with "
330 "ttl");
331
332 snd_sinfo.sinfo_ppid = rand();
333 snd_sinfo.sinfo_flags = 0;
334 snd_sinfo.sinfo_stream = 2;
335 snd_sinfo.sinfo_timetolive = 0;
336 snd_sinfo.sinfo_assoc_id = associd1;
337 test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
338 MSG_NOSIGNAL);
339
340 buflen = REALLY_BIG;
341 msgname_len = sizeof(msgname);
342 msg_flags = 0;
343 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
344 (struct sockaddr *)&msgname, &msgname_len,
345 &sinfo, &msg_flags);
346 test_check_buf_data(big_buffer, error, msg_flags, &sinfo,
347 strlen(message) + 1, MSG_EOR, snd_sinfo.sinfo_stream,
348 snd_sinfo.sinfo_ppid);
349
350 tst_resm(TPASS, "sctp_send");
351
352 /* Shut down the link. */
353 close(sk1);
354
355 /* Get the shutdown complete notification. */
356 buflen = REALLY_BIG;
357 msgname_len = sizeof(msgname);
358 msg_flags = 0;
359 error = test_sctp_recvmsg(sk2, big_buffer, buflen,
360 (struct sockaddr *)&msgname, &msgname_len,
361 &sinfo, &msg_flags);
362 test_check_buf_notification(big_buffer, error, msg_flags,
363 sizeof(struct sctp_assoc_change),
364 SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
365
366 close(sk2);
367
368 /* Indicate successful completion. */
369 return 0;
370}