Socket API for SCTP on OpenVMS V5.7-01 The SCTP socket API has been implemented as a shareable image. Applications using the SCTP API must be linked with: SYS$COMMON:[SYSLIB]TCPIP$SCTP_SHR.EXE NOTE: When linking with a shareable image, the image must appear in an link options file. Refer to the OpenVMS Linker Utility Manual for more information. E.g. $ LINK MY_SCTP_APP, SYS$INPUT:/OPTIONS SYS$LIBRARY:TCPIP$SCTP_SHR/SHARE SCTP API Functions ================== Modeled on routines from FreeBSD V7.0. The following routines are derived from the IETF draft, Sockets API Extensions for Stream Control Transmission Protocol (SCTP), revision 16. [draft-ietf-tsvwg-sctpsocket-17.txt] The routines require BSD4.4 sockets, so any applications that use them must be compiled with _SOCKADDR_LEN defined. - sctp_bindx() - sctp_connectx() - sctp_peeloff() - sctp_getpaddrs() - sctp_freepaddrs() - sctp_getladdrs() - sctp_freeladdrs() - sctp_send() - sctp_sendx() - sctp_sendmsg() - sctp_sendmsgx() - sctp_recvmsg() - sctp_getaddrlen() - sctp_opt_info() - sctp_getassocid() Each of these routines is described in detail in Appendix B. Building SCTP Applications ========================== SCTP Header Files ----------------- Two new header files are required to compile applications using the SCTP API. The file, "sctp_uio.h" is included by "sctp.h", so there is no need to explicitly include in the source code. In addition the header file was modified to define the SCTP protocol type: #define IPPROTO_SCTP 132 /* SCTP */ This protocol type must be passed as the "protocol" argument in the socket() API. E.g. to create a socket that uses SCTP: sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); These header files will appear in the DECC text library in some future release of DECC. In the meantime, they are installed in the TCPIP$EXAMPLES directory. To compile SCTP sources, these header files must be in your include path. One option is to define logicals as follows: $ define netinet tcpip$examples $ define sys tcpip$examples Compilation ----------- The SCTP API requires BSD4.4 sockets. To compile with BSD4.4 socket definitions, the code must be compiled with _SOCKADDR_LEN defined. Without this defined, the default on OpenVMS is to use BSD4.3 sockets. This can be defined in the source code, before any other inclusions, or via the CC command-line-interface. In the source code, the first line of the file (or at least before any other header files are included) should be: #define _SOCKADDR_LEN Alternately, on the command line using the "/DEFINE" option, as in: $ CC /DEFINE=(_SOCKADDR_LEN) ... Linking ------- The SCTP API is supplied as a shareable image: SYS$LIBRARY:TCPIP$SCTP_SHR.EXE Shareable images must be linked with the main object via a link options file. Refer to the OpenVMS Linker Utility Manual for more information. E.g. $ LINK MY_SCTP_APP, SYS$INPUT:/OPTIONS SYS$LIBRARY:TCPIP$SCTP_SHR/SHARE ---------------------------------------------------------------------------- APPENDIX A - SAMPLE CODE ======================== Any TCP application can easily be modified to use SCTP by simply changing the socket call to use IPPROTO_SCTP. E.g. TCP_socket = socket(AF_INET, SOCK_STREAM, 0); SCTP_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); The programs below illustrate very simple use of the SCTP API. - sctp_server.c : server uses select() to read data over SCTP socket - sctp_client.c : client reads user input and send over SCTP socket. - sctp_clientx.c : client uses sctp_connectx() ---------------------------------------------------------------------------- #pragma module SCTP_SERVER "V5.7-00" /* ** BUILD ENVIRONMENT: ** ** If the current version of DECC does not suport SCTP, then you must ** manually configure the environment as follows: ** ** $ define netinet tcpip$examples ** $ define sys tcpip$examples ** ** BUILD INSTRUCTIONS: ** ** $ cc sctp_server ** $ link sctp_server,sys$input:/options ** sys$library:tcpip$sctp_shr/share ** ** SYNTAX: ** ** sctp_server [port] ** ** EXAMPLE: ** ** Define a foreign symbol to point at the application. ** ** $ sctp_server :== $MYDEV:[MYDIR]sctp_server ** $ sctp_server */ #define _SOCKADDR_LEN #include #include #include #include #ifndef __VMS #include #else #include #endif typedef unsigned int socklen_t; /* usually defined in socket.h */ #include #include #include #include #include /* SCTP */ #define DEF_PORT 55555 #define SA(x) ((struct sockaddr *)x) int main(int argc, char *argv[]) { int listen_sd, sd, cc, port; struct sockaddr_in local, peer; socklen_t peerlen = sizeof(peer); char peer_name[INET6_ADDRSTRLEN]; char buf[128]; if(argc == 2) port = atoi(argv[1]); else port = DEF_PORT; /* setup the local address that we will bind to and listen on */ local.sin_len = sizeof(local); local.sin_family = AF_INET; local.sin_port = htons(port); local.sin_addr.s_addr = INADDR_ANY; /* create an SCTP socket */ listen_sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); if(listen_sd == -1) {perror("socket"); return 1;} /* bind to local port and address(es) */ if(bind(listen_sd, SA(&local), local.sin_len) == -1) {perror("bind"); return 1;} /* prepare to accept connections */ if(listen(listen_sd, 5) == -1) {perror("listen"); return 1;} printf("Waiting for connections on SCTP port %d ...\n", port); peerlen = sizeof(peer); if((sd = accept(listen_sd, (struct sockaddr *)&peer, &peerlen)) == -1) {perror("accept"); return 1;} close(listen_sd); /* finished with listen socket */ printf("Accepted connection from: %s:%d\n", inet_ntop(AF_INET, &peer.sin_addr.s_addr, peer_name, INET6_ADDRSTRLEN), ntohs(peer.sin_port)); while(1) { cc = recv(sd, &buf, sizeof(buf), 0); if(cc == -1) /* error on socket */ {perror("recv"); break;} if(cc == 0) /* peer disconnect */ {printf("Peer closed connection."); break;} /* data available */ buf[cc] = '\0'; printf("Received: %s\n", buf); if(buf[0] == 'Q') break; } /* read forever */ close(sd); printf("All done\n"); } ---------------------------------------------------------------------------- #pragma module SCTP_CLIENT "V5.7-00" /* ** BUILD ENVIRONMENT: ** ** If the current version of DECC does not suport SCTP, then you must ** manually configure the environment as follows: ** ** $ define netinet tcpip$examples ** $ define sys tcpip$examples ** ** BUILD INSTRUCTIONS: ** ** $ cc sctp_client ** $ link sctp_client,sys$input:/options ** sys$library:tcpip$sctp_shr/share ** ** SYNTAX: ** ** sctp_client [port] ** ** EXAMPLE: ** ** Define a foreign symbol to point at the application. ** ** $ sctp_client :== $MYDEV:[MYDIR]sctp_client ** $ sctp_client myserver */ #define _SOCKADDR_LEN #include #include #include #ifndef __VMS #include #else #include #endif typedef unsigned int socklen_t; /* usually defined in socket.h */ #include #include #include #include #include /* SCTP */ #define DEF_PORT 55555 #define SA(x) ((struct sockaddr *)x) int main(int argc, char *argv[]) { int sd; int count = 0, cc; struct sockaddr_in peer; int peerlen = sizeof(peer); char peername[INET6_ADDRSTRLEN]; char *hostname; int port; in_addr_t in_addr; struct hostent *hent; char line[128]; if(argc == 1) {printf("Usage: client [port]\n"); return 1;} hostname = argv[1]; if(argc == 3) port = atoi(argv[2]); else port = DEF_PORT; /* convert hostname string to in_addr_t */ in_addr = inet_addr(hostname); /* first try dotted decimal notation? */ if(in_addr == (in_addr_t)-1) { hent = gethostbyname(hostname); /* now try DNS */ if(hent == NULL) {printf("No host information for %s\n", hostname); return 1;} in_addr = *(int *)hent->h_addr; } /* setup the local address that we will connect to */ peer.sin_len = sizeof(peer); peer.sin_family = AF_INET; peer.sin_port = htons(port); peer.sin_addr.s_addr = in_addr; /* create an SCTP socket */ sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); if(sd == -1) {perror("socket"); return 1;} /* connect to server */ if(connect(sd, SA(&peer), peerlen) == -1) {perror("connect"); return 1;} printf("Connected to: %s:%d\n", inet_ntop(AF_INET, &peer.sin_addr.s_addr, &peername[0], sizeof(peername)), ntohs(peer.sin_port)); /* write loop */ do { printf("Enter a line to send:"); if(scanf("%[^\n]%*c", line) == -1) {perror("scanf"); return 1;} cc = write(sd, line, strlen(line)); if(cc == -1) {perror("send"); return(1);} } while(cc != -1 && line[0] != 'Q'); if(close(sd) == -1) {perror("close"); return 1;} return 0; } ---------------------------------------------------------------------------- #pragma module SCTP_CLIENTX "V5.7-00" /* ** PURPOSE: ** ** Simple SCTP client using the sctp_connectx() API. ** ** BUILD ENVIRONMENT: ** ** If the current version of DECC does not suport SCTP, then you must ** manually configure the environment as follows: ** ** $ define netinet tcpip$examples ** $ define sys tcpip$examples ** ** BUILD INSTRUCTIONS: ** ** $ cc sctp_clientx ** $ link sctp_clientx,sys$input:/options ** sys$library:tcpip$sctp_shr/share ** ** SYNTAX: ** ** sctp_clientx [port] ** ** EXAMPLE: ** ** Define a foreign symbol to point at the application. ** ** $ sctp_clientx :== $MYDEV:[MYDIR]sctp_clientx ** $ sctp_clientx myserver */ #define _SOCKADDR_LEN #include #include #include #ifndef __VMS #include #else #include #endif typedef unsigned int socklen_t; /* normally found in socket.h */ #include #include #include #include #include /* SCTP */ #define SA(x) ((struct sockaddr *)(x)) #define SIN(x) ((struct sockaddr_in *)(x)) #define DECODE_AF(af) ((af) == AF_INET ? "AF_INET" : \ (af) == AF_INET6 ? "AF_INET6" : \ "Unknown"), af #define DECODE_ST(st) ((st) == SOCK_STREAM ? "SOCK_STREAM" : \ (st) == SOCK_DGRAM ? "SOCK_DGRAM" : \ (st) == SOCK_RAW ? "SOCK_RAW" : \ (st) == SOCK_SEQPACKET ? "SOCK_SEQPACKET" : \ "Unknown"), st #define DECODE_PR(pr) ((pr) == IPPROTO_TCP ? "IPPROTO_TCP" : \ (pr) == IPPROTO_UDP ? "IPPROTO_UDP" : \ (pr) == IPPROTO_SCTP ? "IPPROTO_SCTP" : \ "Unknown"), pr #define DEF_PORTNAME "55555" void display_sockaddr(struct sockaddr *sa) { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; char name[256]; int err; /* retrieve the nodename */ err = getnameinfo(sa, sa->sa_len, name, sizeof(name), NULL, 0, 0); if(err) { if(err == EAI_SYSTEM) perror("getnameinfo"); else printf("getnameinfo: %s\n", gai_strerror(err)); return; } printf("sockaddr:\n"); printf(" len : %d\n", sa->sa_len); printf(" family: %s (%d)\n", DECODE_AF(sa->sa_family)); switch(sa->sa_family) { case AF_INET: printf(" IPV4 Address Details:\n"); sin = (struct sockaddr_in *)sa; printf(" sin_port : %d\n", ntohs(sin->sin_port)); printf(" sin_addr : %#x (%s)\n", sin->sin_addr.s_addr, name); break; case AF_INET6: printf(" IPV6 Address Details:\n"); sin6 = (struct sockaddr_in6 *)sa; printf(" sin6_port : %d\n", ntohs(sin6->sin6_port)); printf(" sin6_flowinfo: %d\n", sin6->sin6_flowinfo); printf(" sin6_addr[1] : %#Lx (%s)\n", sin6->sin6_addr.s6_qaddr[1], name); printf(" sin6_addr[0] : %#Lx\n", sin6->sin6_addr.s6_qaddr[0]); break; default: printf("Unknown address family: %d\n", sa->sa_family); } } void display_addrinfo(struct addrinfo *ai) { int i = 0; for(; ai; ai = ai->ai_next) { printf("--- %d ----------------------------\n", ++i); printf("ai_family : %s (%d)\n", DECODE_AF(ai->ai_family)); printf("ai_socktype : %s (%d)\n", DECODE_ST(ai->ai_socktype)); printf("ai_protocol : %s (%d)\n", DECODE_PR(ai->ai_protocol)); printf("ai_addrlen : %d\n", ai->ai_addrlen); printf("ai_canonname: %s\n", ai->ai_canonname); display_sockaddr(ai->ai_addr); } } void display_packed_sockaddrs(struct sockaddr_storage *ss, int count) { int i, len; len = 0; for(i = 0; i < count; i++) { printf("+++ %d of %d +++++++++++++++++++++++++++++\n", i+1, count); display_sockaddr(SA((char *)ss + len)); len += ss->ss_len; } } struct addrinfo *parse_addrinfo(char *server, char *service, int protocol, int socktype) { struct addrinfo *res, hints; int err; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_protocol = protocol; hints.ai_socktype = socktype; hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; err = getaddrinfo(server, /* name, alias, or numeric address IPV4/IPV6 */ service,/* service name or port number */ &hints, /* hints limit search to sock type, AF or proto */ &res); /* linked list of addrinfo structures */ if(err) { if(err == EAI_SYSTEM) perror("getaddrinfo"); else printf("%s", gai_strerror(err)); return NULL; } return res; } int main(int argc, char *argv[]) { int sd; int count, cc; char *server, *portname; struct addrinfo *ai; char line[128]; in_addr_t in_addr; struct hostent *hent; struct sockaddr_storage *connectx_addrs = NULL; /* packed addresses */ struct sockaddr_storage *paddrs, *laddrs; /* packed addresses */ if(argc == 1) {printf("Usage: connectx [port]\n"); return 1;} server = argv[1]; if(argc == 3) portname = argv[2]; else portname = DEF_PORTNAME; ai = parse_addrinfo(server, portname, IPPROTO_SCTP, SOCK_STREAM); if(ai == NULL) {printf("Error retrieving address information\n"); return 1;} printf("Addresses matching %s\n", server); display_addrinfo(ai); /* pack socket addresses into the connectx buffer */ count = 0; cc = 0; for(; ai; ai = ai->ai_next) { connectx_addrs = realloc(connectx_addrs, cc + ai->ai_addrlen); /* add an element */ if(connectx_addrs == NULL) {perror("realloc"); return 1;} memcpy((char *)connectx_addrs + cc, ai->ai_addr, ai->ai_addrlen); count++; /* one more address packed in */ cc += ai->ai_addrlen; } freeaddrinfo(ai); /* finished with address info */ printf("\nAddresses (packed) to connect to (%d):\n", count); display_packed_sockaddrs(connectx_addrs, count); /* create socket */ sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); if(sd == -1) {perror("socket"); return 1;} if(sctp_connectx(sd, SA(connectx_addrs), count, 0) == -1) {perror("sctp_connectx"); return 1;} /* call getpaddrs to get list of peer addresses in association */ count = sctp_getpaddrs(sd, 0, (struct sockaddr **)&paddrs); if(count == -1) {perror("sctp_getpaddrs"); return 1;} printf("\nPeer Addresses in association 0:\n"); display_packed_sockaddrs(paddrs, count); /* call getladdrs to get list of local addresses in association */ count = sctp_getladdrs(sd, 0, (struct sockaddr **)&laddrs); if(count == -1) {perror("sctp_getladdrs"); return 1;} printf("\nLocal Addresses in association 0:\n"); display_packed_sockaddrs(laddrs, count); /* write loop */ count = 0; do { printf("Enter a line to send:"); if(scanf("%[^\n]%*c", line) == -1) {perror("scanf"); return 1;} cc = write(sd, line, strlen(line)); if(cc == -1) {perror("send"); return 1;} if(cc == 0) {printf("Peer disconnected\n"); break;} } while(cc != -1 && line[0] != 'Q'); if(close(sd) == -1) {perror("close"); return 1;} } ---------------------------------------------------------------------------- APPENDIX B - SCTP API Definitions ================================= The specification of the SCTP API routines is described in the following pages. The supported SCTP API routines are listed below: - sctp_bindx() - sctp_connectx() - sctp_peeloff() - sctp_getpaddrs() - sctp_freepaddrs() - sctp_getladdrs() - sctp_freeladdrs() - sctp_send() - sctp_sendx() - sctp_sendmsg() - sctp_sendmsgx() - sctp_recvmsg() - sctp_getaddrlen() - sctp_opt_info() - sctp_getassocid() ---------------------------------------------------------------------------- SCTP_BINDX Bind or unbind an SCTP socket to a list of addresses. SYNOPSIS #include #include #include int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags); DESCRIPTION The sctp_bindx() call binds or unbinds an address or a list of addresses to an SCTP endpoint. This allows a user to bind a subset of addresses. The sctp_bindx() call operates similarly to bind() but allows a list of addresses and also allows a bind or an unbind. The argument must be a valid SCTP socket descriptor. The argument addrs is a list of addresses (where the list may be only 1 in length) that the user wishes to bind or unbind to the socket. The argument flags must be one of the following values. SCTP_BINDX_ADD_ADDR This value indicates that the listed address(es) need to be added to the endpoint. SCTP_BINDX_REM_ADDR This value indicates that the listed address(es) need to be removed from the endpoint. Note that when a user adds or deletes an address to an association if the dynamic address flag net.inet.sctp.auto_asconf is enabled any associa- tions in the endpoint will attempt to have the address(es) added dynami- cally to the existing association. RETURN VALUES The call returns 0 on success and -1 upon failure. ERRORS The sctp_bindx() can return the following errors. [EINVAL] This value is returned if the flags field is not one of the allowed values (see above). [ENOMEM] This value is returned if the number of addresses being added causes a memory allocation failure in the call. [EBADF] The argument s is not a valid descriptor. [ENOTSOCK] The argument s is not a socket. ---------------------------------------------------------------------------- SCTP_CONNECTX NAME sctp_connectx -- connect an SCTP socket with multiple destination addresses. SYNOPSIS #include #include #include int sctp_connectx(int sd, struct sockaddr *, int addrcnt, sctp_assoc_t *id); DESCRIPTION The sctp_connectx() call attempts to initiate an association to a peer SCTP endpoint. The call operates similarly to connect() but it also pro- vides the ability to specify multiple destination addresses for the peer. This allows a fault tolerant method of initiating an association. When one of the peers addresses is unreachable, the subsequent listed addresses will also be used to set up the association with the peer. The user also needs to consider that any address listed in an sctp_connectx() call is also considered "confirmed". A confirmed address is one in which the SCTP transport will trust is a part of the associa- tion and it will not send a confirmation heartbeat to it with a random nonce. If the peer SCTP stack does not list one or more of the provided addresses in its response message then the extra addresses sent in the sctp_connectx() call will be silently discarded from the association. On successful completion the provided sctp_assoc_t * will be filled in with the association identification of the newly forming association. RETURN VALUES The call returns 0 on success and -1 upon failure. ERRORS The sctp_connectx() can return the following errors. [EINVAL] An address listed has an invalid family or no addresses were provided. [E2BIG] The size of the address list exceeds the amount of data provided. [EBADF] The argument s is not a valid descriptor. [ENOTSOCK] The argument s is not a socket. ---------------------------------------------------------------------------- SCTP_PEELOFF NAME sctp_peeloff -- detach an association from a one-to-many socket to a separate one-to-one socket. SYNOPSIS #include #include #include int sctp_peeloff(int sd, sctp_assoc_t id); DESCRIPTION The sctp_peeloff() system call attempts detach the association specified by id into its own seperate socket. RETURN VALUES The call returns -1 on failure and the new socket descriptor upon suc- cess. ERRORS The sctp_peeloff() can return the following errors. [ENOTCONN] The id given to the call does not map to a valid asso- ciation. [E2BIG] The size of the address list exceeds the amount of data provided. [EBADF] The argument s is not a valid descriptor. [ENOTSOCK] The argument s is not a socket. ---------------------------------------------------------------------------- SCTP_GETPADDRS SCTP_GETLADDRS NAME sctp_getpaddrs, sctp_getladdrs -- return a list of addresses to the caller SYNOPSIS #include #include #include int sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **addrs); int sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **addrs); DESCRIPTION The sctp_getpaddrs() function is used to get the list of the peers addresses. The sctp_getladdrs() function is used to get the list of the local addresses. The association of interest is identified by the asocid argument. The addresses are returned in a newly allocated array of socket addresses returned in the argument addrs upon success. After the caller is through the function sctp_freepaddrs() or sctp_freeladdrs() should be used to release the memory allocated by these calls. RETURN VALUES The call returns -1 upon failure and a count of the number of addresses returned in addrs upon success. ERRORS The functions can return the following errors. [EINVAL] An address listed has an invalid family or no addresses were provided. [ENOMEM] The call cannot allocate memory to hold the socket addresses. [EBADF] The argument s is not a valid descriptor. [ENOTSOCK] The argument s is not a socket. ---------------------------------------------------------------------------- SCTP_FREEPADDRS SCTP_FREELADDRS NAME sctp_freepaddrs, sctp_freeladdrs -- release the memory returned from a previous call SYNOPSIS #include #include #include void sctp_freepaddrs(struct sockaddr *addrs); void sctp_freeladdrs(struct sockaddr *addrs); DESCRIPTION The sctp_freepaddrs() and sctp_freeladdrs() functions are used to release the memory allocated by previous calls to sctp_getpaddrs() or sctp_getladdrs() respectively. RETURN VALUES none. ---------------------------------------------------------------------------- SCTP_SEND SCTP_SENDX NAME sctp_send, sctp_sendx -- send a message from an SCTP socket SYNOPSIS #include #include #include ssize_t sctp_send(int sd, const void *msg, size_t len, const struct sctp_sndrcvinfo *sinfo, int flags); ssize_t sctp_sendx(int sd, const void *msg, size_t len, struct sockaddr *addrs, int addrcnt, const struct sctp_sndrcvinfo *sinfo, int flags); DESCRIPTION The sctp_send() system call is used to transmit a message to another SCTP endpoint. sctp_send() may be used to send data to an existing associa- tion for both one-to-many (SOCK_SEQPACKET) and one-to-one (SOCK_STREAM) socket types. The length of the message msg is given by len. If the message is too long to pass atomically through the underlying protocol, errno is set to EMSGSIZE, -1 is returned, and the message is not trans- mitted. No indication of failure to deliver is implicit in a sctp_send(). Locally detected errors are indicated by a return value of -1. If no space is available at the socket to hold the message to be trans- mitted, then sctp_send() normally blocks, unless the socket has been placed in non-blocking I/O mode. The select(2) system call may be used to determine when it is possible to send more data on one-to-one type (SOCK_STREAM) sockets. The sinfo structure is used to control various SCTP features and has the following format: struct sctp_sndrcvinfo { u_int16_t sinfo_stream; // Stream sending to u_int16_t sinfo_ssn; // valid for recv only u_int16_t sinfo_flags; // flags to control sending u_int32_t sinfo_ppid; // ppid field u_int32_t sinfo_context; // context field u_int32_t sinfo_timetolive; // timetolive for PR-SCTP u_int32_t sinfo_tsn; // valid for recv only u_int32_t sinfo_cumtsn; // valid for recv only sctp_assoc_t sinfo_assoc_id; // The association id }; The sinfo-_sinfo_ppid argument is an opaque 32 bit value that is passed transparently through the stack to the peer endpoint. It will be avail- able on reception of a message (see sctp_recvmsg(2)). Note that the stack passes this value without regard to byte order. The sinfo-_sinfo_flags argument may include one or more of the following: #define SCTP_EOF 0x0100 // Start a shutdown procedures #define SCTP_ABORT 0x0200 // Send an ABORT to peer #define SCTP_UNORDERED 0x0400 // Message is un-ordered #define SCTP_ADDR_OVER 0x0800 // Override the primary-address #define SCTP_SENDALL 0x1000 // Send this on all associations // for the endpoint // The lower byte is an enumeration of PR-SCTP policies #define SCTP_PR_SCTP_TTL 0x0001 // Time based PR-SCTP #define SCTP_PR_SCTP_BUF 0x0002 // Buffer based PR-SCTP #define SCTP_PR_SCTP_RTX 0x0003 // Num retransmissions based PR-SCTP The flag SCTP_EOF is used to instruct the SCTP stack to queue this mes- sage and then start a graceful shutdown of the association. All remain- ing data in queue will be sent after which the association will be shut down. SCTP_ABORT is used to immediately terminate an association. An abort is sent to the peer and the local TCB is destroyed. SCTP_UNORDERED is used to specify that the message being sent has no spe- cific order and should be delivered to the peer application as soon as possible. When this flag is absent messages are delivered in order within the stream they are sent, but without respect to order to peer streams. The flag SCTP_ADDR_OVER is used to specify that a specific address should be used. Normally SCTP will use only one of a multi-homed peers addresses as the primary address to send to. By default, no matter what the to argument is, this primary address is used to send data. By speci- fying this flag, the user is asking the stack to ignore the primary address and instead use the specified address not only as a lookup mecha- nism to find the association but also as the actual address to send to. For a one-to-many type (SOCK_SEQPACKET) socket the flag SCTP_SENDALL can be used as a convenient way to make one send call and have all associa- tions that are under the socket get a copy of the message. Note that this mechanism is quite efficent and makes only one actual copy of the data which is shared by all the associations for sending. The remaining flags are used for the partial reliability extension (RFC3758) and will only be effective if the peer endpoint supports this extension. This option specifies what local policy the local endpoint should use in skipping data. If none of these options are set, then data is never skipped over. SCTP_PR_SCTP_TTL is used to indicate that a time based lifetime is being applied to the data. The sinfo-_sinfo_timetolive argument is then a num- ber of milliseconds for which the data is attempted to be transmitted. If that many milliseconds ellapse and the peer has not acknowledged the data, the data will be skipped and no longer transmitted. Note that this policy does not even assure that the data will ever be sent. In times of a congestion with large amounts of data being queued, the sinfo-_sinfo_timetolive may expire before the first transmission is ever made. The SCTP_PR_SCTP_BUF based policy transforms the sinfo-_sinfo_timetolive field into a total number of bytes allowed on the outbound send queue. If that number or more bytes are in queue, then other buffer-based sends are looked to be removed and skipped. Note that this policy may also result in the data never being sent if no buffer based sends are in queue and the maximum specified by timetolive bytes is in queue. The SCTP_PR_SCTP_RTX policy transforms the sinfo-_sinfo_timetolive into a number of retransmissions to allow. This policy always assures that at a minimum one send attempt is made of the data. After which no more than sinfo-_sinfo_timetolive retransmissions will be made before the data is skipped. sinfo-_sinfo_stream is the SCTP stream that you wish to send the message on. Streams in SCTP are reliable (or partially reliable) flows of ordered messages. The sinfo-_sinfo_assoc_id field is used to select the association to send to on a one-to-many socket. For a one-to-one socket, this field is ignored. The sinfo-_sinfo_context field is used only in the event the message can- not be sent. This is an opaque value that the stack retains and will give to the user when a failed send is given if that notification is enabled (see sctp(4)). Normally a user process can use this value to index some application specific data structure when a send cannot be ful- filled. The flags argument holds the same meaning and values as those found in sendmsg(2) but is generally ignored by SCTP. The fields sinfo-_sinfo_ssn, sinfo-_sinfo_tsn, and sinfo-_sinfo_cumtsn are used only when receiving messages and are thus ignored by sctp_send(). The function sctp_sendx() has the same properties as sctp_send() with the additional arguments of an array of sockaddr struc- tures passed in. With the addrs argument being given as an array of addresses to be sent to and the addrcnt argument indicating how many socket addresses are in the passed in array. Note that all of the addresses will only be used when an implicit association is being set up. This allows the user the equivalent behavior as doing a sctp_connectx() followed by a sctp_send() to the association. Note that if the sinfo-_sinfo_assoc_id field is 0, then the first address will be used to look up the association in place of the association id. If both an address and an association id are specified, the association id has pri- ority. RETURN VALUES The call returns the number of characters sent, or -1 if an error occurred. ERRORS The sctp_send() system call fails if: [EBADF] An invalid descriptor was specified. [ENOTSOCK] The argument s is not a socket. [EFAULT] An invalid user space address was specified for an argument. [EMSGSIZE] The socket requires that message be sent atomically, and the size of the message to be sent made this impossible. [EAGAIN] The socket is marked non-blocking and the requested operation would block. [ENOBUFS] The system was unable to allocate an internal buffer. The operation may succeed when buffers become avail- able. [ENOBUFS] The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient con- gestion. [EHOSTUNREACH] The remote host was unreachable. [ENOTCON] On a one-to-one style socket no association exists. [ECONNRESET] An abort was received by the stack while the user was attempting to send data to the peer. [ENOENT] On a one-to-many style socket no address is specified so that the association cannot be located or the SCTP_ABORT flag was specified on a non-existing asso- ciation. [EPIPE] The socket is unable to send anymore data (SBS_CANTSENDMORE has been set on the socket). This typically means that the socket is not connected and is a one-to-one style socket. ---------------------------------------------------------------------------- SCTP_SENDMSG SCTP_SENDMSGX NAME sctp_sendmsg, sctp_sendmsgx -- send a message from an SCTP socket SYNOPSIS #include #include #include ssize_t sctp_sendmsg(int sd, const void *msg, size_t len, const struct sockaddr *to, socklen_t tolen, uint32_t ppid, uint32_t flags, uint16_t stream_no, uint32_t timetolive, uint32_t context); ssize_t sctp_sendmsgx(int sd, const void *msg, size_t len, const struct sockaddr *to, int addrcnt, uint32_t ppid, uint32_t flags, uint16_t stream_no, uint32_t timetolive, uint32_t context); DESCRIPTION The sctp_sendmsg() system call is used to transmit a message to another SCTP endpoint. The sctp_sendmsg() may be used at any time. If the socket is a one-to-many type (SOCK_SEQPACKET) socket then an attempt to send to an address that no association exists to will implicitly create a new association. Data sent in such an instance will result in the data being sent on the third leg of the SCTP four-way handshake. Note that if the socket is a one-to-one type (SOCK_STREAM) socket then an association must be in existance (by use of the connect(2) system call). Calling sctp_sendmsg() or sctp_sendmsgx() on a non-connected one-to-one socket will result in errno being set to ENOTCONN, -1 being returned, and the message not being transmitted. The address of the target is given by to with tolen specifying its size. The length of the message msg is given by len. If the message is too long to pass atomically through the underlying protocol, errno is set to EMSGSIZE, -1 is returned, and the message is not transmitted. No indication of failure to deliver is implicit in a sctp_sendmsg(2) call. Locally detected errors are indicated by a return value of -1. If no space is available at the socket to hold the message to be trans- mitted, then sctp_sendmsg(2) normally blocks, unless the socket has been placed in non-blocking I/O mode. The select(2) system call may be used to determine when it is possible to send more data on one-to-one type (SOCK_STREAM) sockets. The ppid argument is an opaque 32 bit value that is passed transparently through the stack to the peer endpoint. It will be available on recep- tion of a message (see sctp_recvmsg(2)). Note that the stack passes this value without regard to byte order. The flags argument may include one or more of the following: #define SCTP_EOF 0x0100 // Start a shutdown procedures #define SCTP_ABORT 0x0200 // Send an ABORT to peer #define SCTP_UNORDERED 0x0400 // Message is un-ordered #define SCTP_ADDR_OVER 0x0800 // Override the primary-address #define SCTP_SENDALL 0x1000 // Send this on all associations // for the endpoint // The lower byte is an enumeration of PR-SCTP policies #define SCTP_PR_SCTP_TTL 0x0001 // Time based PR-SCTP #define SCTP_PR_SCTP_BUF 0x0002 // Buffer based PR-SCTP #define SCTP_PR_SCTP_RTX 0x0003 // Num retransmissions based PR-SCTP The flag SCTP_EOF is used to instruct the SCTP stack to queue this mes- sage and then start a graceful shutdown of the association. All remain- ing data in queue will be sent after which the association will be shut down. SCTP_ABORT is used to immediately terminate an association. An abort is sent to the peer and the local TCB is destroyed. SCTP_UNORDERED is used to specify that the message being sent has no spe- cific order and should be delivered to the peer application as soon as possible. When this flag is absent messages are delivered in order within the stream they are sent, but without respect to order to peer streams. The flag SCTP_ADDR_OVER is used to specify that an specific address should be used. Normally SCTP will use only one of a multi-homed peers addresses as the primary address to send to. By default, no matter what the to argument is, this primary address is used to send data. By speci- fying this flag, the user is asking the stack to ignore the primary address and instead use the specified address not only as a lookup mecha- nism to find the association but also as the actual address to send to. For a one-to-many type (SOCK_SEQPACKET) socket the flag SCTP_SENDALL can be used as a convient way to make one send call and have all associations that are under the socket get a copy of the message. Note that this mechanism is quite efficent and makes only one actual copy of the data which is shared by all the associations for sending. The remaining flags are used for the partial reliability extension (RFC3758) and will only be effective if the peer endpoint supports this extension. This option specifies what local policy the local endpoint should use in skipping data. If none of these options are set, then data is never skipped over. SCTP_PR_SCTP_TTL is used to indicate that a time based lifetime is being applied to the data. The timetolive argument is then a number of mil- liseconds for which the data is attempted to be transmitted. If that many milliseconds ellapse and the peer has not acknowledged the data, the data will be skipped and no longer transmitted. Note that this policy does not even assure that the data will ever be sent. In times of a con- gestion with large amounts of data being queued, the timetolive may expire before the first transmission is ever made. The SCTP_PR_SCTP_BUF based policy transforms the timetolive field into a total number of bytes allowed on the outbound send queue. If that number or more bytes are in queue, then other buffer based sends are looked to be removed and skipped. Note that this policy may also result in the data never being sent if no buffer based sends are in queue and the maxi- mum specified by timetolive bytes is in queue. The SCTP_PR_SCTP_RTX policy transforms the timetolive into a number of retransmissions to allow. This policy always assures that at a minimum one send attempt is made of the data. After which no more than timetolive retransmissions will be made before the data is skipped. stream_no is the SCTP stream that you wish to send the message on. Streams in SCTP are reliable (or partially reliable) flows of ordered messages. The context field is used only in the event the message cannot be sent. This is an opaque value that the stack retains and will give to the user when a failed send is given if that notification is enabled (see sctp(4)). Normally a user process can use this value to index some application specific data structure when a send cannot be fulfilled. sctp_sendmsgx() is identical to sctp_sendmsg() with the exception that it takes an array of sockaddr structures in the argument to and adds the additional argument addrcnt which specifies how many addresses are in the array. This allows a caller to implicitly set up an association passing multiple addresses as if sctp_connectx() had been called to set up the association. RETURN VALUES The call returns the number of characters sent, or -1 if an error occurred. ERRORS The sctp_sendmsg() system call fail if: [EBADF] An invalid descriptor was specified. [ENOTSOCK] The argument s is not a socket. [EFAULT] An invalid user space address was specified for an argument. [EMSGSIZE] The socket requires that message be sent atomically, and the size of the message to be sent made this impossible. [EAGAIN] The socket is marked non-blocking and the requested operation would block. [ENOBUFS] The system was unable to allocate an internal buffer. The operation may succeed when buffers become avail- able. [ENOBUFS] The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient con- gestion. [EHOSTUNREACH] The remote host was unreachable. [ENOTCON] On a one-to-one style socket no association exists. [ECONNRESET] An abort was received by the stack while the user was attempting to send data to the peer. [ENOENT] On a one-to-many style socket no address is specified so that the association cannot be located or the SCTP_ABORT flag was specified on a non-existing asso- ciation. [EPIPE] The socket is unable to send anymore data (SBS_CANTSENDMORE has been set on the socket). This typically means that the socket is not connected and is a one-to-one style socket. ---------------------------------------------------------------------------- SCTP_RECVMSG NAME sctp_recvmsg -- receive a message from an SCTP socket SYNOPSIS #include #include #include ssize_t sctp_recvmsg(int sd, void *msg, size_t len, struct sockaddr * from, socklen_t * fromlen, struct sctp_sndrcvinfo *sinfo, int *msg_flags); DESCRIPTION The sctp_recvmsg() system call is used to receive a message from another SCTP endpoint. The sctp_recvmsg() call is used by one-to-one (SOCK_STREAM) type sockets after a successful connect() call or after the application has performed a listen() followed by a successful accept(). For a one-to-many (SOCK_SEQPACKET) type socket, an endpoint may call sctp_recvmsg() after having implicitly started an association via one of the send calls including sctp_sendmsg() sendto() and sendmsg(). Or, an application may also receive a message after having called listen() with a positive backlog to enable the reception of new associations. The address of the sender is held in the from argument with fromlen spec- ifying its size. At the completion of a successful sctp_recvmsg() call from will hold the address of the peer and fromlen will hold the length of that address. Note that the address is bounded by the inital value of fromlen which is used as an in/out variable. The length of the message msg to be received is bounded by len. If the message is too long to fit in the users receive buffer, then the flags argument will not have the MSG_EOF flag applied. If the message is a complete message then the flags argument will have MSG_EOF set. Locally detected errors are indicated by a return value of -1 with errno set accordingly. The flags argument may also hold the value MSG_NOTIFICATION. When this occurs it indicates that the message received is not from the peer endpoint, but instead is a notification from the SCTP stack (see sctp(4) for more details). Note that no notifi- cations are ever given unless the user subscribes to such notifications using the SCTP_EVENTS socket option. If no messages are available at the socket then sctp_recvmsg() normally blocks on the reception of a message or NOTIFICATION, unless the socket has been placed in non-blocking I/O mode. The select(2) system call may be used to determine when it is possible to receive a message. The sinfo argument is defined as follows. struct sctp_sndrcvinfo { u_int16_t sinfo_stream; // Stream arriving on u_int16_t sinfo_ssn; // Stream Sequence Number u_int16_t sinfo_flags; // Flags on the incoming message u_int32_t sinfo_ppid; // The ppid field u_int32_t sinfo_context; // context field u_int32_t sinfo_timetolive; // not used by sctp_recvmsg u_int32_t sinfo_tsn; // The transport sequence number u_int32_t sinfo_cumtsn; // The cumulative acknowledgment point sctp_assoc_t sinfo_assoc_id; // The association id of the peer }; The sinfo-_sinfo_ppid is an opaque 32 bit value that is passed transpar- ently through the stack from the peer endpoint. Note that the stack passes this value without regard to byte order. The sinfo-_sinfo_flags field may include the following: #define SCTP_UNORDERED 0x0400 // Message is un-ordered The SCTP_UNORDERED flag is used to specify that the message arrived with no specific order and was delivered to the peer application as soon as possible. When this flag is absent the message was delivered in order within the stream it was received. sinfo-_sinfo_stream is the SCTP stream that the message was received on. Streams in SCTP are reliable (or partially reliable) flows of ordered messages. The sinfo-_sinfo_context field is used only if the local application set an association level context with the SCTP_CONTEXT socket option. Optionally a user process can use this value to index some application specific data structure for all data coming from a specific association. The sinfo-_sinfo_ssn will hold the stream sequence number assigned by the peer endpoint if the message is not unordered. For unordered messages this field holds an undefined value. The sinfo-_sinfo_tsn holds a transport sequence number (TSN) that was assigned to this message by the peer endpoint. For messages that fit in or less than the path MTU this will be the only TSN assigned. Note that for messages that span multiple TSNs this value will be one of the TSNs that was used on the message. The sinfo-_sinfo_cumtsn holds the current cumulative acknowledgment point of the transport association. Note that this may be larger or smaller than the TSN assigned to the message itself. The sinfo-_sinfo_assoc_id is the unique association identification that was assigned to the association. For one-to-many (SOCK_SEQPACKET) type sockets this value can be used to send data to the peer without the use of an address field. It is also quite useful in setting various socket options on the specific association (see sctp(4)). The sinfo-_info_timetolive field is not used by sctp_recvmsg. RETURN VALUES The call returns the number of characters sent, or -1 if an error occurred. ERRORS The sctp_recvmsg() system call fails if: [EBADF] An invalid descriptor was specified. [ENOTSOCK] The argument s is not a socket. [EFAULT] An invalid user space address was specified for an argument. [EMSGSIZE] The socket requires that message be sent atomically, and the size of the message to be sent made this impossible. [EAGAIN] The socket is marked non-blocking and the requested operation would block. [ENOBUFS] The system was unable to allocate an internal buffer. The operation may succeed when buffers become avail- able. [ENOBUFS] The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient con- gestion. [EHOSTUNREACH] The remote host was unreachable. [ENOTCON] On a one-to-one style socket no association exists. [ECONNRESET] An abort was received by the stack while the user was attempting to send data to the peer. [ENOENT] On a one to many style socket no address is specified so that the association cannot be located or the SCTP_ABORT flag was specified on a non-existing asso- ciation. [EPIPE] The socket is unable to send anymore data (SBS_CANTSENDMORE has been set on the socket). This typically means that the socket is not connected and is a one-to-one style socket. ---------------------------------------------------------------------------- SCTP_GETADDRLEN NAME sctp_getaddrlen -- return the address length of an address family SYNOPSIS #include #include #include int sctp_getaddrlen(sa_family_t family); DESCRIPTION The sctp_getaddrlen() function returns the size of a specific address family. This function is provided for application binary compatability since it provides the application with the size the operating system thinks the specific address family is. Note that the function will actu- ally create an SCTP socket and then gather the information via a getsockopt() system calls. If for some reason a SCTP socket cannot be created or the getsockopt() call fails, an error will be returned with errno set as specified in the socket() or getsockopt() system call. RETURN VALUES The call returns the number of bytes that the operating system expects for the specific address family or -1. ERRORS The sctp_getaddrlen() function can return the following errors. [EINVAL] The address family specified does NOT exist. ---------------------------------------------------------------------------- SCTP_OPT_INFO NAME sctp_opt_info -- get SCTP socket information SYNOPSIS #include #include #include int sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size); DESCRIPTION The sctp_opt_info() call provides a multi-os compatible method for get- ting specific getsockopt() data where an association identification needs to be passed into the operating system. For FreeBSD a direct getsockopt() may be used, since FreeBSD has the ability to pass informa- tion into the operating system on a getsockopt() call. Other operating systems may not have this ability. For those who wish to write portable code amongst multiple operating systems this call should be used for the following SCTP socket options. SCTP_RTOINFO SCTP_ASSOCINFO SCTP_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR SCTP_STATUS SCTP_GET_PEER_ADDR_INFO SCTP_AUTH_ACTIVE_KEY SCTP_PEER_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS ERRORS The sctp_opt_info() function can return the following errors. [EINVAL] The argument arg value was invalid. [EOPNOTSUPP] The argument opt was not one of the above listed SCTP socket options. [EBADF] The argument s is not a valid descriptor. [ENOTSOCK] The argument s is not a socket. ---------------------------------------------------------------------------- SCTP_GETASSOCID NAME sctp_getassocid -- return an association id for a specified socket address. SYNOPSIS #include #include #include sctp_assoc_t sctp_getassocid(int sd, struct sockaddr *addr); DESCRIPTION The sctp_getassocid() call attempts to look up the specified socket address addr and find the respective association identification. RETURN VALUES The call returns the association id upon success and 0 is returned upon failure. ERRORS The sctp_getassocid() function can return the following errors. [ENOENT] The address does not have an association setup to it. [EBADF] The argument s is not a valid descriptor. [ENOTSOCK] The argument s is not a socket. ----------------------------------------------------------------------------