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 59char *TCID = __FILE__; 60int TST_TOTAL = 10; 61int 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 68static char *fillmsg = NULL; 69static char *ttlmsg = "This should time out!\n"; 70static char *nottlmsg = "This should NOT time out!\n"; 71static char ttlfrag[SMALL_MAXSEG*3] = {0}; 72static char *message = "Hello world\n"; 73 74int 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