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