SCTP编程

本文详细介绍了Stream Control Transmission Protocol (SCTP) 的核心特性及其在网络编程中的应用。包括SCTP的API介绍、实现细节及例外情况,并通过示例展示了如何使用SCTP进行客户端与服务器端的通信。
摘要由CSDN通过智能技术生成

Stream Control Transmission Protocol

Stream Control Transmission Protocol (SCTP) is a reliable transport protocol that provides services similar to the services provided by TCP. In addition, SCTP provides network-level fault tolerance. SCTP supports multihoming at either end of an association. The SCTP socket API supports a one-to-one socket style modeled after TCP. The SCTP socket API also supports a one-to-many socket style designed for use with signaling. The one-to-many socket style reduces the number of file descriptors used in a process. You must link the libsctp library to use SCTP function calls.

An SCTP association is set up between two endpoints. The endpoints use a four-way handshake mechanism that uses a cookie to guard against some types of denial-of-service (DoS) attacks. The endpoints can be represented by multiple IP addresses.

SCTP Stack Implementation

This section lists the details of the Solaris implementation of the IETF standard for the Stream Control Transmission Protocol (RFC 2960) and the Stream Control Transmission Protocol Checksum Change (RFC 3309). The table in this section lists all of the exceptions from RFC 2960. The SCTP protocol in the Solaris operating system fully implements RFC 3309 and any section of RFC 2960 that is not explicitly mentioned in the table.

Table 8–3 Solaris SCTP Implementation Exceptions from RFC 2960

RFC 2960 Section 

Exceptions in the Solaris Implementation 

3. SCTP Packet Format 

3.2 Chunk Field Descriptions: Solaris SCTP does not implement the optional ECNE and CWR. 

3.3.2: Solaris SCTP does not implement the Initiation (INIT) Optional ECN, Host Name Address, and Cookie Preserving parameters. 

3.3.3: Solaris SCTP does not implement the Initiation Acknowledgement, Optional ECN, and Host Name Address parameters. 

5. Association Initialization 

5.1.2, Handle Address Parameters: Section (B), Optional Host Name parameter, is not implemented. 

6. User Data Transfer 

6.8, Adler-32 Checksum Calculation: This section has been rendered obsolete by RFC 3309. 

10. Interface with Upper Layer 

Solaris SCTP implements the IETF TSVWG SCTP socket API draft. 


Note –

The Solaris 10 implementation of the TSVWG SCTP socket API is based on a version of the API draft that was published at the time when Solaris 10 first shipped.


SCTP Socket Interfaces

When the socket() call creates a socket for IPPROTO_SCTP, it calls an SCTP-specific socket creation routine. Socket calls made on an SCTP socket call the appropriate SCTP socket routine automatically. In a one-to-one socket, each socket corresponds to one SCTP association. Create a one-to-one socket by calling this function:

socket(AF_INET[6], SOCK_STREAM, IPPROTO_STCP); 

In a one-to-many style socket, each socket handles multiple SCTP associations. Each association has an association identifier calledsctp_assoc_t. Create a one-to-many socket by calling this function:

socket(AF_INET[6], SOCK_SEQPACKET, IPPROTO_STCP); 

sctp_bindx()

int sctp_bindx(int  sock , void  *addrs , int  addrcnt , int  flags ); 

The sctp_bindx() function manages addresses on an SCTP socket. If the sock parameter is an IPv4 socket, the addresses passed to thesctp_bindx() function must be IPv4 addresses. If the sock parameter is an IPv6 socket, the addresses passed to the sctp_bindx()function can be either IPv4 or IPv6 addresses. When the address that is passed to the sctp_bindx() function is INADDR_ANY orIN6ADDR_ANY, the socket binds to all available addresses. Bind the SCTP endpoint with the bind(3SOCKET)

The value of the *addrs parameter is a pointer to an array of one or more socket addresses. Each address is contained in its appropriate structure. If the addresses are IPv4 addresses, they are contained in either sockaddr_in structures or sockaddr_in6 structures. If the addresses are IPv6 addresses, they are contained in sockaddr_in6 structures. The address type's family distinguishes the address length. The caller specifies the number of addresses in the array with the addrcnt parameter.

The sctp_bindx() function returns 0 on success. The sctp_bindx() function returns -1 on failure and sets the value of errno to the appropriate error code.

If the same port is not given for each socket address, the sctp_bindx() function fails and sets the value of errno to EINVAL.

The flags parameter is formed from performing the bitwise OR operation on zero or more of the following currently defined flags:

  • SCTP_BINDX_ADD_ADDR

  • SCTP_BINDX_REM_ADDR

SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the association. SCTP_BINDX_REM_ADDR directs SCTP to remove the given addresses from the association. The two flags are mutually exclusive. If both are given, the sctp_bindx() fails and sets the value oferrno to EINVAL.

