Skip to main content

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]