ストリーム制御伝送プロトコル (SCTP) は、TCP が提供するサービスと同様のサービスを提供する信頼性の高いトランスポートプロトコルです。さらに、SCTP はネットワークレベルの耐障害性を提供します。SCTP では、関連付けの両端でマルチホーミングがサポートされます。SCTP ソケット API は、TCP にならった 1 対 1 ソケットスタイルをサポートします。その他に SCTP ソケット API は、シグナリングで使用するために設計された 1 対多ソケットスタイルもサポートします。1 対多ソケットスタイルは、プロセスで使用されるファイル記述子の数を削減します。SCTP 関数の呼び出しを使用するには、libsctp ライブラリをリンクする必要があります。
SCTP 関連付けは 2 つの終端の間で設定します。各終端は、特定のタイプのサービス拒否 (DoS) 攻撃から保護するために、cookie による 4 ウェイハンドシェークを使用します。複数の IP アドレスによって終端を表現できます。
この節では、IETF 勧告の Stream Control Transmission Protocol (RFC 2960) および Stream Control Transmission Protocol Checksum Change (RFC 3309) について、Solaris における実装の詳細を表に示します。ここでは、RFC 2960 勧告の実装例外について次の表に示します。Solaris オペレーティングシステムの SCTP プロトコルは、RFC 3309 のすべてと、RFC 2960 のセクションのうちこの表に明記されていないセクションのすべてを実装しています。
表 8–3 RFC 2960 との比較における Solaris SCTP 実装の例外
RFC 2960 のセクション |
Solaris 実装における例外 |
---|---|
3. SCTP Packet Format |
3.2 Chunk Field Descriptions: Solaris SCTP は、省略可能な ECNE および CWR を実装していません。 3.3.2: Solaris SCTP は、Initiation (INIT) の Optional ECN、Host Name Address、および Cookie Preserving パラメータを実装していません。 3.3.3: Solaris SCTP は、Initiation Acknowledgement、Optional ECN、および Host Name Address パラメータを実装していません。 |
5. Association Initialization |
5.1.2, Handle Address Parameters: セクション (B) の Optional Host Name は実装されていません。 |
6. User Data Transfer |
6.8, Adler-32 Checksum Calculation: RFC 3309 によって、このセクションは廃止されています。 |
10. Interface with Upper Layer |
Solaris SCTP は、IETF TSVWG SCTP ソケット API ドラフトを実装しています。 |
TSVWG SCTP ソケット API の Solaris 10 実装は、Solaris 10 が最初に出荷されたときに公開されていた API ドラフトのバージョンに基づいています。
socket() 呼び出しは、IPPROTO_SCTP のソケットを作成するとき、SCTP 固有のソケット作成ルーチンを呼び出します。SCTP ソケットでソケットを呼び出すと、自動的に適切な SCTP ソケットルーチンが呼び出されます。1 対 1 ソケットの場合、各ソケットは 1 つの SCTP 関連付けに対応します。1 対 1 ソケットを作成するには、次の関数を呼び出します。
socket(AF_INET[6], SOCK_STREAM, IPPROTO_STCP);1 対多スタイルソケットの場合、各ソケットは複数の SCTP 関連付けを処理します。各関連付けには、sctp_assoc_t と呼ばれる関連付け識別子があります。1 対多ソケットを作成するには、次の関数を呼び出します。
socket(AF_INET[6], SOCK_SEQPACKET, IPPROTO_STCP);sctp_bindx() 関数は、SCTP ソケット上のアドレスを管理します。sock パラメータが IPv4 ソケットである場合、sctp_bindx() 関数に渡されるアドレスは IPv4 アドレスである必要があります。sock パラメータが IPv6 ソケットである場合、sctp_bindx() 関数に渡されるアドレスは IPv4 アドレスまたは IPv6 アドレスのどちらかになります。sctp_bindx() 関数に渡されるアドレスが INADDR_ANY または IN6ADDR_ANY であると、ソケットは使用可能なすべてのアドレスにバインドします。bind(3SOCKET) を使用して SCTP 終端をバインドします。
*addrs パラメータの値は、1 つ以上のソケットアドレスの配列へのポインタです。各アドレスは、それぞれ該当する構造体に含まれます。アドレスが IPv4 アドレスである場合、sockaddr_in 構造体または sockaddr_in6 構造体に含まれます。IPv6 アドレスである場合、sockaddr_in6 構造体に含まれます。アドレスタイプ群によって、アドレス長が異なります。呼び出し元は、配列内のアドレスの数を addrcnt パラメータによって指定します。
sctp_bindx() 関数は成功すると 0 を返します。失敗すると、sctp_bindx() 関数は -1 を返し、errno の値を該当するエラーコードに設定します。
各ソケットアドレスに同じポートが指定されていない場合、sctp_bindx() 関数は失敗し、errno の値を EINVAL に設定します。
flags パラメータは、現在定義されている次のフラグの 0 以上に対してビット単位の論理和演算を実行することによって求められます。
SCTP_BINDX_ADD_ADDR
SCTP_BINDX_REM_ADDR
SCTP_BINDX_ADD_ADDR は、指定されたアドレスを関連付けに追加するように SCTP に指示します。SCTP_BINDX_REM_ADDR は、指定されたアドレスを関連付けから削除するように SCTP に指示します。この 2 つのフラグは相互に排他です。両方が指定された場合、sctp_bindx() は失敗して errno の値を EINVAL に設定します。
呼び出し元は、関連付けからすべてのアドレスを削除することはできません。このような試みは拒否され、sctp_bindx() 関数は失敗して errno の値が EINVAL に設定されます。アプリケーションは、bind() 関数を呼び出したあとに sctp_bindx(SCTP_BINDX_ADD_ADDR) を使用することにより、追加のアドレスを終端に関連付けることができます。またアプリケーションは、sctp_bindx(SCTP_BINDX_REM_ADDR) を使用することにより、待機しているソケットに関連付けられているアドレスを削除できます。アドレスを削除するために sctp_bindx(SCTP_BINDX_REM_ADDR) を使用したあとは、新しい関連付けを受け入れても、削除されたアドレスは再び関連付けられません。終端が動的アドレスをサポートする場合、SCTP_BINDX_REM_ADDR または SCTP_BINDX_ADD_ADDR を使用すると、ピアにメッセージが送信されてピアのアドレスリストが変更されます。接続されている関連付けにおけるアドレスの追加および削除は、オプションの機能です。この機能をサポートしない実装では、EOPNOTSUPP が返されます。
アドレス群が AF_INET または AF_INET6 ではない場合、sctp_bindx() 関数は失敗して EAFNOSUPPORT を返します。sctp_bindx() に渡される sock パラメータのファイル記述子が無効である場合、sctp_bindx() 関数は失敗して EBADF を返します。
sctp_opt_info() 関数は、sock パラメータに記述されるソケットに関連付けられている SCTP レベルのオプションを返します。1 対多スタイルの SCTP ソケットの場合、id パラメータの値は特定の関連付けを指します。1 対 1 スタイルの SCTP ソケットの場合、id パラメータは無視されます。opt パラメータの値は、取得する SCTP ソケットオプションを指定します。arg パラメータの値は、呼び出し元プログラムによって割り当てられるオプション固有の構造体バッファーです。*len パラメータの値は、オプションの長さです。
opt パラメータは、次の値を取ることができます。
調整可能な再伝送タイムアウト(RTO) を初期化および設定するために使用されるプロトコルのパラメータを返します。プロトコルのパラメータは次の構造体を使用します。
struct sctp_rtoinfo { sctp_assoc_t srto_assoc_id; uint32_t srto_initial; uint32_t srto_max; uint32_t srto_min; };
対象になる関連付けを指定するこの値は、呼び出し元プログラムが提供します。
この値は初期 RTO 値です。
この値は最大 RTO 値です。
この値は最小 RTO 値です。
関連付け固有のパラメータを返します。パラメータは次の構造体を使用します。
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; };
対象になる関連付けを指定するこの値は、呼び出し元プログラムが提供します。
この値は、関連付けに対する再伝送の最大数を指定します。
この値は、ピアが持つアドレスの数を指定します。
この値は、ピアの受信ウィンドウの現在値を指定します。
この値は、ピアの送信先の、最後に報告された受信ウィンドウを指定します。
この値は、関連付けの cookie の存続時間を指定し、cookie を発行する際に使用されます。
時間の値を使用するすべてのパラメータはミリ秒単位です。
sendto(3SOCKET) 関数の呼び出しが関連付けに関して使用するパラメータのデフォルトセットを返します。パラメータは次の構造体を使用します。
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; };
この値は、sendmsg() 呼び出しのデフォルトストリームを指定します。
この値は常に 0 です。
この値は、sendmsg() 呼び出しのデフォルトフラグです。フラグは次の値を取ることができます。
MSG_UNORDERED
MSG_ADDR_OVER
MSG_ABORT
MSG_EOF
MSG_PR_SCTP
この値は、sendmsg() 呼び出しのデフォルトのペイロードプロトコル識別子です。
この値は、sendmsg() 呼び出しのデフォルトコンテキストです。
この値は、ミリ秒単位で期間を指定します。この期間を経過すると、伝送が開始されていないメッセージは期限切れになります。値が 0 の場合は、メッセージが期限切れにならないことを示します。MSG_PR_SCTP フラグが設定されている場合、sinfo_timetolive に指定された期間内に伝送が正常に完了しないメッセージは期限切れになります。
この値は常に 0 です。
この値は常に 0 です。
この値は、呼び出し元アプリケーションによって設定され、対象になる関連付けを指定します。
指定されたピアのアドレスのパラメータを返します。パラメータは次の構造体を使用します。
struct sctp_paddrparams { sctp_assoc_t spp_assoc_id; struct sockaddr_storage spp_address; uint32_t spp_hbinterval; uint16_t spp_pathmaxrxt; };
対象になる関連付けを指定するこの値は、呼び出し元プログラムが提供します。
この値は、対象になるピアのアドレスを指定します。
この値は、ミリ秒単位でハートビート間隔を指定します。
この値は、あるアドレスを到達不能と見なすまでの、再伝送を試みる最大回数を指定します。
関連付けに関する現在の状態情報を返します。パラメータは次の構造体を使用します。
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; };
対象になる関連付けを指定するこの値は、呼び出し元プログラムが提供します。
この値は、関連付けの現在の状態を示し、関連付けは次の状態を取ることができます。
SCTP 終端がいずれの関連付けとも関連付けられていません。socket() 関数が終端を開いた直後、または、終端が閉じられた直後、終端はこの状態になります。
bind() の呼び出しのあと、SCTP 終端が 1 つ以上のローカルアドレスにバインドされています。
リモート SCTP 終端からの関連付け要求を終端が待機しています。
SCTP 終端が INIT チャンクを送信し、INIT-ACK チャンクを待機しています。
SCTP 終端が、ピアの INIT-ACK チャンクから受信した cookie をピアにエコーバックしました。
SCTP 終端はピアとデータを交換できます。
SCTP 終端が上位層から SHUTDOWN プリミティブを受信しました。この終端は上位層からデータを受け入れません。
SCTP_SHUTDOWN_PENDING 状態にあった SCTP 終端が SHUTDOWN チャンクをピアに送信しました。SHUTDOWN チャンクが送信されるのは、終端からピアへの未処理データがすべて確認されたあとだけです。終端のピアが SHUTDOWN ACK チャンクを送信すると、終端は SHUTDOWN COMPLETE チャンクを送信し、関連付けが閉じられたと見なされます。
SCTP 終端がピアから SHUTDOWN チャンクを受信しました。この終端はそのユーザーから新しいデータを受け入れません。
SCTP_SHUTDOWN_RECEIVED 状態の SCTP 終端がピアに SHUTDOWN ACK チャンクを送信しました。終端が SHUTDOWN ACK チャンクを送信するのは、その終端からのすべての未処理データをピアが確認したあとだけです。終端のピアが SHUTDOWN COMPLETE チャンクを送信すると、関連付けは閉じられます。
この値は、関連付けピアの現在の受信ウィンドウです。
この値は、未確認 DATA チャンクの数です。
この値は、受信を待機している DATA チャンクの数です。
この値は、着信ストリームの数です。
この値は、発信ストリームの数です。
メッセージ、SCTP ヘッダー、および IP ヘッダーを含めたサイズが sstat_fragmentation_point の値を超える場合、メッセージは分割されます。この値は、パケットの着信先アドレスのパス最大伝送ユニット (P-MTU) と同じです。
この値は、プライマリピアのアドレスに関する情報です。この情報は次の構造体を使用します。
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; };
対象になる関連付けを指定するこの値は、呼び出し元プログラムが提供します。
この値は、プライマリピアのアドレスです。
この値は、SCTP_ACTIVE または SCTP_INACTIVE の 2 つの値のいずれかを取ります。
この値は、ピアアドレスの輻輳ウィンドウです。
この値は、ピアアドレスに関する現在の平滑化された RTT の計算値です。ミリ秒単位で示されます。
この値は、ピアアドレスに関する現在の伝送タイムアウト値です。ミリ秒単位で示されます。
この値は、ピアアドレスに関する P-MTU です。
sctp_opt_info() 関数は成功すると 0 を返します。失敗すると、sctp_opt_info() 関数は -1 を返し、errno の値を該当するエラーコードに設定します。sctp_opt_info() に渡される sock パラメータのファイル記述子が無効である場合、sctp_opt_info() 関数は失敗して EBADF を返します。sctp_opt_info() 関数に渡される sock パラメータのファイル記述子がソケットではない場合、sctp_opt_info() 関数は失敗して ENOTSOCK を返します。関連付け ID が 1 対多スタイル SCTP ソケットに対して無効である場合、sctp_opt_info() 関数は失敗して errno の値を EINVAL に設定します。指定されたオプションに対して入力バッファー長が短すぎる場合、sctp_opt_info() 関数は失敗して errno の値を EINVAL に設定します。ピアのアドレスのアドレス群が AF_INET または AF_INET6 ではない場合、sctp_opt_info() 関数は失敗して errno の値を EAFNOSUPPORT に設定します。
sctp_recvmsg() 関数は、s パラメータによって指定される SCTP 終端からのメッセージの受信を有効にします。呼び出し元プログラムによって次の属性を指定できます。
このパラメータは、メッセージバッファーのアドレスです。
このパラメータは、メッセージバッファーの長さです。
このパラメータは、送信元のアドレスを含むアドレスへのポインタです。
from パラメータのアドレスに関連付けられたバッファーのサイズです。
このパラメータは、呼び出し元プログラムで sctp_data_io_events が有効な場合のみ有効です。sctp_data_io_events を有効にするには、ソケットオプション SCTP_EVENTS() によって setsockopt 関数を呼び出します。sctp_data_io_events が有効である場合、アプリケーションは着信メッセージごとに sctp_sndrcvinfo 構造体の内容を受信します。このパラメータは、sctp_sndrcvinfo 構造体へのポインタです。構造体はメッセージの受信時にデータを取り込みます。
このパラメータは、存在するメッセージフラグを含みます。
sctp_recvmsg() 関数は、受信するバイト数を返します。エラーが発生した場合、sctp_recvmsg() 関数は -1 を返します。
s パラメータの渡されたファイル記述子が有効でない場合、sctp_recvmsg() 関数は失敗して errno の値を EBADF に設定します。s パラメータに渡されたファイル記述子がソケットでない場合、sctp_recvmsg() 関数は失敗して errno の値を ENOTSOCK に設定します。msg_flags パラメータに値 MSG_OOB が含まれる場合、sctp_recvmsg() 関数は失敗して errno の値を EOPNOTSUPP に設定します。関連付けが確立していない場合、sctp_recvmsg() 関数は失敗して errno の値を ENOTCONN に設定します。
sctp_sendmsg() 関数は、SCTP 終端からメッセージを送信する際の拡張 SCTP 機能を有効にします。
この値は、メッセージを送信する SCTP 終端を指定します。
この値は、sctp_sendmsg() 関数によって送信されるメッセージです。
この値は、メッセージの長さで、バイト単位で表されます。
この値は、メッセージの着信先アドレスです。
この値は、着信先アドレスの長さです。
この値は、アプリケーション固有のペイロードプロトコル識別子です。
この値は、メッセージのターゲットストリームです。
この値は、メッセージが正常にピアに送信されなかった場合に期限切れになるまでの期間で、ミリ秒単位で示されます。
メッセージの送信時にエラーが発生した場合に、この値が返されます。
この値は、0 以上の次のフラグビットに対するビット単位の論理和演算を実行することによって求められます。
このフラグが設定されている場合 sctp_sendmsg() 関数はメッセージを順不同で配信します。
このフラグが設定されている場合、sctp_sendmsg() 関数は関連付けのプライマリ着信先アドレスではなく、to パラメータのアドレスを使用します。このフラグは 1 対多スタイル SCTP ソケットの場合にのみ使用されます。
このフラグが設定されている場合、指定された関連付けは ABORT シグナルをピアに送信して異常終了します。このフラグは 1 対多スタイル SCTP ソケットの場合にのみ使用されます。
このフラグが設定されている場合、指定された関連付けは適切に終了します。このフラグは 1 対多スタイル SCTP ソケットの場合にのみ使用されます。
このフラグが設定されている場合、timetolive パラメータに指定された期間内に伝送が正常に完了しないメッセージは期限切れになります。
sctp_sendmsg() 関数は、送信したバイト数を返します。エラーが発生した場合、sctp_sendmsg() 関数は -1 を返します。
s パラメータに渡されたファイル記述子が有効でない場合、sctp_sendmsg() 関数は失敗して errno の値を EBADF に設定します。s パラメータの渡されたファイル記述子がソケットでない場合、sctp_sendmsg() 関数は失敗して errno の値を ENOTSOCK に設定します。flags パラメータに値 MSG_OOB が含まれる場合、sctp_sendmsg() 関数は失敗して errno の値を EOPNOTSUPP に設定します。1 対 1 スタイルソケットで flags パラメータに値 MSG_ABORT または MSG_EOF が含まれる場合、sctp_sendmsg() 関数は失敗して errno の値を EOPNOTSUPP に設定します。関連付けが確立していない場合、sctp_sendmsg() 関数は失敗して errno の値を ENOTCONN に設定します。ソケットが停止していてそれ以上の書込みができない場合、sctp_sendmsg() 関数は失敗して errno の値を EPIPE に設定します。ソケットが非ブロックで、伝送待ち行列がいっぱいである場合、sctp_sendmsg() 関数は失敗して errno の値を EAGAIN に設定します。
制御メッセージ長が不正である場合、sctp_sendmsg() 関数は失敗して errno の値を EINVAL に設定します。指定された着信先アドレスが関連付けに属さない場合、sctp_sendmsg() 関数は失敗して errno の値を EINVAL に設定します。stream_no の値が関連付けによってサポートされる発信ストリームの数以外である場合、sctp_sendmsg() 関数は失敗して errno の値を EINVAL に設定します。指定された着信先アドレスのアドレス群が AF_INET または AF_INET6 でない場合、sctp_sendmsg() 関数は失敗して errno の値を EINVAL に設定します。
sctp_send() 関数は、1 対 1 スタイルソケットと 1 対多スタイルソケットで使用できます。sctp_send() 関数は、SCTP 終端からメッセージを送信する際の拡張 SCTP 機能を有効にします。
この値は、socket() 関数によって作成されるソケットです。
この値は、sctp_send() 関数によって送信されるメッセージです。
この値は、メッセージの長さで、バイト単位で表されます。
この値は、メッセージの送信のために使用されるパラメータです。1 対多スタイルソケットの場合、メッセージの送信先の関連付け ID をこの値に指定できます。
この値は、sendmsg() 関数のフラグパラメータと同じです。
sctp_send() 関数は、送信したバイト数を返します。エラーが発生した場合、sctp_send() 関数は -1 を返します。
s パラメータの渡されたファイル記述子が有効でない場合、sctp_send() 関数は失敗して errno の値を EBADF に設定します。s パラメータの渡されたファイル記述子がソケットでない場合、sctp_send() 関数は失敗して errno の値を ENOTSOCK に設定します。sinfo パラメータの sinfo_flags フィールドに値 MSG_OOB が含まれる場合、sctp_send() 関数は失敗して errno の値を EOPNOTSUPP に設定します。1 対 1 スタイルソケットで sinfo パラメータの sinfo_flags フィールドに値 MSG_ABORT または MSG_EOF が含まれる場合、sctp_send() 関数は失敗して errno の値を EOPNOTSUPP に設定します。関連付けが確立していない場合、sctp_send() 関数は失敗して errno の値を ENOTCONN に設定します。ソケットが停止していてそれ以上の書込みができない場合、sctp_send() 関数は失敗して errno の値を EPIPE に設定します。ソケットが非ブロックで、伝送待ち行列がいっぱいである場合、sctp_send() 関数は失敗して errno の値を EAGAIN に設定します。
制御メッセージ長が不正である場合、sctp_send() 関数は失敗して errno の値を EINVAL に設定します。指定された着信先アドレスが関連付けに属さない場合、sctp_send() 関数は失敗して errno の値を EINVAL に設定します。stream_no の値が関連付けによってサポートされる発信ストリームの数以外である場合、sctp_send() 関数は失敗して errno の値を EINVAL に設定します。指定された着信先アドレスのアドレス群が AF_INET または AF_INET6 ではない場合、sctp_send() 関数は失敗して errno の値を EINVAL に設定します。
アプリケーションは、1 対多スタイルソケットで確立された関連付けを別のソケットとファイル記述子に分岐できます。散発的なメッセージの送信側または受信側が多数あり、元の 1 対多スタイルソケットのままである必要があるアプリケーションの場合に、別のソケットとファイル記述子を使用すると便利です。アプリケーションは、大量のデータトラフィックを伝送する関連付けを別のソケット記述子に分岐します。アプリケーションは、sctp_peeloff() 呼び出しを使用して、関連付けを別のソケットに分岐します。新しいソケットは 1 対 1 スタイルソケットです。sctp_peeloff() 関数の構文は次のとおりです。
int sctp_peeloff(int sock, sctp_assoc_t id);socket() システムコールから返される元の 1 対多スタイルソケット記述子。
別のファイル記述子に分岐する関連付けの識別子。
sock に渡されるソケット記述子が 1 対多スタイル SCTP ソケットではない場合、sctp_peeloff() 関数は失敗して EOPTNOTSUPP を返します。id() の値が 0 である場合、または、id の値が sock パラメータに渡されるソケット記述子の関連付けの最大数より大きい場合、sctp_peeloff 関数は失敗して EINVAL を返します。sctp_peeloff() 関数が新しいユーザーファイル記述子またはファイル構造体を作成できない場合、関数は失敗して EMFILE を返します。
sctp_getpaddrs() 関数は、関連付け内のすべてのピアを返します。
int sctp_getpaddrs(int sock, sctp_assoc_t id, void **addrs);sctp_getpaddrs() 関数が正常に結果を返した場合、**addrs パラメータの値は、動的に割り当てられるパックされた配列である、各アドレスの適切なタイプの sockaddr 構造体を指します。呼び出し元スレッドは、sctp_freepaddrs() 関数によってメモリーを解放します。**addrs パラメータに値 NULL はありません。sock に指定されるソケット記述子が IPv4 ソケット用である場合、sctp_getpaddrs() 関数は IPv4 アドレスを返します。sock に指定されるソケット記述子が IPv6 ソケット用である場合、sctp_getpaddrs() 関数は IPv4 アドレスと IPv6 アドレスを混在して返します。1 対多スタイルソケットの場合、id パラメータは照会する関連付けを指定します。1 対 1 スタイルソケットの場合、sctp_getpaddrs() 関数は id パラメータを無視します。sctp_getpaddrs() 関数が正常に結果を返す場合、関連付け内のピアアドレスの数が返されます。ソケット上に関連付けがない場合、sctp_getpaddrs() 関数は 0 を返し、**addrs パラメータの値は未定義です。エラーが発生した場合、sctp_getpaddrs() 関数は -1 を返し、**addrs パラメータの値は未定義です。
sctp_getpaddrs() に渡される sock パラメータのファイル記述子が無効である場合、sctp_getpaddrs() 関数は失敗して EBADF を返します。sctp_getpaddrs() 関数に渡される sock パラメータのファイル記述子がソケットでない場合、sctp_getpaddrs() 関数は失敗して ENOTSOCK を返します。sctp_getpaddrs() 関数に渡される sock パラメータのファイル記述子が接続されていないソケットである場合、sctp_getpaddrs() 関数は失敗して ENOTCONN を返します。
sctp_freepaddrs() 関数は、それ以前の sctp_getpaddrs() の呼び出しによって割り当てられたすべての資源を解放します。sctp_freepaddrs() 関数の構文は次のとおりです。
void sctp_freepaddrs(void *addrs);*addrs パラメータは、sctp_getpaddrs() 関数によって返されたピアのアドレスを含む配列です。
sctp_getladdrs() 関数は、ソケット上のローカルでバインドされているすべてのアドレスを返します。sctp_getladdrs() 関数の構文は次のとおりです。
int sctp_getladdrs(int sock, sctp_assoc_t id, void **addrs);sctp_getladdrs() 関数が正常に結果を返した場合、addrs の値は動的に割り当てられるパックされた配列の sockaddr 構造体を指します。sockaddr 構造体は各ローカルアドレスの適切なタイプです。呼び出し元アプリケーションは、sctp_freeladdrs() 関数を使用してメモリーを解放します。addrs パラメータの値が NULL であってはなりません。
sd パラメータによって参照されるソケットが IPv4 ソケットである場合、sctp_getladdrs() 関数は IPv4 アドレスを返します。sd パラメータによって参照されるソケットが IPv6 ソケットである場合、sctp_getladdrs() 関数は必要に応じて IPv4 アドレスと IPv6 アドレスを混在して返します。
1 対多スタイルソケットで sctp_getladdrs() 関数が起動されると、id パラメータは照会する関連付けを指定します。1 対 1 ソケットで sctp_getladdrs() 関数で動作する場合、id パラメータは無視されます。
id パラメータの値が 0 である場合、sctp_getladdrs() 関数は特定の関連付けに関係なくローカルでバインドされているアドレスを返します。sctp_getladdrs() 関数が正常に結果を返す場合、ソケットにバインドされているローカルアドレスの数を報告します。ソケットがバインドされていない場合、sctp_getladdrs() 関数は 0 を返し、*addrs の値は未定義です。エラーが発生した場合、sctp_getladdrs() 関数は -1 を返し、*addrs パラメータの値は未定義です。
sctp_freeladdrs() 関数は、それ以前の sctp_getladdrs() の呼び出しによって割り当てられたすべての資源を解放します。sctp_freeladdrs() 関数の構文は次のとおりです。
void sctp_freeladdrs(void *addrs);*addrs パラメータは、sctp_getladdrs() 関数によって返されたピアのアドレスを含む配列です。
この節では、SCTP ソケットの 2 つの使用法を示します。
/* * 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); }
/* * 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); } }