A caller may not remove all addresses from an association. The sctp_bindx() function rejects such an attempt by failing and setting the value of errno to EINVAL. An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate additional addresses with an endpoint after calling the bind() function. An application can use sctp_bindx(SCTP_BINDX_REM_ADDR) to remove addresses associated with a listening socket. After using sctp_bindx(SCTP_BINDX_REM_ADDR) to remove addresses, accepting new associations will not reassociate the removed address. If the endpoint supports dynamic address, using SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDRsends a message to the peer to change the peer's address lists. Adding and removing addresses from a connected association is optional functionality. Implementations that do not support this functionality return EOPNOTSUPP.

If the address family is not AF_INET or AF_INET6, the sctp_bindx() function fails and returns EAFNOSUPPORT. If the file descriptor passed to the sctp_bindx() in the sock parameter is invalid, the sctp_bindx() function fails and returns EBADF.

sctp_opt_info()

int sctp_opt_info(int  sock , sctp_assoc_id_t  id , int  opt , void  *arg , socklen_t  *len ); 

The sctp_opt_info() function returns the SCTP level options that are associated with the socket described in the sock parameter. If the socket is a one-to-many style SCTP socket the value of the id parameter refers to a specific association. The id parameter is ignored for one-to-one style SCTP sockets. The value of the opt parameter specifies the SCTP socket option to get. The value of the arg parameter is an option-specific structure buffer that is allocated by the calling program. The value of the *len parameter is the length of the option.

The opt parameter can take on the following values:

SCTP_RTOINFO

Returns the protocol parameters that are used to initialize and bind the retransmission timeout (RTO) tunable. The protocol parameters use the following structure:

struct sctp_rtoinfo {
    sctp_assoc_t    srto_assoc_id;
    uint32_t        srto_initial;
    uint32_t        srto_max; 
    uint32_t        srto_min;
};
srto_assoc_id

The calling program provides this value, which specifies the association of interest.

srto_initial

This value is the initial RTO value.

srto_max

This value is the maximum RTO value.

srto_min

This value is the minimum RTO value.

SCTP_ASSOCINFO

Returns the association-specific parameters. The parameters use the following structure:

struct sctp_assocparams {
    sctp_assoc_t    sasoc_assoc_id;
    uint16_t        sasoc_asocmaxrxt;
    uint16_t        sasoc_number_peer_destinations;
    uint32_t        sasoc_peer_rwnd;
    uint32_t        sasoc_local_rwnd;
    uint32_t        sasoc_cookie_life;
};
sasoc_assoc_id

The calling program provides this value, which specifies the association of interest.

sasoc_assocmaxrxt

This value specifies the maximum retransmission count for the association.

sasoc_number_peer_destinations

This value specifies the number of addresses that the peer has.

sasoc_peer_rwnd

This value specifies the current value of the peer's receive window.

sasoc_local_rwnd

This value specifies the last reported receive window that the peer transmitted to.

sasoc_cookie_life

The value specifies the lifetime of the association's cookie. The value is used when issuing cookies.

All parameters that use time values are measured in milliseconds.

SCTP_DEFAULT_SEND_PARAM

Returns the default set of parameters that a call to the sendto(3SOCKET) function uses on this association. The parameters use the following structure:

struct sctp_sndrcvinfo {
    uint16_t        sinfo_stream;
    uint16_t        sinfo_ssn;
    uint16_t        sinfo_flags;
    uint32_t        sinfo_ppid;
    uint32_t        sinfo_context;
    uint32_t        sinfo_timetolive;
    uint32_t        sinfo_tsn;
    uint32_t        sinfo_cumtsn;
    sctp_assoc_t    sinfo_assoc_id;
};
sinfo_stream

This value specifies the default stream for the sendmsg() call.

sinfo_ssn

This value is always zero.

sinfo_flags

This value contains the default flags for the sendmsg() call. This flag can take on the following values:

  • MSG_UNORDERED

  • MSG_ADDR_OVER

  • MSG_ABORT

  • MSG_EOF

  • MSG_PR_SCTP

sinfo_ppid

This value is the default payload protocol identifier for the sendmsg() call.

sinfo_context

This value is the default context for the sendmsg() call.

sinfo_timetolive

This value specifies a time period in milliseconds. After this time period has passed, the message expires if its transmission has not begun. A value of zero indicates that the message does not expire. If the MSG_PR_SCTP flag is set, the message expires when its transmission has not successfully completed within the time period specified in sinfo_timetolive.

sinfo_tsn

This value is always zero.

sinfo_cumtsn

This value is always zero.

sinfo_assoc_id

This value is filled in by the calling application. This value specifies the association of interest.

SCTP_PEER_ADDR_PARAMS

Returns the parameters for a specified peer address. The parameters use the following structure:

struct sctp_paddrparams {
    sctp_assoc_t               spp_assoc_id;
    struct sockaddr_storage    spp_address;
    uint32_t                   spp_hbinterval;
    uint16_t                   spp_pathmaxrxt;
};
spp_assoc_id

