23.4 Notifications
As we discussed in Section 9.14, an
application can subscribe to seven notifications. Up to now, our
application has ignored all events that may occur other than the
receipt of new data. The examples in this section give an overview
of how to receive and interpret SCTP's notifications of additional
transport-layer events. Figure
23.4 shows a function that will display any notification that
arrives from the transport. We will also modify our server to
enable all events and call this new function when a notification is
received. Note that our server is not really using the notification
for any specific purpose.
Cast and switch
14鈥?5
The function casts the incoming buffer to the overall union type.
It dereferences the generic sn_header structure and the
generic type sn_type, and switches on this value.
Process association change
16鈥?0
If the function finds an association change notification in the
buffer, it prints the type of association change that occurred.
Peer address change
41鈥?6
If it was a peer address notification, the function prints the
address event (after decoding) and the address.
Remote error
67鈥?1
If the function finds a remote error, it displays this fact and the
association ID on which it occurred. The function does not bother
to decode and display the actual error reported by the remote peer.
The information is available in the sre_data field of the
sctp_remote_error structure.
Figure 23.4 A
notifications display utility.
sctp/sctp_displayevents.c
1 #include "unp.h"
2 void
3 print_notification(char *notify_buf)
4 {
5 union sctp_notification *snp;
6 struct sctp_assoc_change *sac;
7 struct sctp_paddr_change *spc;
8 struct sctp_remote_error *sre;
9 struct sctp_send_failed *ssf;
10 struct sctp_shutdown_event *sse;
11 struct sctp_adaption_event *ae;
12 struct sctp_pdapi_event *pdapi;
13 const char *str;
14 snp = (union sctp_notification *) notify_buf;
15 switch (snp->sn_header.sn_type) {
16 case SCTP_ASSOC_CHANGE:
17 sac = &snp->sn_assoc_change;
18 switch (sac->sac_state) {
19 case SCTP_COMM_UP:
20 str = "COMMUNICATION UP";
21 break;
22 case SCTP_COMM_LOST:
23 str = "COMMUNICATION LOST";
24 break;
25 case SCTP_RESTART:
26 str = "RESTART";
27 break;
28 case SCTP_SHUTDOWN_COMP:
29 str = "SHUTDOWN COMPLETE";
30 break;
31 case SCTP_CANT_STR_ASSOC:
32 str = "CAN'T START ASSOC";
33 break;
34 default:
35 str = "UNKNOWN";
36 break;
37 } /* end switch(sac->sac_state) */
38 printf("SCTP_ASSOC_CHANGE: %s, assoc=0x%x\n", str,
39 (uint32_t) sac->sac_assoc_id);
40 break;
41 case SCTP_PEER_ADDR_CHANGE:
42 spc = &snp->sn_paddr_change;
43 switch (spc->spc_state) {
44 case SCTP_ADDR_AVAILABLE:
45 str = "ADDRESS AVAILABLE";
46 break;
47 case SCTP_ADDR_UNREACHABLE:
48 str = "ADDRESS UNREACHABLE";
49 break;
50 case SCTP_ADDR_REMOVED:
51 str = "ADDRESS REMOVED";
52 break;
53 case SCTP_ADDR_ADDED:
54 str = "ADDRESS ADDED";
55 break;
56 case SCTP_ADDR_MADE_PRIM:
57 str = "ADDRESS MADE PRIMARY";
58 break;
59 default:
60 str = "UNKNOWN";
61 break;
62 } /* end switch(spc->spc_state) */
63 printf("SCTP_PEER_ADDR_CHANGE: %s, addr=%s, assoc=0x%x\n", str,
64 Sock_ntop((SA *) &spc->spc_aaddr, sizeof(spc->spc_aaddr)),
65 (uint32_t) spc->spc_assoc_id);
66 break;
67 case SCTP_REMOTE_ERROR:
68 sre = &snp->sn_remote_error;
69 printf("SCTP_REMOTE_ERROR: assoc=0x%x error=%d\n",
70 (uint32_t) sre->sre_assoc_id, sre->sre_error);
71 break;
72 case SCTP_SEND_FAILED:
73 ssf = &snp->sn_send_failed;
74 printf("SCTP_SEND_FAILED: assoc=0x%x error=%d\n",
75 (uint32_t) ssf->ssf_assoc_id, ssf->ssf_error);
76 break;
77 case SCTP_ADAPTION_INDICATION:
78 ae = &snp->sn_adaption_event;
79 printf("SCTP_ADAPTION_INDICATION: 0x%x\n",
80 (u_int) ae->sai_adaption_ind);
81 break;
82 case SCTP_PARTIAL_DELIVERY_EVENT:
83 pdapi = &snp->sn_pdapi_event;
84 if (pdapi->pdapi_indication == SCTP_PARTIAL_DELIVERY_ABORTED)
85 printf("SCTP_PARTIAL_DELIEVERY_ABORTED\n");
86 else
87 printf("Unknown SCTP_PARTIAL_DELIVERY_EVENT 0x%x\n",
88 pdapi->pdapi_indication);
89 break;
90 case SCTP_SHUTDOWN_EVENT:
91 sse = &snp->sn_shutdown_event;
92 printf("SCTP_SHUTDOWN_EVENT: assoc=0x%x\n",
93 (uint32_t) sse->sse_assoc_id);
94 break;
95 default:
96 printf("Unknown notification event type=0x%x\n",
97 snp->sn_header.sn_type);
98 }
99 }
Failed message
72鈥?6
If the function decodes a send failed notification, it knows that a
message was not sent to the peer. This means that either: (i) the
association is coming down, and an association notification will
soon follow (if it has not already arrived), or (ii) the server is
using the partial reliability extension and a message was not
successfully sent (due to constraints placed on the transfer). The
data actually sent is available to the function in the
ssf_data field (which our function does not examine).
Adaption layer indication
77鈥?1
If the function decodes an adaption layer indicator, it displays
the 32-bit value passed in the setup message (INIT or
INIT-ACK).
Partial delivery notification
82鈥?9
If a partial delivery notification arrives, the function announces
it. The only event defined as of this writing is that the partial
delivery is aborted.
Shutdown notification
90鈥?4
If the function decodes this notification, it knows that the peer
has issued a graceful shutdown. This notification is usually soon
followed by an association change notification when the shutdown
sequence completes.
The modification to the server to use our new
function can be seen in Figure
23.5.
Figure 23.5 A
modified server that uses notifications.
sctp/sctpserv06.c
21 bzero(&evnts, sizeof(evnts));
22 evnts.sctp_data_io_event = 1;
23 evnts.sctp_association_event = 1;
24 evnts.sctp_address_event = 1;
25 evnts.sctp_send_failure_event = 1;
26 evnts.sctp_peer_error_event = 1;
27 evnts.sctp_shutdown_event = 1;
28 evnts.sctp_partial_delivery_event = 1;
29 evnts.sctp_adaption_layer_event = 1;
30 Setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts));
31 Listen(sock_fd, LISTENQ);
32 for ( ; ; ) {
33 len = sizeof(struct sockaddr_in);
34 rd_sz = Sctp_recvmsg(sock_fd, readbuf, sizeof(readbuf),
35 (SA *) &cliaddr, &len, &sri, &msg_flags);
36 if (msg_flags & MSG_NOTIFICATION) {
37 print_notification(readbuf);
38 continue;
39 }
Set up to receive notifications
21鈥?0
Here the server changes the event settings so that it will receive
all notifications.
Normal receive code
31鈥?5
This section of server code is unchanged.
Handle notification
36鈥?9
Here the server checks the msg_flags field. If the server
finds that the data is a notification, it calls our display
function sctp_print_notification and loops around to read
the next message.
Running the Code
We start the client and send one message as
follows:
FreeBSD-lap: ./sctpclient01 10.1.1.5
[0] Hello
From str:1 seq:0 (assoc:c99e15a0) : [0] Hello
Control-D
FreeBSD-lap:
When receiving the connection, message, and
connection termination, our modified server displays each event as
it occurs.
FreeBSD-lap: ./sctpserv06
SCTP_ADAPTION_INDICATION: 0x504c5253
SCTP_ASSOC_CHANGE: COMMUNICATION UP, assoc=c99e2680h
SCTP_SHUTDOWN_EVENT: assoc=c99e2680h
SCTP_ASSOC_CHANGE: SHUTDOWN COMPLETE, assoc=c99e2680h
Control-C
As you can see, the server now announces the
events as they occur on the transport.
|