[ Team LiB ] |
23.4 NotificationsAs 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 switch14–15 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 change16–40 If the function finds an association change notification in the buffer, it prints the type of association change that occurred. Peer address change41–66 If it was a peer address notification, the function prints the address event (after decoding) and the address. Remote error67–71 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 message72–76 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 indication77–81 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 notification82–89 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 notification90–94 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 notifications21–30 Here the server changes the event settings so that it will receive all notifications. Normal receive code31–35 This section of server code is unchanged. Handle notification36–39 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 CodeWe 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. |
[ Team LiB ] |