The calling program provides this value, which specifies the association of interest.

spp_address

This value specifies the peer's address of interest.

spp_hbinterval

This value specifies the heartbeat interval in milliseconds.

spp_pathmaxrxt

This value specifies the maximum number of retransmissions to attempt on an address before considering the address unreachable.

SCTP_STATUS

Returns the current status information about the association. The parameters use the following structure:

struct sctp_status {
    sctp_assoc_t             sstat_assoc_id;
    int32_t                  sstat_state;
    uint32_t                 sstat_rwnd;
    uint16_t                 sstat_unackdata;
    uint16_t                 sstat_penddata;
    uint16_t                 sstat_instrms;
    uint16_t                 sstat_outstrms;
    uint32_t                 sstat_fragmentation_point;
    struct sctp_paddrinfo    sstat_primary;
};
sstat_assoc_id

The calling program provides this value, which specifies the association of interest.

sstat_state

This value is the association's current state. The association can take on the following states:

SCTP_IDLE

The SCTP endpoint does not have any association associated with it. Immediately after the call to the socket()function opens an endpoint, or after the endpoint closes, the endpoint is in this state.

SCTP_BOUND

An SCTP endpoint is bound to one or more local addresses after calling the bind().

SCTP_LISTEN

This endpoint is waiting for an association request from any remote SCTP endpoint.

SCTP_COOKIE_WAIT

This SCTP endpoint has sent an INIT chunk and is waiting for an INIT-ACK chunk.

SCTP_COOKIE_ECHOED

This SCTP endpoint has echoed the cookie that it received from its peer's INIT-ACK chunk back to the peer.

SCTP_ESTABLISHED

This SCTP endpoint can exchange data with its peer.

SCTP_SHUTDOWN_PENDING

This SCTP endpoint has received a SHUTDOWN primitive from its upper layer. This endpoint no longer accepts data from its upper layer.

SCTP_SHUTDOWN_SEND

An SCTP endpoint that was in the SCTP_SHUTDOWN_PENDING state has sent a SHUTDOWN chunk to its peer. The SHUTDOWN chunk is sent only after all outstanding data from this endpoint to its peer is acknowledged. When this endpoint's peer sends a SHUTDOWN ACK chunk, this endpoint sends a SHUTDOWN COMPLETE chunk and the association is considered closed.

SCTP_SHUTDOWN_RECEIVED

An SCTP endpoint has received a SHUTDOWN chunk from its peer. This endpoint no longer accepts new data from its user.

SCTP_SHUTDOWN_ACK_SEND

An SCTP endpoint in the SCTP_SHUTDOWN_RECEIVED state has sent the SHUTDOWN ACK chunk to its peer. The endpoint only sends the SHUTDOWN ACK chunk after the peer acknowledges all outstanding data from this endpoint. When this endpoint's peer sends a SHUTDOWN COMPLETE chunk, the association is closed.

sstat_rwnd

This value is the association peer's current receive window.

sstat_unackdata

This value is the number of unacknowledged DATA chunks.

sstat_penddata

This value is the number of DATA chunks that are awaiting receipt.

sstat_instrms

This value is the number of inbound streams.

sstat_outstrms

This value is the number of outbound streams.

sstat_fragmentation_point

If the combined size of the message, the SCTP headers, and the IP headers exceeds the value ofsstat_fragmentation_point, the message fragments. This value is equal to the Path Maximum Transmission Unit (P-MTU) for the packet's destination address

sstat_primary

This value contains information about the primary peer address. This information uses the following structure:

struct sctp_paddrinfo {
    sctp_assoc_t               spinfo_assoc_id;
    struct sockaddr_storage    spinfo_address;
    int32_t                    spinfo_state;
    uint32_t                   spinfo_cwnd;
    uint32_t                   spinfo_srtt;
    uint32_t                   spinfo_rto;
    uint32_t                   spinfo_mtu;
};
spinfo_assoc_id

The calling program provides this value, which specifies the association of interest.

spinfo_address

This value is the primary peer's address.

spinfo_state

This value can take on either of the two values SCTP_ACTIVE or SCTP_INACTIVE.

spinfo_cwnd

This value is the congestion window of the peer address.

spinfo_srtt

This value is the current smoothed round-trip time calculation for the peer address. This value is expressed in milliseconds.

spinfo_rto

This value is the current retransmission timeout value for the peer address. This value is expressed in milliseconds.

spinfo_mtu

This value is the P-MTU for the peer address.

The sctp_opt_info() function returns 0 on success. The sctp_opt_info() function returns -1 on failure and sets the value of errnoto the appropriate error code. If the file descriptor passed to the sctp_opt_info() in the sock parameter is invalid, the sctp_opt_info()function fails and returns EBADF. If the file descriptor passed to the sctp_opt_info() function in the sock parameter does not describe a socket, the sctp_opt_info() function fails and returns ENOTSOCK. If the association ID is invalid for a one-to-many style SCTP socket, thesctp_opt_info() function fails and sets the value of errno to EINVAL. If the input buffer length is too short for the option specified, thesctp_opt_info() function fails and sets the value of errno to EINVAL. If the address family for the peer's address is not AF_INET orAF_INET6, the sctp_opt_info() function fails and sets the value of errno to EAFNOSUPPORT.

