Changes in freeDiameter/sctp.c [20:277ec00d793e:29:5ba91682f0bc] in freeDiameter
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
freeDiameter/sctp.c
r20 r29 35 35 36 36 #include "fD.h" 37 38 int fd_sctp_create_bind_server( int * socket, uint16_t port ) 37 #include "cnxctx.h" 38 39 #include <netinet/sctp.h> 40 #include <sys/uio.h> 41 42 /* Size of buffer to receive ancilliary data. May need to be enlarged if more sockopt are set... */ 43 #ifndef CMSG_BUF_LEN 44 #define CMSG_BUF_LEN 1024 45 #endif /* CMSG_BUF_LEN */ 46 47 /* Level of SCTP-specific traces */ 48 #ifdef DEBUG_SCTP 49 #define SCTP_LEVEL FULL 50 #else /* DEBUG_SCTP */ 51 #define SCTP_LEVEL ANNOYING 52 #endif /* DEBUG_SCTP */ 53 54 /* Pre-binding socket options -- # streams read in config */ 55 static int fd_setsockopt_prebind(int sk) 39 56 { 40 TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str"); 41 42 return ENOTSUP; 57 socklen_t sz; 58 59 TRACE_ENTRY( "%d", sk); 60 61 CHECK_PARAMS( sk > 0 ); 62 63 /* Subscribe to some notifications */ 64 { 65 struct sctp_event_subscribe event; 66 67 memset(&event, 0, sizeof(event)); 68 event.sctp_data_io_event = 1; /* to receive the stream ID in SCTP_SNDRCV ancilliary data on message reception */ 69 event.sctp_association_event = 0; /* new or closed associations (mostly for one-to-many style sockets) */ 70 event.sctp_address_event = 1; /* address changes */ 71 event.sctp_send_failure_event = 1; /* delivery failures */ 72 event.sctp_peer_error_event = 1; /* remote peer sends an error */ 73 event.sctp_shutdown_event = 1; /* peer has sent a SHUTDOWN */ 74 event.sctp_partial_delivery_event = 1; /* a partial delivery is aborted, probably indicating the connection is being shutdown */ 75 // event.sctp_adaptation_layer_event = 0; /* adaptation layer notifications */ 76 // event.sctp_authentication_event = 0; /* when new key is made active */ 77 78 /* Set the option to the socket */ 79 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) ); 80 81 if (TRACE_BOOL(SCTP_LEVEL)) { 82 sz = sizeof(event); 83 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, &sz) ); 84 if (sz != sizeof(event)) 85 { 86 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(event)); 87 return ENOTSUP; 88 } 89 90 fd_log_debug( "SCTP_EVENTS : sctp_data_io_event : %hhu\n", event.sctp_data_io_event); 91 fd_log_debug( " sctp_association_event : %hhu\n", event.sctp_association_event); 92 fd_log_debug( " sctp_address_event : %hhu\n", event.sctp_address_event); 93 fd_log_debug( " sctp_send_failure_event : %hhu\n", event.sctp_send_failure_event); 94 fd_log_debug( " sctp_peer_error_event : %hhu\n", event.sctp_peer_error_event); 95 fd_log_debug( " sctp_shutdown_event : %hhu\n", event.sctp_shutdown_event); 96 fd_log_debug( " sctp_partial_delivery_event : %hhu\n", event.sctp_partial_delivery_event); 97 fd_log_debug( " sctp_adaptation_layer_event : %hhu\n", event.sctp_adaptation_layer_event); 98 // fd_log_debug( " sctp_authentication_event : %hhu\n", event.sctp_authentication_event); 99 } 100 101 } 102 103 /* Set the INIT parameters, such as number of streams */ 104 { 105 struct sctp_initmsg init; 106 memset(&init, 0, sizeof(init)); 107 108 if (TRACE_BOOL(SCTP_LEVEL)) { 109 sz = sizeof(init); 110 111 /* Read socket defaults */ 112 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); 113 if (sz != sizeof(init)) 114 { 115 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init)); 116 return ENOTSUP; 117 } 118 fd_log_debug( "Def SCTP_INITMSG : sinit_num_ostreams : %hu\n", init.sinit_num_ostreams); 119 fd_log_debug( " sinit_max_instreams : %hu\n", init.sinit_max_instreams); 120 fd_log_debug( " sinit_max_attempts : %hu\n", init.sinit_max_attempts); 121 fd_log_debug( " sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo); 122 } 123 124 /* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters */ 125 init.sinit_num_ostreams = fd_g_config->cnf_sctp_str; /* desired number of outgoing streams */ 126 init.sinit_max_init_timeo = CNX_TIMEOUT * 1000; 127 128 /* Set the option to the socket */ 129 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init)) ); 130 131 if (TRACE_BOOL(SCTP_LEVEL)) { 132 /* Check new values */ 133 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); 134 fd_log_debug( "New SCTP_INITMSG : sinit_num_ostreams : %hu\n", init.sinit_num_ostreams); 135 fd_log_debug( " sinit_max_instreams : %hu\n", init.sinit_max_instreams); 136 fd_log_debug( " sinit_max_attempts : %hu\n", init.sinit_max_attempts); 137 fd_log_debug( " sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo); 138 } 139 } 140 141 /* Set the SCTP_DISABLE_FRAGMENTS option, required for TLS */ 142 #ifdef SCTP_DISABLE_FRAGMENTS 143 { 144 int nofrag; 145 146 if (TRACE_BOOL(SCTP_LEVEL)) { 147 sz = sizeof(nofrag); 148 /* Read socket defaults */ 149 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); 150 if (sz != sizeof(nofrag)) 151 { 152 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag)); 153 return ENOTSUP; 154 } 155 fd_log_debug( "Def SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false"); 156 } 157 158 nofrag = 0; /* We turn ON the fragmentation */ 159 160 /* Set the option to the socket */ 161 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, sizeof(nofrag)) ); 162 163 if (TRACE_BOOL(SCTP_LEVEL)) { 164 /* Check new values */ 165 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); 166 fd_log_debug( "New SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false"); 167 } 168 } 169 #else /* SCTP_DISABLE_FRAGMENTS */ 170 # error "TLS requires support of SCTP_DISABLE_FRAGMENTS" 171 #endif /* SCTP_DISABLE_FRAGMENTS */ 172 173 174 /* Set the RETRANSMIT parameters */ 175 #ifdef SCTP_RTOINFO 176 { 177 struct sctp_rtoinfo rtoinfo; 178 memset(&rtoinfo, 0, sizeof(rtoinfo)); 179 180 if (TRACE_BOOL(SCTP_LEVEL)) { 181 sz = sizeof(rtoinfo); 182 /* Read socket defaults */ 183 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); 184 if (sz != sizeof(rtoinfo)) 185 { 186 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo)); 187 return ENOTSUP; 188 } 189 fd_log_debug( "Def SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial); 190 fd_log_debug( " srto_max : %u\n", rtoinfo.srto_max); 191 fd_log_debug( " srto_min : %u\n", rtoinfo.srto_min); 192 } 193 194 rtoinfo.srto_max = fd_g_config->cnf_timer_tw * 500 - 1000; /* Maximum retransmit timer (in ms) (set to Tw / 2 - 1) */ 195 196 /* Set the option to the socket */ 197 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo)) ); 198 199 if (TRACE_BOOL(SCTP_LEVEL)) { 200 /* Check new values */ 201 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); 202 fd_log_debug( "New SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial); 203 fd_log_debug( " srto_max : %u\n", rtoinfo.srto_max); 204 fd_log_debug( " srto_min : %u\n", rtoinfo.srto_min); 205 } 206 } 207 #else /* SCTP_RTOINFO */ 208 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_RTOINFO"); 209 #endif /* SCTP_RTOINFO */ 210 211 /* Set the ASSOCIATION parameters */ 212 #ifdef SCTP_ASSOCINFO 213 { 214 struct sctp_assocparams assoc; 215 memset(&assoc, 0, sizeof(assoc)); 216 217 if (TRACE_BOOL(SCTP_LEVEL)) { 218 sz = sizeof(assoc); 219 /* Read socket defaults */ 220 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); 221 if (sz != sizeof(assoc)) 222 { 223 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc)); 224 return ENOTSUP; 225 } 226 fd_log_debug( "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu\n", assoc.sasoc_asocmaxrxt); 227 fd_log_debug( " sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations); 228 fd_log_debug( " sasoc_peer_rwnd : %u\n" , assoc.sasoc_peer_rwnd); 229 fd_log_debug( " sasoc_local_rwnd : %u\n" , assoc.sasoc_local_rwnd); 230 fd_log_debug( " sasoc_cookie_life : %u\n" , assoc.sasoc_cookie_life); 231 } 232 233 assoc.sasoc_asocmaxrxt = 5; /* Maximum retransmission attempts: we want fast detection of errors */ 234 235 /* Set the option to the socket */ 236 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) ); 237 238 if (TRACE_BOOL(SCTP_LEVEL)) { 239 /* Check new values */ 240 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); 241 fd_log_debug( "New SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu\n", assoc.sasoc_asocmaxrxt); 242 fd_log_debug( " sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations); 243 fd_log_debug( " sasoc_peer_rwnd : %u\n" , assoc.sasoc_peer_rwnd); 244 fd_log_debug( " sasoc_local_rwnd : %u\n" , assoc.sasoc_local_rwnd); 245 fd_log_debug( " sasoc_cookie_life : %u\n" , assoc.sasoc_cookie_life); 246 } 247 } 248 #else /* SCTP_ASSOCINFO */ 249 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_ASSOCINFO"); 250 #endif /* SCTP_ASSOCINFO */ 251 252 253 /* The SO_LINGER option will be re-set if we want to perform SCTP ABORT */ 254 #ifdef SO_LINGER 255 { 256 struct linger linger; 257 memset(&linger, 0, sizeof(linger)); 258 259 if (TRACE_BOOL(SCTP_LEVEL)) { 260 sz = sizeof(linger); 261 /* Read socket defaults */ 262 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); 263 if (sz != sizeof(linger)) 264 { 265 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger)); 266 return ENOTSUP; 267 } 268 fd_log_debug( "Def SO_LINGER : l_onoff : %d\n", linger.l_onoff); 269 fd_log_debug( " l_linger : %d\n", linger.l_linger); 270 } 271 272 linger.l_onoff = 0; /* Do not activate the linger */ 273 linger.l_linger = 0; /* Return immediately when closing (=> abort) */ 274 275 /* Set the option */ 276 CHECK_SYS( setsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) ); 277 278 if (TRACE_BOOL(SCTP_LEVEL)) { 279 /* Check new values */ 280 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); 281 fd_log_debug( "New SO_LINGER : l_onoff : %d\n", linger.l_onoff); 282 fd_log_debug( " l_linger : %d\n", linger.l_linger); 283 } 284 } 285 #else /* SO_LINGER */ 286 TRACE_DEBUG(SCTP_LEVEL, "Skipping SO_LINGER"); 287 #endif /* SO_LINGER */ 288 289 /* Set the NODELAY option (Nagle-like algorithm) */ 290 #ifdef SCTP_NODELAY 291 { 292 int nodelay; 293 294 if (TRACE_BOOL(SCTP_LEVEL)) { 295 sz = sizeof(nodelay); 296 /* Read socket defaults */ 297 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); 298 if (sz != sizeof(nodelay)) 299 { 300 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay)); 301 return ENOTSUP; 302 } 303 fd_log_debug( "Def SCTP_NODELAY value : %s\n", nodelay ? "true" : "false"); 304 } 305 306 nodelay = 0; /* We turn ON the Nagle algorithm (probably the default already) */ 307 308 /* Set the option to the socket */ 309 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay)) ); 310 311 if (TRACE_BOOL(SCTP_LEVEL)) { 312 /* Check new values */ 313 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); 314 fd_log_debug( "New SCTP_NODELAY value : %s\n", nodelay ? "true" : "false"); 315 } 316 } 317 #else /* SCTP_NODELAY */ 318 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_NODELAY"); 319 #endif /* SCTP_NODELAY */ 320 321 /* Set the interleaving option */ 322 #ifdef SCTP_FRAGMENT_INTERLEAVE 323 { 324 int interleave; 325 326 if (TRACE_BOOL(SCTP_LEVEL)) { 327 sz = sizeof(interleave); 328 /* Read socket defaults */ 329 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz) ); 330 if (sz != sizeof(interleave)) 331 { 332 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(interleave)); 333 return ENOTSUP; 334 } 335 fd_log_debug( "Def SCTP_FRAGMENT_INTERLEAVE value : %d\n", interleave); 336 } 337 338 #if 0 339 interleave = 2; /* Allow partial delivery on several streams at the same time, since we are stream-aware in our security modules */ 340 #else /* 0 */ 341 interleave = 1; /* hmmm actually, we are not yet capable of handling this, and we don t need it. */ 342 #endif /* 0 */ 343 344 /* Set the option to the socket */ 345 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, sizeof(interleave)) ); 346 347 if (TRACE_BOOL(SCTP_LEVEL)) { 348 /* Check new values */ 349 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz) ); 350 fd_log_debug( "New SCTP_FRAGMENT_INTERLEAVE value : %d\n", interleave); 351 } 352 } 353 #else /* SCTP_FRAGMENT_INTERLEAVE */ 354 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_FRAGMENT_INTERLEAVE"); 355 #endif /* SCTP_FRAGMENT_INTERLEAVE */ 356 357 /* Set the v4 mapped addresses option */ 358 #ifdef SCTP_I_WANT_MAPPED_V4_ADDR 359 { 360 int v4mapped; 361 362 if (TRACE_BOOL(SCTP_LEVEL)) { 363 sz = sizeof(v4mapped); 364 /* Read socket defaults */ 365 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); 366 if (sz != sizeof(v4mapped)) 367 { 368 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped)); 369 return ENOTSUP; 370 } 371 fd_log_debug( "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false"); 372 } 373 374 #ifndef SCTP_USE_MAPPED_ADDRESSES 375 v4mapped = 0; /* We don't want v4 mapped addresses */ 376 #else /* SCTP_USE_MAPPED_ADDRESSES */ 377 v4mapped = 1; /* but we may have to, otherwise the bind fails in some environments */ 378 #endif /* SCTP_USE_MAPPED_ADDRESSES */ 379 380 /* Set the option to the socket */ 381 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped)) ); 382 383 if (TRACE_BOOL(SCTP_LEVEL)) { 384 /* Check new values */ 385 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); 386 fd_log_debug( "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false"); 387 } 388 } 389 #else /* SCTP_I_WANT_MAPPED_V4_ADDR */ 390 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR"); 391 #endif /* SCTP_I_WANT_MAPPED_V4_ADDR */ 392 393 394 /* Other settable options (draft-ietf-tsvwg-sctpsocket-17): 395 SO_RCVBUF size of receiver window 396 SO_SNDBUF size of pending data to send 397 SCTP_AUTOCLOSE for one-to-many only 398 SCTP_SET_PEER_PRIMARY_ADDR ask remote peer to use this local address as primary 399 SCTP_PRIMARY_ADDR use this address as primary locally 400 SCTP_ADAPTATION_LAYER set adaptation layer indication 401 SCTP_PEER_ADDR_PARAMS control heartbeat per peer address 402 SCTP_DEFAULT_SEND_PARAM parameters for the sendto() call 403 SCTP_MAXSEG max size of fragmented segments -- bound to PMTU 404 SCTP_AUTH_CHUNK request authentication of some type of chunk 405 SCTP_HMAC_IDENT authentication algorithms 406 SCTP_AUTH_KEY set a shared key 407 SCTP_AUTH_ACTIVE_KEY set the active key 408 SCTP_AUTH_DELETE_KEY remove a key 409 SCTP_AUTH_DEACTIVATE_KEY will not use that key anymore 410 SCTP_DELAYED_SACK control delayed acks 411 SCTP_PARTIAL_DELIVERY_POINT control partial delivery size 412 SCTP_USE_EXT_RCVINFO use extended receive info structure (information about the next message if available) 413 SCTP_MAX_BURST number of packets that can be burst emitted 414 SCTP_CONTEXT save a context information along with the association. 415 SCTP_EXPLICIT_EOR enable sending one message across several send calls 416 SCTP_REUSE_PORT share one listening port with several sockets 417 418 read-only options: 419 SCTP_STATUS retrieve info such as number of streams, pending packets, state, ... 420 SCTP_GET_PEER_ADDR_INFO get information about a specific peer address of the association. 421 SCTP_PEER_AUTH_CHUNKS list of chunks the remote peer wants authenticated 422 SCTP_LOCAL_AUTH_CHUNKS list of chunks the local peer wants authenticated 423 SCTP_GET_ASSOC_NUMBER number of associations in a one-to-many socket 424 SCTP_GET_ASSOC_ID_LIST list of these associations 425 */ 426 427 /* In case of no_ip4, force the v6only option -- is it a valid option for SCTP ? */ 428 #ifdef IPV6_V6ONLY 429 if (fd_g_config->cnf_flags.no_ip4) { 430 int opt = 1; 431 CHECK_SYS(setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))); 432 } 433 #endif /* IPV6_V6ONLY */ 434 435 return 0; 43 436 } 44 437 45 int fd_sctp_get_str_info( int socket, int *in, int *out ) 438 439 /* Post-binding socket options */ 440 static int fd_setsockopt_postbind(int sk, int bound_to_default) 46 441 { 47 TODO("Retrieve streams info from the socket"); 48 49 return ENOTSUP; 442 TRACE_ENTRY( "%d %d", sk, bound_to_default); 443 444 CHECK_PARAMS( (sk > 0) ); 445 446 /* Set the ASCONF option */ 447 #ifdef SCTP_AUTO_ASCONF 448 { 449 int asconf; 450 451 if (TRACE_BOOL(SCTP_LEVEL)) { 452 socklen_t sz; 453 454 sz = sizeof(asconf); 455 /* Read socket defaults */ 456 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz) ); 457 if (sz != sizeof(asconf)) 458 { 459 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(asconf)); 460 return ENOTSUP; 461 } 462 fd_log_debug( "Def SCTP_AUTO_ASCONF value : %s\n", asconf ? "true" : "false"); 463 } 464 465 asconf = bound_to_default ? 1 : 0; /* allow automatic use of added or removed addresses in the association (for bound-all sockets) */ 466 467 /* Set the option to the socket */ 468 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, sizeof(asconf)) ); 469 470 if (TRACE_BOOL(SCTP_LEVEL)) { 471 socklen_t sz = sizeof(asconf); 472 /* Check new values */ 473 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz) ); 474 fd_log_debug( "New SCTP_AUTO_ASCONF value : %s\n", asconf ? "true" : "false"); 475 } 476 } 477 #else /* SCTP_AUTO_ASCONF */ 478 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_AUTO_ASCONF"); 479 #endif /* SCTP_AUTO_ASCONF */ 480 481 return 0; 50 482 } 483 484 /* Create a socket server and bind it according to daemon s configuration */ 485 int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port ) 486 { 487 int family; 488 int bind_default; 489 490 TRACE_ENTRY("%p %p %hu", sock, list, port); 491 CHECK_PARAMS(sock); 492 493 if (fd_g_config->cnf_flags.no_ip6) { 494 family = AF_INET; 495 } else { 496 family = AF_INET6; /* can create socket for both IP and IPv6 */ 497 } 498 499 /* Create the socket */ 500 CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) ); 501 502 /* Set pre-binding socket options, including number of streams etc... */ 503 CHECK_FCT( fd_setsockopt_prebind(*sock) ); 504 505 bind_default = (! list) || (FD_IS_LIST_EMPTY(list)) ; 506 redo: 507 if ( bind_default ) { 508 /* Implicit endpoints : bind to default addresses */ 509 union { 510 sSS ss; 511 sSA sa; 512 sSA4 sin; 513 sSA6 sin6; 514 } s; 515 516 /* 0.0.0.0 and [::] are all zeros */ 517 memset(&s, 0, sizeof(s)); 518 519 s.sa.sa_family = family; 520 521 if (family == AF_INET) 522 s.sin.sin_port = htons(port); 523 else 524 s.sin6.sin6_port = htons(port); 525 526 CHECK_SYS( bind(*sock, &s.sa, sizeof(s)) ); 527 528 } else { 529 /* Explicit endpoints to bind to from config */ 530 531 union { 532 sSA * sa; 533 sSA4 *sin; 534 sSA6 *sin6; 535 uint8_t *buf; 536 } ptr; 537 union { 538 sSA * sa; 539 uint8_t * buf; 540 } sar; 541 int count = 0; /* number of sock addr in sar array */ 542 size_t offset = 0; 543 struct fd_list * li; 544 545 sar.buf = NULL; 546 547 /* Create a flat array from the list of configured addresses */ 548 for (li = list->next; li != list; li = li->next) { 549 struct fd_endpoint * ep = (struct fd_endpoint *)li; 550 size_t sz = 0; 551 552 if (! (ep->flags & EP_FL_CONF)) 553 continue; 554 555 count++; 556 557 /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */ 558 #ifndef SCTP_USE_MAPPED_ADDRESSES 559 if (ep->sa.sa_family == AF_INET6) 560 #else /* SCTP_USE_MAPPED_ADDRESSES */ 561 if (family == AF_INET6) 562 #endif /* SCTP_USE_MAPPED_ADDRESSES */ 563 sz = sizeof(sSA6); 564 else 565 sz = sizeof(sSA4); 566 567 /* augment sar to contain the additional info */ 568 CHECK_MALLOC( sar.buf = realloc(sar.buf, offset + sz) ); 569 570 ptr.buf = sar.buf + offset; /* place of the new SA */ 571 offset += sz; /* update to end of sar */ 572 573 if (sz == sizeof(sSA4)) { 574 memcpy(ptr.buf, &ep->sin, sz); 575 ptr.sin->sin_port = htons(port); 576 } else { 577 if (ep->sa.sa_family == AF_INET) { /* We must map the address */ 578 memset(ptr.buf, 0, sz); 579 ptr.sin6->sin6_family = AF_INET6; 580 IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr ); 581 } else { 582 memcpy(ptr.sin6, &ep->sin6, sz); 583 } 584 ptr.sin6->sin6_port = htons(port); 585 } 586 } 587 588 if (!count) { 589 /* None of the addresses in the list came from configuration, we bind to default */ 590 bind_default = 1; 591 goto redo; 592 } 593 594 if (TRACE_BOOL(SCTP_LEVEL)) { 595 int i; 596 ptr.buf = sar.buf; 597 fd_log_debug("Calling sctp_bindx with the following address array:\n"); 598 for (i = 0; i < count; i++) { 599 TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" ); 600 ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ; 601 } 602 } 603 604 /* Bind to this array */ 605 CHECK_SYS( sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR) ); 606 607 /* We don't need sar anymore */ 608 free(sar.buf); 609 } 610 611 /* Now, the server is bound, set remaining sockopt */ 612 CHECK_FCT( fd_setsockopt_postbind(*sock, bind_default) ); 613 614 /* Debug: show all local listening addresses */ 615 if (TRACE_BOOL(SCTP_LEVEL)) { 616 sSA *sar; 617 union { 618 sSA *sa; 619 uint8_t *buf; 620 } ptr; 621 int sz; 622 623 CHECK_SYS( sz = sctp_getladdrs(*sock, 0, &sar) ); 624 625 fd_log_debug("SCTP server bound on :\n"); 626 for (ptr.sa = sar; sz-- > 0; ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6)) { 627 TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" ); 628 } 629 sctp_freeladdrs(sar); 630 } 631 632 return 0; 633 } 634 635 /* Allow clients connections on server sockets */ 636 int fd_sctp_listen( int sock ) 637 { 638 TRACE_ENTRY("%d", sock); 639 CHECK_SYS( listen(sock, 5) ); 640 return 0; 641 } 642 643 /* Create a client socket and connect to remote server */ 644 int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list ) 645 { 646 int family; 647 int count = 0; 648 size_t offset = 0, sz; 649 union { 650 uint8_t *buf; 651 sSA *sa; 652 } sar; 653 union { 654 uint8_t *buf; 655 sSA *sa; 656 sSA4 *sin; 657 sSA6 *sin6; 658 } ptr; 659 struct fd_list * li; 660 int ret; 661 662 sar.buf = NULL; 663 664 TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list); 665 CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) ); 666 667 if (no_ip6) { 668 family = AF_INET; 669 } else { 670 family = AF_INET6; 671 } 672 673 /* Create the socket */ 674 CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) ); 675 676 /* Cleanup if we are cancelled */ 677 pthread_cleanup_push(fd_cleanup_socket, sock); 678 679 /* Set the socket options */ 680 CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail ); 681 682 /* Create the array of addresses for sctp_connectx */ 683 for (li = list->next; li != list; li = li->next) { 684 struct fd_endpoint * ep = (struct fd_endpoint *) li; 685 686 count++; 687 688 /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */ 689 #ifndef SCTP_USE_MAPPED_ADDRESSES 690 if (ep->sa.sa_family == AF_INET6) 691 #else /* SCTP_USE_MAPPED_ADDRESSES */ 692 if (family == AF_INET6) 693 #endif /* SCTP_USE_MAPPED_ADDRESSES */ 694 sz = sizeof(sSA6); 695 else 696 sz = sizeof(sSA4); 697 698 /* augment sar to contain the additional info */ 699 CHECK_MALLOC_DO( sar.buf = realloc(sar.buf, offset + sz), { ret = ENOMEM; goto fail; } ); 700 701 ptr.buf = sar.buf + offset; /* place of the new SA */ 702 offset += sz; /* update to end of sar */ 703 704 if (sz == sizeof(sSA4)) { 705 memcpy(ptr.buf, &ep->sin, sz); 706 ptr.sin->sin_port = htons(port); 707 } else { 708 if (ep->sa.sa_family == AF_INET) { /* We must map the address */ 709 memset(ptr.buf, 0, sz); 710 ptr.sin6->sin6_family = AF_INET6; 711 IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr ); 712 } else { 713 memcpy(ptr.sin6, &ep->sin6, sz); 714 } 715 ptr.sin6->sin6_port = htons(port); 716 } 717 } 718 719 /* Try connecting */ 720 TRACE_DEBUG(FULL, "Attempting SCTP connection (%d addresses attempted)...", count); 721 CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count), { ret = errno; goto fail; } ); 722 free(sar.buf); sar.buf = NULL; 723 724 /* Set the remaining sockopts */ 725 CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, 1), goto fail ); 726 727 /* Done! */ 728 pthread_cleanup_pop(0); 729 return 0; 730 731 fail: 732 if (*sock > 0) { 733 shutdown(*sock, SHUT_RDWR); 734 *sock = -1; 735 } 736 free(sar.buf); 737 return ret; 738 } 739 740 /* Retrieve streams information from a connected association -- optionaly provide the primary address */ 741 int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary ) 742 { 743 struct sctp_status status; 744 socklen_t sz = sizeof(status); 745 746 TRACE_ENTRY("%d %p %p %p", sock, in, out, primary); 747 CHECK_PARAMS( (sock > 0) && in && out ); 748 749 /* Read the association parameters */ 750 memset(&status, 0, sizeof(status)); 751 CHECK_SYS( getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz) ); 752 if (sz != sizeof(status)) 753 { 754 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %zd", sz, sizeof(status)); 755 return ENOTSUP; 756 } 757 if (TRACE_BOOL(SCTP_LEVEL)) { 758 fd_log_debug( "SCTP_STATUS : sstat_state : %i\n" , status.sstat_state); 759 fd_log_debug( " sstat_rwnd : %u\n" , status.sstat_rwnd); 760 fd_log_debug( " sstat_unackdata : %hu\n", status.sstat_unackdata); 761 fd_log_debug( " sstat_penddata : %hu\n", status.sstat_penddata); 762 fd_log_debug( " sstat_instrms : %hu\n", status.sstat_instrms); 763 fd_log_debug( " sstat_outstrms : %hu\n", status.sstat_outstrms); 764 fd_log_debug( " sstat_fragmentation_point : %u\n" , status.sstat_fragmentation_point); 765 fd_log_debug( " sstat_primary.spinfo_address : "); 766 sSA_DUMP_NODE_SERV(&status.sstat_primary.spinfo_address, NI_NUMERICHOST | NI_NUMERICSERV ); 767 fd_log_debug( "\n" ); 768 fd_log_debug( " sstat_primary.spinfo_state : %d\n" , status.sstat_primary.spinfo_state); 769 fd_log_debug( " sstat_primary.spinfo_cwnd : %u\n" , status.sstat_primary.spinfo_cwnd); 770 fd_log_debug( " sstat_primary.spinfo_srtt : %u\n" , status.sstat_primary.spinfo_srtt); 771 fd_log_debug( " sstat_primary.spinfo_rto : %u\n" , status.sstat_primary.spinfo_rto); 772 fd_log_debug( " sstat_primary.spinfo_mtu : %u\n" , status.sstat_primary.spinfo_mtu); 773 } 774 775 *in = status.sstat_instrms; 776 *out = status.sstat_outstrms; 777 778 if (primary) 779 memcpy(primary, &status.sstat_primary.spinfo_address, sizeof(sSS)); 780 781 return 0; 782 } 783 784 /* Get the list of local endpoints of the socket */ 785 int fd_sctp_get_local_ep(int sock, struct fd_list * list) 786 { 787 union { 788 sSA *sa; 789 uint8_t *buf; 790 } ptr; 791 792 sSA * data; 793 int count; 794 795 TRACE_ENTRY("%d %p", sock, list); 796 CHECK_PARAMS(list); 797 798 /* Read the list on the socket */ 799 CHECK_SYS( count = sctp_getladdrs(sock, 0, &data) ); 800 ptr.sa = data; 801 802 while (count) { 803 socklen_t sl; 804 switch (ptr.sa->sa_family) { 805 case AF_INET: sl = sizeof(sSA4); break; 806 case AF_INET6: sl = sizeof(sSA6); break; 807 default: 808 TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family); 809 } 810 811 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) ); 812 ptr.buf += sl; 813 count --; 814 } 815 816 /* Free the list */ 817 sctp_freeladdrs(data); 818 819 /* Now get the primary address, the add function will take care of merging with existing entry */ 820 { 821 822 struct sctp_status status; 823 socklen_t sz = sizeof(status); 824 int ret; 825 826 memset(&status, 0, sizeof(status)); 827 /* Attempt to use SCTP_STATUS message to retrieve the primary address */ 828 ret = getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz); 829 if (sz != sizeof(status)) 830 ret = -1; 831 sz = sizeof(sSS); 832 if (ret < 0) 833 { 834 /* Fallback to getsockname -- not recommended by draft-ietf-tsvwg-sctpsocket-19#section-7.4 */ 835 CHECK_SYS(getsockname(sock, (sSA *)&status.sstat_primary.spinfo_address, &sz)); 836 } 837 838 CHECK_FCT( fd_ep_add_merge( list, (sSA *)&status.sstat_primary.spinfo_address, sz, EP_FL_PRIMARY ) ); 839 } 840 841 return 0; 842 } 843 844 /* Get the list of remote endpoints of the socket */ 845 int fd_sctp_get_remote_ep(int sock, struct fd_list * list) 846 { 847 union { 848 sSA *sa; 849 uint8_t *buf; 850 } ptr; 851 852 sSA * data; 853 int count; 854 855 TRACE_ENTRY("%d %p", sock, list); 856 CHECK_PARAMS(list); 857 858 /* Read the list on the socket */ 859 CHECK_SYS( count = sctp_getpaddrs(sock, 0, &data) ); 860 ptr.sa = data; 861 862 while (count) { 863 socklen_t sl; 864 switch (ptr.sa->sa_family) { 865 case AF_INET: sl = sizeof(sSA4); break; 866 case AF_INET6: sl = sizeof(sSA6); break; 867 default: 868 TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getpaddrs: %d", ptr.sa->sa_family); 869 } 870 871 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) ); 872 ptr.buf += sl; 873 count --; 874 } 875 876 /* Free the list */ 877 sctp_freepaddrs(data); 878 879 /* Now get the primary address, the add function will take care of merging with existing entry */ 880 { 881 sSS ss; 882 socklen_t sl = sizeof(sSS); 883 884 CHECK_SYS(getpeername(sock, (sSA *)&ss, &sl)); 885 CHECK_FCT( fd_ep_add_merge( list, (sSA *)&ss, sl, EP_FL_PRIMARY ) ); 886 } 887 888 /* Done! */ 889 return 0; 890 } 891 892 /* Send a buffer over a specified stream */ 893 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len) 894 { 895 struct msghdr mhdr; 896 struct iovec iov; 897 struct { 898 struct cmsghdr hdr; 899 struct sctp_sndrcvinfo sndrcv; 900 } anci; 901 ssize_t ret; 902 903 TRACE_ENTRY("%d %hu %p %zd", sock, strid, buf, len); 904 905 memset(&mhdr, 0, sizeof(mhdr)); 906 memset(&iov, 0, sizeof(iov)); 907 memset(&anci, 0, sizeof(anci)); 908 909 /* IO Vector: message data */ 910 iov.iov_base = buf; 911 iov.iov_len = len; 912 913 /* Anciliary data: specify SCTP stream */ 914 anci.hdr.cmsg_len = sizeof(anci); 915 anci.hdr.cmsg_level = IPPROTO_SCTP; 916 anci.hdr.cmsg_type = SCTP_SNDRCV; 917 anci.sndrcv.sinfo_stream = strid; 918 /* note : we could store other data also, for example in .sinfo_ppid for remote peer or in .sinfo_context for errors. */ 919 920 /* We don't use mhdr.msg_name here; it could be used to specify an address different from the primary */ 921 922 mhdr.msg_iov = &iov; 923 mhdr.msg_iovlen = 1; 924 925 mhdr.msg_control = &anci; 926 mhdr.msg_controllen = sizeof(anci); 927 928 TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock); 929 930 CHECK_SYS( ret = sendmsg(sock, &mhdr, 0) ); 931 ASSERT( ret == len ); /* There should not be partial delivery with sendmsg... */ 932 933 return 0; 934 } 935 936 /* Receive the next data from the socket, or next notification */ 937 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event) 938 { 939 ssize_t ret = 0; 940 struct msghdr mhdr; 941 char ancidata[ CMSG_BUF_LEN ]; 942 struct iovec iov; 943 uint8_t *data = NULL; 944 size_t bufsz = 0, datasize = 0; 945 size_t mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */ 946 947 TRACE_ENTRY("%d %p %p %p %p", sock, strid, buf, len, event); 948 CHECK_PARAMS( (sock > 0) && buf && len && event ); 949 950 /* Cleanup out parameters */ 951 *buf = NULL; 952 *len = 0; 953 *event = 0; 954 955 /* Prepare header for receiving message */ 956 memset(&mhdr, 0, sizeof(mhdr)); 957 mhdr.msg_iov = &iov; 958 mhdr.msg_iovlen = 1; 959 mhdr.msg_control = &ancidata; 960 mhdr.msg_controllen = sizeof(ancidata); 961 962 /* We will loop while all data is not received. */ 963 incomplete: 964 if (datasize == bufsz) { 965 /* The buffer is full, enlarge it */ 966 bufsz += mempagesz; 967 CHECK_MALLOC( data = realloc(data, bufsz) ); 968 } 969 /* the new data will be received following the preceding */ 970 memset(&iov, 0, sizeof(iov)); 971 iov.iov_base = data + datasize ; 972 iov.iov_len = bufsz - datasize; 973 974 /* Receive data from the socket */ 975 pthread_cleanup_push(free, data); 976 ret = recvmsg(sock, &mhdr, 0); 977 pthread_cleanup_pop(0); 978 979 /* Handle errors */ 980 if (ret <= 0) { /* Socket is closed, or an error occurred */ 981 CHECK_SYS_DO(ret, /* to log in case of error */); 982 free(data); 983 *event = FDEVP_CNX_ERROR; 984 return 0; 985 } 986 987 /* Update the size of data we received */ 988 datasize += ret; 989 990 /* SCTP provides an indication when we received a full record; loop if it is not the case */ 991 if ( ! (mhdr.msg_flags & MSG_EOR) ) { 992 goto incomplete; 993 } 994 995 TRACE_DEBUG(FULL, "Received %db data on socket %d", datasize, sock); 996 997 /* Handle the case where the data received is a notification */ 998 if (mhdr.msg_flags & MSG_NOTIFICATION) { 999 union sctp_notification * notif = (union sctp_notification *) data; 1000 1001 switch (notif->sn_header.sn_type) { 1002 1003 case SCTP_ASSOC_CHANGE: 1004 TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification"); 1005 TRACE_DEBUG(SCTP_LEVEL, " state : %hu", notif->sn_assoc_change.sac_state); 1006 TRACE_DEBUG(SCTP_LEVEL, " error : %hu", notif->sn_assoc_change.sac_error); 1007 TRACE_DEBUG(SCTP_LEVEL, " instr : %hu", notif->sn_assoc_change.sac_inbound_streams); 1008 TRACE_DEBUG(SCTP_LEVEL, " outstr : %hu", notif->sn_assoc_change.sac_outbound_streams); 1009 1010 *event = FDEVP_CNX_EP_CHANGE; 1011 break; 1012 1013 case SCTP_PEER_ADDR_CHANGE: 1014 TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification"); 1015 TRACE_DEBUG_sSA(SCTP_LEVEL, " intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" ); 1016 TRACE_DEBUG(SCTP_LEVEL, " state : %d", notif->sn_paddr_change.spc_state); 1017 TRACE_DEBUG(SCTP_LEVEL, " error : %d", notif->sn_paddr_change.spc_error); 1018 1019 *event = FDEVP_CNX_EP_CHANGE; 1020 break; 1021 1022 case SCTP_SEND_FAILED: 1023 TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification"); 1024 TRACE_DEBUG(SCTP_LEVEL, " len : %hu", notif->sn_send_failed.ssf_length); 1025 TRACE_DEBUG(SCTP_LEVEL, " err : %d", notif->sn_send_failed.ssf_error); 1026 1027 *event = FDEVP_CNX_ERROR; 1028 break; 1029 1030 case SCTP_REMOTE_ERROR: 1031 TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification"); 1032 TRACE_DEBUG(SCTP_LEVEL, " err : %hu", ntohs(notif->sn_remote_error.sre_error)); 1033 TRACE_DEBUG(SCTP_LEVEL, " len : %hu", ntohs(notif->sn_remote_error.sre_length)); 1034 1035 *event = FDEVP_CNX_ERROR; 1036 break; 1037 1038 case SCTP_SHUTDOWN_EVENT: 1039 TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification"); 1040 1041 *event = FDEVP_CNX_ERROR; 1042 break; 1043 1044 default: 1045 TRACE_DEBUG(FULL, "Received unknown notification %d, assume error", notif->sn_header.sn_type); 1046 *event = FDEVP_CNX_ERROR; 1047 } 1048 1049 free(data); 1050 return 0; 1051 } 1052 1053 /* From this point, we have received a message */ 1054 *event = FDEVP_CNX_MSG_RECV; 1055 *buf = data; 1056 *len = datasize; 1057 1058 if (strid) { 1059 struct cmsghdr *hdr; 1060 struct sctp_sndrcvinfo *sndrcv; 1061 1062 /* Handle the anciliary data */ 1063 for (hdr = CMSG_FIRSTHDR(&mhdr); hdr; hdr = CMSG_NXTHDR(&mhdr, hdr)) { 1064 1065 /* We deal only with anciliary data at SCTP level */ 1066 if (hdr->cmsg_level != IPPROTO_SCTP) { 1067 TRACE_DEBUG(FULL, "Received some anciliary data at level %d, skipped", hdr->cmsg_level); 1068 continue; 1069 } 1070 1071 /* Also only interested in SCTP_SNDRCV message for the moment */ 1072 if (hdr->cmsg_type != SCTP_SNDRCV) { 1073 TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type); 1074 continue; 1075 } 1076 1077 sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr); 1078 if (TRACE_BOOL(SCTP_LEVEL)) { 1079 fd_log_debug( "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV\n"); 1080 fd_log_debug( " sinfo_stream : %hu\n", sndrcv->sinfo_stream); 1081 fd_log_debug( " sinfo_ssn : %hu\n", sndrcv->sinfo_ssn); 1082 fd_log_debug( " sinfo_flags : %hu\n", sndrcv->sinfo_flags); 1083 /* fd_log_debug( " sinfo_pr_policy : %hu\n", sndrcv->sinfo_pr_policy); */ 1084 fd_log_debug( " sinfo_ppid : %u\n" , sndrcv->sinfo_ppid); 1085 fd_log_debug( " sinfo_context : %u\n" , sndrcv->sinfo_context); 1086 /* fd_log_debug( " sinfo_pr_value : %u\n" , sndrcv->sinfo_pr_value); */ 1087 fd_log_debug( " sinfo_tsn : %u\n" , sndrcv->sinfo_tsn); 1088 fd_log_debug( " sinfo_cumtsn : %u\n" , sndrcv->sinfo_cumtsn); 1089 } 1090 1091 *strid = sndrcv->sinfo_stream; 1092 } 1093 } 1094 1095 return 0; 1096 }
Note: See TracChangeset
for help on using the changeset viewer.