[ Team LiB ] |
23.7 Determining Peer and Local Address InformationBecause SCTP is a multihomed protocol, different mechanisms are needed to find out what addresses are in use at both the remote as well as the local endpoints of an association. In this section, we will modify our client to receive the communication up notification. Our client will then use this notification to display the addresses of both the local and remote sides of the association. Figures 23.9 and 23.10 show the modifications to our client code. Figures 23.11 and 23.12 show the new code we add to the client. Figure 23.9 Client set up for notifications.sctp/sctpclient04 16 bzero(&evnts, sizeof(evnts)); 17 evnts.sctp_data_io_event = 1; 18 evnts.sctp_association_event = 1; 19 Setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts)); 20 sctpstr_cli(stdin, sock_fd, (SA *) &servaddr, sizeof(servaddr)); Set events and call echo function16–20 We see a slight change to our client's main routine. The client explicitly subscribes to association change notifications. We now look at the modifications needed to sctpstr_cli so that it will use our new notification processing routine. Figure 23.10 sctp_strcli that handles notifications.sctp/sctp_strcli1.c 21 do { 22 len = sizeof(peeraddr); 23 rd_sz = Sctp_recvmsg(sock_fd, recvline, sizeof(recvline), 24 (SA *) &peeraddr, &len, &sri, &msg_flags); 25 if (msg_flags & MSG_NOTIFICATION) 26 check_notification(sock_fd, recvline, rd_sz); 27 } while (msg_flags & MSG_NOTIFICATION); 28 printf("From str:%d seq:%d (assoc:0x%x):", 29 sri.sinfo_stream, sri.sinfo_ssn, (u_int) sri.sinfo_assoc_id); 30 printf("%.*s", rd_sz, recvline); Loop waiting for message21–24 Here the client sets up the address length variable and calls the receive function to get the echoed message from the server. Check for notifications25–26 The client now checks to see if the message it just read is a notification. If it is, the client calls our notification processing routine shown in Figure 23.11. Loop while waiting for data27 If the message read was a notification, keep looping until we read actual data. Display message28–30 Next, the client displays the message and goes back to the top of its processing loop, waiting for user input. Now let's look at the new function sctp_check_notification, which will display the addresses of both endpoints when an association notification event arrives. Figure 23.11 Process notifications.sctp/sctp_check_notify.c 1 #include "unp.h" 2 void 3 check_notification(int sock_fd, char *recvline, int rd_len) 4 { 5 union sctp_notification *snp; 6 struct sctp_assoc_change *sac; 7 struct sockaddr_storage *sal, *sar; 8 int num_rem, num_loc; 9 snp = (union sctp_notification *) recvline; 10 if (snp->sn_header.sn_type == SCTP_ASSOC_CHANGE) { 11 sac = &snp->sn_assoc_change; 12 if ((sac->sac_state == SCTP_COMM_UP) || 13 (sac->sac_state == SCTP_RESTART)) { 14 num_rem = sctp_getpaddrs(sock_fd, sac->sac_assoc_id, &sar); 15 printf("There are %d remote addresses and they are:\n", num_rem); 16 sctp_print_addresses(sar, num_rem); 17 sctp_freepaddrs(sar); 18 num_loc = sctp_getladdrs(sock_fd, sac->sac_assoc_id, &sal); 19 printf("There are %d local addresses and they are:\n", num_loc); 20 sctp_print_addresses(sal, num_loc); 21 sctp_freeladdrs(sal); 22 } 23 } 24 } Check if it is notification we want9–13 The function casts the receive buffer to our generic notification pointer to find the notification type. If it is the notification the function is interested in, an association change notification, it then tests if the notification is a new or restarted association (SCTP_COMM_UP or SCTP_RESTART). We ignore all other notifications. Gather and print peer addresses14–17 We call sctp_getpaddrs to gather a list of remote addresses. We then print the number of addresses and use the address printing routine, sctp_print_addresses, shown in Figure 23.12, to display the addresses. When it finishes using the address pointer, the function calls the sctp_freepaddrs function to release the resources allocated by sctp_getpaddrs. Gather and print local addresses18–21 We call sctp_getladdrs to gather a list of local addresses, plus print the number of addresses and the addresses themselves. After the function finishes using the addresses, it calls the sctp_freeladdrs function to release the resources allocated by sctp_getladdrs. Finally, we look at one last new function, sctp_print_addresses, which will print a list of addresses in the form that is returned by the sctp_getpaddrs and sctp_getladdrs functions. Figure 23.12 Print a list of addresses.sctp/sctp_print_addrs.c 1 #include "unp.h" 2 void 3 sctp_print_addresses(struct sockaddr_storage *addrs, int num) 4 { 5 struct sockaddr_storage *ss; 6 int i, salen; 7 ss = addrs; 8 for (i = 0; i < num; i++) { 9 printf("%s\n", Sock_ntop((SA *) ss, salen)); 10 #ifdef HAVE_SOCKADDR_SA_LEN 11 salen = ss->ss_len; 12 #else 13 switch (ss->ss_family) { 14 case AF_INET: 15 salen = sizeof(struct sockaddr_in); 16 break; 17 #ifdef IPV6 18 case AF_INET6: 19 salen = sizeof(struct sockaddr_in6); 20 break; 21 #endif 22 default: 23 err_quit("sctp_print_addresses: unknown AF"); 24 break; 25 } 26 #endif 27 ss = (struct sockaddr_storage *) ((char *) ss + salen); 28 } 29 } Process each address7–8 The function loops through each address based on the number of addresses our caller specified. Print address9 We print the address using our sock_ntop function. Recall that this prints any socket address structure format the system supports. Determine address size10–26 The list of addresses is a packed list, not a simple array of sockaddr_storage structures. This is because the sockaddr_storage structure is quite large and it is too wasteful to use in passing addresses back and forth between the kernel and user space. On systems on which the sockaddr structure contains its own length, this is trivial: just extract the length from the current sockaddr_storage structure. On other systems, we choose the length based on the address family and quit with an error if the address family is unknown. Move address pointer27 The function now adds the size of the address to the base pointer to move forward through the list of addresses. Running the CodeWe run our modified client against the server as follows: FreeBSD-lap: ./sctpclient01 10.1.1.5 [0]Hi There are 2 remote addresses and they are: 10.1.1.5:9877 127.0.0.1:9877 There are 2 local addresses and they are: 10.1.1.5:1025 127.0.0.1:1025 From str:0 seq:0 (assoc:c99e2680):[0]Hi Control-D FreeBSD-lap: |
[ Team LiB ] |