sctp_recvmsg()

ssize_t sctp_recvmsg(int  s , void  *msg , size_t  len , struct sockaddr  *from , socklen_t  *fromlen , struct sctp_sndrcvinfo  *sinfo , int  *msg_flags ); 

The sctp_recvmsg() function enables receipt of a message from the SCTP endpoint specified by the s parameter. The calling program can specify the following attributes:

msg

This parameter is the address of the message buffer.

len

This parameter is the length of the message buffer.

from

This parameter is a pointer to an address that contains the sender's address.

fromlen

This parameter is the size of the buffer associated with the address in the from parameter.

sinfo

This parameter is only active if the calling program enables sctp_data_io_events. To enable sctp_data_io_events, call thesetsockopt() function with the socket option SCTP_EVENTS. When sctp_data_io_events is enabled, the application receives the contents of the sctp_sndrcvinfo structure for each incoming message. This parameter is a pointer to a sctp_sndrcvinfostructure. The structure is populated upon receipt of the message.

msg_flags

This parameter contains any message flags that are present.

The sctp_recvmsg() function returns the number of bytes it receives. The sctp_recvmsg() function returns -1 when an error occurs.

If the file descriptor passed in the s parameter is not valid, the sctp_recvmsg() function fails and sets the value of errno to EBADF. If the file descriptor passed in the s parameter does not describe a socket, the sctp_recvmsg() function fails and sets the value of errno toENOTSOCK. If the msg_flags parameter includes the value MSG_OOB, the sctp_recvmsg() function fails and sets the value of errno toEOPNOTSUPP. If there is no established association, the sctp_recvmsg() function fails and sets the value of errno to ENOTCONN.

sctp_sendmsg()

ssize_t sctp_sendmsg(int  s , 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 ); 

The sctp_sendmsg() function enables advanced SCTP features while sending a message from an SCTP endpoint.

s

This value specifies the SCTP endpoint that is sending the message.

msg

This value contains the message sent by the sctp_sendmsg() function.

len

This value is the length of the message. This value is expressed in bytes.

to

This value is the destination address of the message.

tolen

This value is the length of the destination address.

ppid

This value is the application-specified payload protocol identifier.

stream_no

This value is the target stream for this message.

timetolive

This value is the time period after which the message expires if it has not been successfully sent to the peer. This value is expressed in milliseconds.

context

This value is returned if an error occurs during the sending of the message.

flags

This value is formed from applying the logical operation OR in bitwise fashion on zero or more of the following flag bits:

MSG_UNORDERED

When this flag is set, the sctp_sendmsg() function delivers the message unordered.

MSG_ADDR_OVER

When this flag is set, the sctp_sendmsg() function uses the address in the to parameter instead of the association's primary destination address. This flag is only used with one-to-many style SCTP sockets.

MSG_ABORT

When this flag is set, the specified association aborts by sending an ABORT signal to its peer. This flag is only used with one-to-many style SCTP sockets.

MSG_EOF

When this flag is set, the specified association enters graceful shutdown. This flag is only used with one-to-many style SCTP sockets.

MSG_PR_SCTP

When this flag is set, the message expires when its transmission has not successfully completed within the time period specified in the timetolive parameter.

The sctp_sendmsg() function returns the number of bytes it sent. The sctp_sendmsg() function returns -1 when an error occurs.

If the file descriptor passed in the s parameter is not valid, the sctp_sendmsg() function fails and sets the value of errno to EBADF. If the file descriptor passed in the s parameter does not describe a socket, the sctp_sendmsg() function fails and sets the value of errno toENOTSOCK. If the flags parameter includes the value MSG_OOB, the sctp_sendmsg() function fails and sets the value of errno toEOPNOTSUPP. If the flags parameter includes the values MSG_ABORT or MSG_EOF for a one-to-one style socket, the sctp_sendmsg() function fails and sets the value of errno to EOPNOTSUPP. If there is no established association, the sctp_sendmsg() function fails and sets the value of errno to ENOTCONN. If the socket is shutting down, disallowing further writes, the sctp_sendmsg() function fails and sets the value oferrno to EPIPE. If the socket is nonblocking and the transmit queue is full, the sctp_sendmsg() function fails and sets the value of errnoto EAGAIN.

If the control message length is incorrect, the sctp_sendmsg() function fails and sets the value of errno to EINVAL. If the specified destination address does not belong to the association, the sctp_sendmsg() function fails and sets the value of errno to EINVAL. If the value of stream_no is outside the number of outbound streams that the association supports, the sctp_sendmsg() function fails and sets the value of errno to EINVAL. If the address family of the specified destination address is not AF_INET or AF_INET6, thesctp_sendmsg() function fails and sets the value of errno to EINVAL.

