SCTP 事件通知

    SCTP 提供了多种可用的通知,用户可经由这些通知追踪相关关联的状态。通知传递的是传输级的事件,包括网络状态变动、关联启动、远程操作错误以及消息不可递送。不论是一到一式还是一到多式接口,默认情况下除 sctp_data_io_event 外的所有事件都是禁止的。
    使用 SCTP 套接字选项一节中提到的 SCTP_EVENTS 选项可以预定 8 个事件,其中 7 个产生称为通知的额外数据,通知本身可经由普通的套接字描述符获取。当产生它们的事件发生时,这些通知就会内嵌在数据中加入到套接字描述符。在预订相应通知的前提下读取某个套接字时,用户数据和通知将在套接字缓冲区中交错出现,所以为了区分数据和通知,应该使用 recvmsg 或 sctp_recvmsg 函数。如果所返回的数据是一个事件通知,那么这两个函数返回的 msg_flags 参数将含有 MSG_NOTIFICATION 标志。
    每种通知都采用标签-长度-值(tag-length-value,TLV)格式,其中前 8 个字节给出通知的类型和总长度。开启 sctp_data_io_event 事件将导致每次读入用户数据都收到一个 sctp_sndrcvinfo 结构。一般情况下这些信息通过调用 recvmsg 函数作为辅助数据获取,或者也可以利用 sctp_recvmsg 函数的 sctp_sndrcvinfo 结构来获取。通知的格式如下。
union sctp_notification{          // notification event
    struct sctp_tlv    sn_header;
    struct sctp_assoc_change    sn_assoc_change;
    struct sctp_paddr_change    sn_paddr_change;
    struct sctp_remote_error    sn_remote_error;
    struct sctp_send_failed     sn_send_failed;
    struct sctp_shutdown_event  sn_shutdown_event;
    struct sctp_adaption_event  sn_adaption_event;
    struct sctp_pdapi_event     sn_pdapi_event;
};
struct sctp_tlv{
    u_int16_t sn_type;
    u_int16_t sn_flags;
    u_int32_t sn_length;
};

    sn_header 字段用于解释类型值,以便译解出所处理的实际消息。下表给出了 sn_header.sn_type 的取值与 SCTP_EVENTS 套接字选项中使用的预订字段之间的对应关系。

    每种通知都有各自的结构,给出了在传输中发生的相应事件的具体信息。
    * SCTP_ASSOC_CHANGE
    本通知告知应用进程关联本身发生变动:或者已开始一个新的关联,或者已结束一个现有的关联。它提供的信息定义如下。
struct sctp_assoc_change{
    u_int16_t    sac_type;
    u_int16_t    sac_flags;
    u_int32_t    sac_length;
    u_int16_t    sac_state;
    u_int16_t    sac_error;
    u_int16_t    sac_outbound_streams;
    u_int16_t    sac_inbound_streams;
    sctp_assoc_t sac_asoc_id;
    u_int8_t    sac_info[];
};

    其中 sac_state 给出关联上发生的事件类型状态,取如下值之一。
    (1)SCTP_COMM_UP:表示某个新的关联刚刚启动,此时的内入流和外出流字段分别指出各自方向有多少流可用,关联标识字段给出这个关联在本地 SCTP 栈的唯一访问标识。
    (2)SCTP_COMM_LOST:表示由关联标识字段给出的关联已经关闭,原因既可以是触发了某个不可达门限(例如本地 SCTP 端点多次超时触及门限,表明对端不再可达),也可以是对端执行了对于该关联的终止性关闭(通常使用 SO_LINGER 套接字选项或以 MSG_ABORT 标志使用 sendmsg)。特定于用户的消息将存放在本通知的 sac_info 字段中。
    (3)SCTP_RESTART:表示对端已经重启。应用进程应该验证每个方向流的数目,因为这些值可能在重启过程中发生变动。
    (4)SCTP_SHUTDOWN_COMP:表示由本地端点激发的关联终止过程(或者通过调用 shutdown 函数,或者通过以 MSG_EOF 标志使用 sendmsg 函数)已经结束。对于一到一式接口,收到本通知后,相应套接字描述符可再次用于连接到另一个对端。
    (5)SCTP_CANT_STR_ASSOC:表示对端对于本端的关联建立尝试(例如 INIT 消息)未曾给出响应。
    sac_error 存放导致本地关联变动的 SCTP 协议错误起因代码。sac_outbound_streams 和 sac_inbound_streams 存放本关联上每个方向协定的流数目。sac_assoc_id 存放本关联的唯一标识。sac_info 字段存放用户可用的其他信息,比如如果某个关联被对端的某个用户自定义错误终止,这个错误就会存放在该字段中。
    * SCTP_PEER_ADDR_CHANGE
    本通知告知对端的某个地址经历了状态变动,这种变动既可以是失败性质(例如目的地不对所发送的消息作出响应),也可以是恢复性质(例如早先处于故障状态的某个目的地恢复正常)。伴随地址变动的结构如下。
