Sockets API Extensions for the Stream Control Transmission Protocol (SCTP)
RFC 6458
Document | Type | RFC - Informational (December 2011) Errata | |
---|---|---|---|
Authors | Michael Tüxen , Vladislav Yasevich , Peter Lei , Randall R. Stewart , Kacheong Poon | ||
Last updated | 2020-04-28 | ||
RFC stream | Internet Engineering Task Force (IETF) | ||
Formats | |||
Additional resources | Mailing list discussion | ||
IESG | Responsible AD | Wesley Eddy | |
Send notices to | (None) |
RFC 6458
quot; #define SIZE_OF_MESSAGE 1000 #define NUMBER_OF_MESSAGES 10 #define PPID 1234 Stewart, et al. Informational [Page 106] RFC 6458 SCTP Sockets API December 2011 int main(void) { unsigned int i; int sd; struct sockaddr_in addr; char buffer[SIZE_OF_MESSAGE]; struct iovec iov; struct sctp_status status; struct sctp_initmsg init; struct sctp_sndinfo info; struct sctp_setadaptation ind; socklen_t opt_len; /* Create a one-to-one style SCTP socket. */ if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0) { perror("socket"); exit(1); } /* Prepare for requesting 2048 outgoing streams. */ memset(&init, 0, sizeof(init)); init.sinit_num_ostreams = 2048; if (setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &init, (socklen_t)sizeof(init)) < 0) { perror("setsockopt"); exit(1); } ind.ssb_adaptation_ind = 0x01020304; if (setsockopt(sd, IPPROTO_SCTP, SCTP_ADAPTATION_LAYER, &ind, (socklen_t)sizeof(ind)) < 0) { perror("setsockopt"); exit(1); } /* Connect to the discard server. */ memset(&addr, 0, sizeof(addr)); #ifdef HAVE_SIN_LEN addr.sin_len = sizeof(struct sockaddr_in); #endif addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = inet_addr(ADDR); Stewart, et al. Informational [Page 107] RFC 6458 SCTP Sockets API December 2011 if (connect(sd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { perror("connect"); exit(1); } /* Get the actual number of outgoing streams. */ memset(&status, 0, sizeof(status)); opt_len = (socklen_t)sizeof(status); if (getsockopt(sd, IPPROTO_SCTP, SCTP_STATUS, &status, &opt_len) < 0) { perror("getsockopt"); exit(1); } memset(&info, 0, sizeof(info)); info.snd_ppid = htonl(PPID); info.snd_flags = SCTP_UNORDERED; memset(buffer, 'A', SIZE_OF_MESSAGE); iov.iov_base = buffer; iov.iov_len = SIZE_OF_MESSAGE; for (i = 0; i < NUMBER_OF_MESSAGES; i++) { info.snd_sid = i % status.sstat_outstrms; if (sctp_sendv(sd, (const struct iovec *)&iov, 1, NULL, 0, &info, sizeof(info), SCTP_SENDV_SNDINFO, 0) < 0) { perror("sctp_sendv"); exit(1); } } if (close(sd) < 0) { perror("close"); exit(1); } return(0); } <CODE ENDS> Stewart, et al. Informational [Page 108] RFC 6458 SCTP Sockets API December 2011 Appendix B. Example Using One-to-Many Style Sockets The following code is a simple implementation of a discard server over SCTP. The example shows how to use some features of one-to-many style IPv6 SCTP sockets, including o Opening and binding of a socket. o Enabling notifications. o Handling notifications. o Configuring the auto-close timer. o Using sctp_recvv() to receive messages. Please note that this server can be used in combination with the client described in Appendix A. <CODE BEGINS> /* Copyright (c) 2011 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with or without modification, is permitted pursuant to, and subject to the license terms contained in, the Simplified BSD License set forth in Section 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info). */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/sctp.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define BUFFER_SIZE (1<<16) #define PORT 9 #define ADDR "0.0.0.0" #define TIMEOUT 5 Stewart, et al. Informational [Page 109] RFC 6458 SCTP Sockets API December 2011 static void print_notification(void *buf) { struct sctp_assoc_change *sac; struct sctp_paddr_change *spc; struct sctp_adaptation_event *sad; union sctp_notification *snp; char addrbuf[INET6_ADDRSTRLEN]; const char *ap; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; snp = buf; switch (snp->sn_header.sn_type) { case SCTP_ASSOC_CHANGE: sac = &snp->sn_assoc_change; printf("^^^ Association change: "); switch (sac->sac_state) { case SCTP_COMM_UP: printf("Communication up (streams (in/out)=(%u/%u)).\n", sac->sac_inbound_streams, sac->sac_outbound_streams); break; case SCTP_COMM_LOST: printf("Communication lost (error=%d).\n", sac->sac_error); break; case SCTP_RESTART: printf("Communication restarted (streams (in/out)=(%u/%u).\n", sac->sac_inbound_streams, sac->sac_outbound_streams); break; case SCTP_SHUTDOWN_COMP: printf("Communication completed.\n"); break; case SCTP_CANT_STR_ASSOC: printf("Communication couldn't be started.\n"); break; default: printf("Unknown state: %d.\n", sac->sac_state); break; } break; case SCTP_PEER_ADDR_CHANGE: spc = &snp->sn_paddr_change; if (spc->spc_aaddr.ss_family == AF_INET) { sin = (struct sockaddr_in *)&spc->spc_aaddr; ap = inet_ntop(AF_INET, &sin->sin_addr, addrbuf, INET6_ADDRSTRLEN); } else { Stewart, et al. Informational [Page 110] RFC 6458 SCTP Sockets API December 2011 sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; ap = inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, INET6_ADDRSTRLEN); } printf("^^^ Peer Address change: %s ", ap); switch (spc->spc_state) { case SCTP_ADDR_AVAILABLE: printf("is available.\n"); break; case SCTP_ADDR_UNREACHABLE: printf("is not available (error=%d).\n", spc->spc_error); break; case SCTP_ADDR_REMOVED: printf("was removed.\n"); break; case SCTP_ADDR_ADDED: printf("was added.\n"); break; case SCTP_ADDR_MADE_PRIM: printf("is primary.\n"); break; default: printf("unknown state (%d).\n", spc->spc_state); break; } break; case SCTP_SHUTDOWN_EVENT: printf("^^^ Shutdown received.\n"); break; case SCTP_ADAPTATION_INDICATION: sad = &snp->sn_adaptation_event; printf("^^^ Adaptation indication 0x%08x received.\n", sad->sai_adaptation_ind); break; default: printf("^^^ Unknown event of type: %u.\n", snp->sn_header.sn_type); break; }; } Stewart, et al. Informational [Page 111] RFC 6458 SCTP Sockets API December 2011 int main(void) { int sd, flags, timeout, on; ssize_t n; unsigned int i; union { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_in6 sin6; } addr; socklen_t fromlen, infolen; struct sctp_rcvinfo info; unsigned int infotype; struct iovec iov; char buffer[BUFFER_SIZE]; struct sctp_event event; uint16_t event_types[] = {SCTP_ASSOC_CHANGE, SCTP_PEER_ADDR_CHANGE, SCTP_SHUTDOWN_EVENT, SCTP_ADAPTATION_INDICATION}; /* Create a one-to-many style SCTP socket. */ if ((sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0) { perror("socket"); exit(1); } /* Enable the events of interest. */ memset(&event, 0, sizeof(event)); event.se_assoc_id = SCTP_FUTURE_ASSOC; event.se_on = 1; for (i = 0; i < sizeof(event_types)/sizeof(uint16_t); i++) { event.se_type = event_types[i]; if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) < 0) { perror("setsockopt"); exit(1); } } /* Configure auto-close timer. */ timeout = TIMEOUT; if (setsockopt(sd, IPPROTO_SCTP, SCTP_AUTOCLOSE, &timeout, sizeof(timeout)) < 0) { perror("setsockopt SCTP_AUTOCLOSE"); exit(1); } Stewart, et al. Informational [Page 112] RFC 6458 SCTP Sockets API December 2011 /* Enable delivery of SCTP_RCVINFO. */ on = 1; if (setsockopt(sd, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0) { perror("setsockopt SCTP_RECVRCVINFO"); exit(1); } /* Bind the socket to all local addresses. */ memset(&addr, 0, sizeof(addr)); #ifdef HAVE_SIN6_LEN addr.sin6.sin6_len = sizeof(addr.sin6); #endif addr.sin6.sin6_family = AF_INET6; addr.sin6.sin6_port = htons(PORT); addr.sin6.sin6_addr = in6addr_any; if (bind(sd, &addr.sa, sizeof(addr.sin6)) < 0) { perror("bind"); exit(1); } /* Enable accepting associations. */ if (listen(sd, 1) < 0) { perror("listen"); exit(1); } for (;;) { flags = 0; memset(&addr, 0, sizeof(addr)); fromlen = (socklen_t)sizeof(addr); memset(&info, 0, sizeof(info)); infolen = (socklen_t)sizeof(info); infotype = 0; iov.iov_base = buffer; iov.iov_len = BUFFER_SIZE; n = sctp_recvv(sd, &iov, 1, &addr.sa, &fromlen, &info, &infolen, &infotype, &flags); if (flags & MSG_NOTIFICATION) { print_notification(iov.iov_base); } else { char addrbuf[INET6_ADDRSTRLEN]; const char *ap; in_port_t port; Stewart, et al. Informational [Page 113] RFC 6458 SCTP Sockets API December 2011 if (addr.sa.sa_family == AF_INET) { ap = inet_ntop(AF_INET, &addr.sin.sin_addr, addrbuf, INET6_ADDRSTRLEN); port = ntohs(addr.sin.sin_port); } else { ap = inet_ntop(AF_INET6, &addr.sin6.sin6_addr, addrbuf, INET6_ADDRSTRLEN); port = ntohs(addr.sin6.sin6_port); } printf("Message received from %s:%u: len=%d", ap, port, (int)n); switch (infotype) { case SCTP_RECVV_RCVINFO: printf(", sid=%u", info.rcv_sid); if (info.rcv_flags & SCTP_UNORDERED) { printf(", unordered"); } else { printf(", ssn=%u", info.rcv_ssn); } printf(", tsn=%u", info.rcv_tsn); printf(", ppid=%u.\n", ntohl(info.rcv_ppid)); break; case SCTP_RECVV_NOINFO: case SCTP_RECVV_NXTINFO: case SCTP_RECVV_RN: printf(".\n"); break; default: printf(" unknown infotype.\n"); } } } if (close(sd) < 0) { perror("close"); exit(1); } return (0); } <CODE ENDS> Stewart, et al. Informational [Page 114] RFC 6458 SCTP Sockets API December 2011 Authors' Addresses Randall R. Stewart Adara Networks Chapin, SC 29036 USA EMail: randall@lakerest.net Michael Tuexen Muenster University of Applied Sciences Stegerwaldstr. 39 48565 Steinfurt Germany EMail: tuexen@fh-muenster.de Kacheong Poon Oracle Corporation EMail: ka-cheong.poon@oracle.com Peter Lei Cisco Systems, Inc. 9501 Technology Blvd. West Office Center Rosemont, IL 60018 USA EMail: peterlei@cisco.com Vladislav Yasevich HP 110 Spitrook Rd. Nashua, NH 03062 USA EMail: vladislav.yasevich@hp.com Stewart, et al. Informational [Page 115]