sctp_send()

ssize_t sctp_send(int  s , const void  *msg , size_t  len , const struct sctp_sndrcvinfo  *sinfo , int  flags ); 

The sctp_send() function is usable by one-to-one and one-to-many style sockets. The sctp_send() function enables advanced SCTP features while sending a message from an SCTP endpoint.

s

This value specifies the socket created by the socket() function.

msg

This value contains the message sent by the sctp_send() function.

len

This value is the length of the message. This value is expressed in bytes.

sinfo

This value contains the parameters used to send the message. For a one-to-many style socket, this value can contain the association ID to which the message is being sent.

flags

This value is identical to the flags parameter in the sendmsg() function.

The sctp_send() function returns the number of bytes it sent. The sctp_send() function returns -1 when an error occurs.

If the file descriptor passed in the s parameter is not valid, the sctp_send() function fails and sets the value of errno to EBADF. If the file descriptor passed in the s parameter does not describe a socket, the sctp_send() function fails and sets the value of errno to ENOTSOCK. If the sinfo_flags field of the sinfo parameter includes the value MSG_OOB, the sctp_send() function fails and sets the value of errno toEOPNOTSUPP. If the sinfo_flags field of the sinfo parameter includes the values MSG_ABORT or MSG_EOF for a one-to-one style socket, thesctp_send() function fails and sets the value of errno to EOPNOTSUPP. If there is no established association, the sctp_send() function fails and sets the value of errno to ENOTCONN. If the socket is shutting down, disallowing further writes, the sctp_send() function fails and sets the value of errno to EPIPE. If the socket is nonblocking and the transmit queue is full, the sctp_send() function fails and sets the value of errno to EAGAIN.

If the control message length is incorrect, the sctp_send() function fails and sets the value of errno to EINVAL. If the specified destination address does not belong to the association, the sctp_send() function fails and sets the value of errno to EINVAL. If the value of stream_nois outside the number of outbound streams that the association supports, the sctp_send() function fails and sets the value of errno toEINVAL. If the address family of the specified destination address is not AF_INET or AF_INET6, the sctp_send() function fails and sets the value of errno to EINVAL.

Branched-off Association

Applications can branch an established association on a one-to-many style socket into a separate socket and file descriptor. A separate socket and file descriptor is useful for applications that have a number of sporadic message senders or receivers that need to remain under the original one-to-many style socket. The application branches off associations that carry high volume data traffic into separate socket descriptors. The application uses the sctp_peeloff() call to branch off an association into a separate socket. The new socket is a one-to-one style socket. The syntax for the sctp_peeloff() function is as follows:

int sctp_peeloff(int  sock , sctp_assoc_t  id ); 
sock

The original one-to-many style socket descriptor returned from the socket() system call

id

The identifier of the association to branch off to a separate file descriptor

The sctp_peeloff() function fails and returns EOPTNOTSUPP if the socket descriptor passed in the sock parameter is not a one-to-many style SCTP socket. The sctp_peeloff() function fails and returns EINVAL if the value of id is zero or if the value of id is greater than the maximum number of associations for the socket descriptor passed in the sock parameter. The sctp_peeloff() function fails and returns EMFILE if the function fails to create a new user file descriptor or file structure.

sctp_getpaddrs()

The sctp_getpaddrs() function returns all peer addresses in an association.

int sctp_getpaddrs(int  sock , sctp_assoc_t  id , void  **addrs ); 

When the sctp_getpaddrs() function returns successfully, the value of the **addrs parameter points to a dynamically allocated packed array of sockaddr structures of the appropriate type for each address. The calling thread frees the memory with the sctp_freepaddrs()function. The **addrs parameter cannot have a value of NULL. If the socket descriptor given in sock is for an IPv4 socket, thesctp_getpaddrs() function returns IPv4 addresses. If the socket descriptor given in sock is for an IPv6 socket, the sctp_getpaddrs()function returns a mix of IPv4 and IPv6 addresses. For one-to-many style sockets, the id parameter specifies the association to query. Thesctp_getpaddrs() function ignores the id parameter for one-to-one style sockets. When the sctp_getpaddrs() function returns successfully, it returns the number of peer addresses in the association. If there is no association on this socket, the sctp_getpaddrs()function returns 0 and the value of the **addrs parameter is undefined. If an error occurs, the sctp_getpaddrs() function returns -1 and the value of the **addrs parameter is undefined.

If the file descriptor passed to the sctp_getpaddrs() function in the sock parameter is invalid, the sctp_getpaddrs() function fails and returns EBADF. If the file descriptor passed to the sctp_getpaddrs() function in the sock parameter does not describe a socket, thesctp_getpaddrs() function fails and returns ENOTSOCK. If the file descriptor passed to the sctp_getpaddrs() function in the sockparameter describes a socket that is not connected, the sctp_getpaddrs() function fails and returns ENOTCONN.

