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