struct sctp_paddr_change{
    u_int16_t    spc_type;
    u_int16_t    spc_flags;
    u_int32_t    spc_length;
    struct sockaddr_storage    spc_aaddr;
    u_int32_t    spc_state;
    u_int32_t    spc_error;
    sctp_assoc_t    spc_assoc_id;
};

    其中 spc_aaddr 字段存放本事件所影响的对端地址。spc_state 字段存放下表所示的值之一。

    当一个地址被声明为 SCTP_ADDR_UNREACHABLE 状态时,发送到该地址的任何数据都会被重新路由到一个候选地址。另外,其中一些状态(如 SCTP_ADDR_ADDED 和 SCTP_ADDR_REMOVED)仅仅适用于支持动态地址选项的 SCTP 实现。
    spc_error 存放用于提供关于事件更详细信息的通知错误代码,spc_assoc_id 存放关联标识。
    * SCTP_REMOTE_ERROR
    远程端点可能给本端发送一个操作性错误消息,这些消息可以指示当前关联的各种出错条件。当开启本通知时,整个错误块将以内嵌格式传递给应用进程。本消息的格式如下。
struct sctp_remote_error{
    u_int16_t    sre_type;
    u_int16_t    sre_flags;
    u_int32_t    sre_length;
    u_int16_t    sre_error;
    sctp_assoc_t    sre_assoc_id;
    u_int8_t    sre_data[];
};

    其中 sre_error 存放 SCTP 协议错误起因代码,sre_assoc_id 存放关联标识,sre_data 以内嵌格式存放完整的错误。
    * SCTP_SEND_FAILED
    无法递送到对端的消息会通过本通知送还给用户,这之后通常还会跟有一个关联故障通知。多数情况下一个消息不能被递送的唯一原因是关联已经失效,关联有效的前提下消息递送失败的唯一情况是使用了 SCTP 的部分可靠性扩展。它提供的结构如下。
struct sctp_send_failed{
    u_int16_t    ssf_type;
    u_int16_t    ssf_flags;
    u_int32_t    ssf_length;
    u_int32_t    ssf_error;
    struct sctp_sndrcvinfo    ssf_info;
    sctp_assoc_t    ssf_assoc_id;
    u_int3_t    ssf_data[];
};

    其中 ssf_flags 可取以下两个值之一。
    (1)SCTP_DATA_UNSENT:表示相应消息无法发送到对端(例如流控导致该消息无法在其生命期终止前送出)。
    (2)SCTP_DATA_SENT:表示相应消息已经至少发送到对端一次,然而对端一直没有确认。
    这种区分对于事务性协议可能比较重要,因为它们可能需要基于是否收到某个给定消息而采取不同的行为以恢复一个破裂的连接。ssf_error 字段若不为 0,则存放一个特定于本通知的错误代码,ssf_info 若有的话提供的是发送数据时传递给内核的信息(例如流数目、上下文等),ssf_assoc_id 存放关联标识,ssf_data 存放未能递送的消息本身。
    * SCTP_SHUTDOWN_EVENT
    本通知会在对端发送一个 SHUTDOWN 块到本地端点时传递给应用进程,它告知应用进程在相应套接字上不再接受新的数据。所有当前已排队的数据将被发送出去,发送完毕后相应关联就被终止。本通知的格式如下。
struct sctp_shutdown_event{
    uint16_t    sse_type;
    uint16_t    sse_flags;
    uint32_t    see_length;
    sctp_assoc_t    sse_assoc_id;
};

    其中 sse_assoc_id 存放即将关闭的那个关联的关联标识。
    * SCTP_ADAPTION_INDICATION
    有些实现支持适应层指示参数,该参数在 INIT 和 INIT_ACK 中交换,用于通知对端将执行什么类型的应用适应行为。本通知的格式如下。
struct sctp_adaption_event{
    u_int16_t    sai_type;
    u_int16_t    sai_flags;
    u_int32_t    sai_length;
    u_int32_t    sai_adaption_ind;
    sctp_assoc_t    sai_assoc_id;
};

    其中 sai_assoc_id 给出了本适应层通知的关联标识,sai_adaption_ind 给出对端在 INIT 或 INIT_ACK 消息中传递给本地主机的 32 为整数。外出适应层使用 SCTP_ADAPTION_LAYER 套接字选项设置。
    * SCTP_PARTIAL_DELIVERY_EVENT
    部分递送应用程序接口用于经由套接字缓冲区向用户传送大消息。一个支持在整个消息到达之前就可以开始递送它的实现称为具备部分递送 API。SCTP 实现如此调用部分递送 API:置空 msg_flags 字段,然后发送一个消息的各部分数据,在发送最后一部分数据时把 msg_flags 字段设置为 MSG_EOR。注意,如果应用进程准备接收大消息,应该使用 recvmsg 或 sctp_recvmsg 函数,以便查看 msg_flags 字段确定是否出现本条件。
    部分递送 API 有时需要向应用进程传递状态信息。比如如果需要终止一次部分递送 API 调用,本通知就得送给接收应用进程。本通知的格式如下。
struct sctp_pdapi_event{
    uint16_t    pdapi_type;
    uint16_t    pdapi_flags;
    uint32_t    pdapi_length;
    uint32_t    pdapi_indication;
    sctp_assoc_t    pdapi_assoc_id;
};

    其中,pdapi_assoc_id 给出部分递送 API 事件发生的关联标识,pdapi_indication 存放发生的事件,目前该字段的唯一有效值是 SCTP_PARTIAL_DELIVERY_ABORTED,它指出当前活跃的部分递送已被终止。

猜你喜欢

转载自aisxyz.iteye.com/blog/2410176