sctp_freepaddrs()

The sctp_freepaddrs() function frees all of the resources that were allocated by a previous call to the sctp_getpaddrs(). The syntax for the sctp_freepaddrs() function is as follows:

void sctp_freepaddrs(void  *addrs ); 

The *addrs parameter is an array that contains the peer addresses that are returned by the sctp_getpaddrs() function.

sctp_getladdrs()

The sctp_getladdrs() function returns all locally bound addresses on a socket. The syntax for the sctp_getladdrs() function is as follows:

int sctp_getladdrs(int  sock , sctp_assoc_t  id , void  **addrs ); 

When the sctp_getladdrs() function returns successfully, the value of addrs points to a dynamically allocated packed array of sockaddrstructures. The sockaddr structures are of the appropriate type for each local address. The calling application uses the sctp_freeladdrs()function to free the memory. The value of the addrs parameter must not be NULL.

If the socket referenced by the sd parameter is an IPv4 socket, the sctp_getladdrs() function returns IPv4 addresses. If the socket referenced by the sd parameter is an IPv6 socket, the sctp_getladdrs() function returns a mix of IPv4 or IPv6 addresses as appropriate.

When the sctp_getladdrs() function is invoked for a one-to-many style socket, the value of the id parameter specifies the association to query. The sctp_getladdrs() function ignores the id parameter when the function is operating on a one-to-one socket.

When the value of the id parameter is zero, the sctp_getladdrs() function returns locally bound addresses without regard to any particular association. When the sctp_getladdrs() function returns successfully, it reports the number of local addresses bound to the socket. If the socket is unbound, the sctp_getladdrs() function returns 0 and the value of *addrs is undefined. If an error occurs, thesctp_getladdrs() function returns -1 and the value of *addrs is undefined.

sctp_freeladdrs()

The sctp_freeladdrs() function frees all of the resources that were allocated by a previous call to the sctp_getladdrs(). The syntax for the sctp_freeladdrs() function is as follows:

void sctp_freeladdrs(void  *addrs ); 

The *addrs parameter is an array that contains the peer addresses that are returned by the sctp_getladdrs() function.

Code Examples of SCTP Use

This section details two uses of SCTP sockets.


Example 8–17 SCTP Echo Client

/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/* To enable socket features used for SCTP socket. */
#define _XPG4_2
#define __EXTENSIONS__

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <netinet/sctp.h>
#include <netdb.h>

#define BUFLEN 1024

static void
usage(char *a0)
{
    fprintf(stderr, "Usage: %s <addr>\n", a0);
}

/*
 * Read from the network.
 */
static void
readit(void *vfdp)
{
    int   fd;
    ssize_t   n;
    char   buf[BUFLEN];
    struct msghdr  msg[1];
    struct iovec  iov[1];
    struct cmsghdr  *cmsg;
    struct sctp_sndrcvinfo *sri;
    char   cbuf[sizeof (*cmsg) + sizeof (*sri)];
    union sctp_notification *snp;

    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

    fd = *(int *)vfdp;

    /* Initialize the message header for receiving */
    memset(msg, 0, sizeof (*msg));
    msg->msg_control = cbuf;
    msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri);
    msg->msg_flags = 0;
    cmsg = (struct cmsghdr *)cbuf;
    sri = (struct sctp_sndrcvinfo *)(cmsg + 1);
    iov->iov_base = buf;
    iov->iov_len = BUFLEN;
    msg->msg_iov = iov;
    msg->msg_iovlen = 1;

    while ((n = recvmsg(fd, msg, 0)) > 0) {
        /* Intercept notifications here */
        if (msg->msg_flags & MSG_NOTIFICATION) {
            snp = (union sctp_notification *)buf;
            printf("[ Receive notification type %u ]\n",
                snp->sn_type);
            continue;
        }
        msg->msg_control = cbuf;
        msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri);
        printf("[ Receive echo (%u bytes): stream = %hu, ssn = %hu, "
            "flags = %hx, ppid = %u ]\n", n,
            sri->sinfo_stream, sri->sinfo_ssn, sri->sinfo_flags,
            sri->sinfo_ppid);
    }

    if (n < 0) {
        perror("recv");
        exit(1);
    }

    close(fd);
    exit(0);
}

#define MAX_STREAM 64

