[ Team LiB ] Previous Section Next Section

23.7 Determining Peer and Local Address Information

Because 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 function

16–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 message

21–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 notifications

25–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 data

27 If the message read was a notification, keep looping until we read actual data.

Display message

28–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 want

9–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 addresses

14–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 addresses

18–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 address

7–8 The function loops through each address based on the number of addresses our caller specified.

Print address

9 We print the address using our sock_ntop function. Recall that this prints any socket address structure format the system supports.

Determine address size

10–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 pointer

27 The function now adds the size of the address to the base pointer to move forward through the list of addresses.

Running the Code

We 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 ] Previous Section Next Section