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