static void
echo(struct sockaddr_in *addr)
{
    int     fd;
    uchar_t     buf[BUFLEN];
    ssize_t    n;
    int    perr;
    pthread_t   tid;
    struct cmsghdr   *cmsg;
    struct sctp_sndrcvinfo  *sri;
    char    cbuf[sizeof (*cmsg) + sizeof (*sri)];
    struct msghdr   msg[1];
    struct iovec   iov[1];
    int    ret;
    struct sctp_initmsg   initmsg;
    struct sctp_event_subscribe events;

    /* Create a one-one SCTP socket */
    if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
        perror("socket");
        exit(1);
    }

    /*
     * We are interested in association change events and we want
     * to get sctp_sndrcvinfo in each receive.
     */
    events.sctp_association_event = 1; 
    events.sctp_data_io_event = 1; 
    ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &events,
        sizeof (events));
    if (ret < 0) {
        perror("setsockopt SCTP_EVENTS");
        exit(1);
    }

    /*
     * Set the SCTP stream parameters to tell the other side when
     * setting up the association.
     */
    memset(&initmsg, 0, sizeof(struct sctp_initmsg));
    initmsg.sinit_num_ostreams = MAX_STREAM;
    initmsg.sinit_max_instreams = MAX_STREAM;
    initmsg.sinit_max_attempts = MAX_STREAM;
    ret = setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
        sizeof(struct sctp_initmsg));
    if (ret < 0) {
        perror("setsockopt SCTP_INITMSG");
        exit(1);
    }

    if (connect(fd, (struct sockaddr *)addr, sizeof (*addr)) == -1) {
        perror("connect");
        exit(1);
    }

    /* Initialize the message header structure for sending. */
    memset(msg, 0, sizeof (*msg));
    iov->iov_base = buf;
    msg->msg_iov = iov;
    msg->msg_iovlen = 1;
    msg->msg_control = cbuf;
    msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri);
    msg->msg_flags |= MSG_XPG4_2;

    memset(cbuf, 0, sizeof (*cmsg) + sizeof (*sri));
    cmsg = (struct cmsghdr *)cbuf;
    sri = (struct sctp_sndrcvinfo *)(cmsg + 1);

    cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*sri);
    cmsg->cmsg_level = IPPROTO_SCTP;
    cmsg->cmsg_type  = SCTP_SNDRCV;

    sri->sinfo_ppid   = 1;
    /* Start sending to stream 0. */
    sri->sinfo_stream = 0;

    /* Create a thread to receive network traffic. */
    perr = pthread_create(&tid, NULL, (void *(*)(void *))readit, &fd);

    if (perr != 0) {
        fprintf(stderr, "pthread_create: %d\n", perr);
        exit(1);
    }

    /* Read from stdin and then send to the echo server. */
    while ((n = read(fileno(stdin), buf, BUFLEN)) > 0) {
        iov->iov_len = n;
        if (sendmsg(fd, msg, 0) < 0) {
            perror("sendmsg");
            exit(1);
        }
        /* Send the next message to a different stream. */
        sri->sinfo_stream = (sri->sinfo_stream + 1) % MAX_STREAM;
    }

    pthread_cancel(tid);
    close(fd);
}

int
main(int argc, char **argv)
{
    struct sockaddr_in addr[1];
    struct hostent *hp;
    int error;

    if (argc < 2) {
        usage(*argv);
        exit(1);
    }

    /* Find the host to connect to. */ 
    hp = getipnodebyname(argv[1], AF_INET, AI_DEFAULT, &error);
    if (hp == NULL) {
        fprintf(stderr, "host not found\n");
        exit(1);
    }

    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = *(ipaddr_t *)hp->h_addr_list[0];
    addr->sin_port = htons(5000);

    echo(addr);

    return (0);
}


Example 8–18 SCTP Echo Server

/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/* To enable socket features used for SCTP socket. */
#define _XPG4_2
#define __EXTENSIONS__

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/sctp.h>

#define BUFLEN 1024

/*
 * Given an event notification, print out what it is.
 */
static void
handle_event(void *buf)
{
    struct sctp_assoc_change *sac;
    struct sctp_send_failed  *ssf;
    struct sctp_paddr_change *spc;
    struct sctp_remote_error *sre;
    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("^^^ assoc_change: state=%hu, error=%hu, instr=%hu "
            "outstr=%hu\n", sac->sac_state, sac->sac_error,
            sac->sac_inbound_streams, sac->sac_outbound_streams);
        break;
    case SCTP_SEND_FAILED:
        ssf = &snp->sn_send_failed;
        printf("^^^ sendfailed: len=%hu err=%d\n", ssf->ssf_length,
            ssf->ssf_error);
        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 {
            sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
            ap = inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf,
                INET6_ADDRSTRLEN);
        }
        printf("^^^ intf_change: %s state=%d, error=%d\n", ap,
            spc->spc_state, spc->spc_error);
        break;
    case SCTP_REMOTE_ERROR:
        sre = &snp->sn_remote_error;
        printf("^^^ remote_error: err=%hu len=%hu\n",
            ntohs(sre->sre_error), ntohs(sre->sre_length));
        break;
    case SCTP_SHUTDOWN_EVENT:
        printf("^^^ shutdown event\n");
        break;
    default:
        printf("unknown type: %hu\n", snp->sn_header.sn_type);
        break;
    }
}

/*
 * Receive a message from the network.
 */
static void *
getmsg(int fd, struct msghdr *msg, void *buf, size_t *buflen,
    ssize_t *nrp, size_t cmsglen)
{
    ssize_t  nr = 0;
    struct iovec iov[1];

    *nrp = 0;
    iov->iov_base = buf;
    msg->msg_iov = iov;
    msg->msg_iovlen = 1;

    /* Loop until a whole message is received. */
    for (;;) {
        msg->msg_flags = MSG_XPG4_2;
        msg->msg_iov->iov_len = *buflen;
        msg->msg_controllen = cmsglen;

        nr += recvmsg(fd, msg, 0);
        if (nr <= 0) {
            /* EOF or error */
            *nrp = nr;
            return (NULL);
        }

        /* Whole message is received, return it. */
        if (msg->msg_flags & MSG_EOR) {
            *nrp = nr;
            return (buf);
        }

        /* Maybe we need a bigger buffer, do realloc(). */
        if (*buflen == nr) {
            buf = realloc(buf, *buflen * 2);
            if (buf == 0) {
                fprintf(stderr, "out of memory\n");
                exit(1);
            }
            *buflen *= 2;
        }

        /* Set the next read offset */
        iov->iov_base = (char *)buf + nr;
        iov->iov_len = *buflen - nr;

    }
}

/*
 * The echo server.
 */
static void
echo(int fd)
{
    ssize_t   nr;
    struct sctp_sndrcvinfo *sri;
    struct msghdr  msg[1];
    struct cmsghdr  *cmsg;
    char   cbuf[sizeof (*cmsg) + sizeof (*sri)];
    char   *buf;
    size_t   buflen;
    struct iovec  iov[1];
    size_t   cmsglen = sizeof (*cmsg) + sizeof (*sri);

    /* Allocate the initial data buffer */
    buflen = BUFLEN;
    if ((buf = malloc(BUFLEN)) == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(1);
    }

    /* Set up the msghdr structure for receiving */
    memset(msg, 0, sizeof (*msg));
    msg->msg_control = cbuf;
    msg->msg_controllen = cmsglen;
    msg->msg_flags = 0;
    cmsg = (struct cmsghdr *)cbuf;
    sri = (struct sctp_sndrcvinfo *)(cmsg + 1);

    /* Wait for something to echo */
    while ((buf = getmsg(fd, msg, buf, &buflen, &nr, cmsglen)) != NULL) {

        /* Intercept notifications here */
        if (msg->msg_flags & MSG_NOTIFICATION) {
            handle_event(buf);
            continue;
        }

        iov->iov_base = buf;
        msg->msg_iov = iov;
        msg->msg_iovlen = 1;
        iov->iov_len = nr;
        msg->msg_control = cbuf;
        msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri);

        printf("got %u bytes on stream %hu:\n", nr,
               sri->sinfo_stream);
        write(0, buf, nr);

        /* Echo it back */
        msg->msg_flags = MSG_XPG4_2;
        if (sendmsg(fd, msg, 0) < 0) {
            perror("sendmsg");
            exit(1);
        }
    }

    if (nr < 0) {
        perror("recvmsg");
    }
    close(fd);
}

int
main(void)
{
    int    lfd;
    int    cfd;
    int    onoff = 1;
    struct sockaddr_in  sin[1];
    struct sctp_event_subscribe events;
    struct sctp_initmsg  initmsg;

    if ((lfd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
        perror("socket");
        exit(1);
    }

    sin->sin_family = AF_INET;
    sin->sin_port = htons(5000);
    sin->sin_addr.s_addr = INADDR_ANY;
    if (bind(lfd, (struct sockaddr *)sin, sizeof (*sin)) == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(lfd, 1) == -1) {
        perror("listen");
        exit(1);
    }

    (void) memset(&initmsg, 0, sizeof(struct sctp_initmsg));
    initmsg.sinit_num_ostreams = 64;
    initmsg.sinit_max_instreams = 64;
    initmsg.sinit_max_attempts = 64;
    if (setsockopt(lfd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
           sizeof(struct sctp_initmsg)) < 0) { 
        perror("SCTP_INITMSG");
        exit (1);
    }

    /* Events to be notified for */
    (void) memset(&events, 0, sizeof (events));
    events.sctp_data_io_event = 1;
    events.sctp_association_event = 1;
    events.sctp_send_failure_event = 1;
    events.sctp_address_event = 1;
    events.sctp_peer_error_event = 1;
    events.sctp_shutdown_event = 1;

    /* Wait for new associations */
    for (;;) {
        if ((cfd = accept(lfd, NULL, 0)) == -1) {
            perror("accept");
            exit(1);
        }

        /* Enable ancillary data */
        if (setsockopt(cfd, IPPROTO_SCTP, SCTP_EVENTS, &events,
               sizeof (events)) < 0) {
            perror("setsockopt SCTP_EVENTS");
            exit(1);
        }
        /* Echo back any and all data */
        echo(cfd);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值