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鈥?0
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鈥?4
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鈥?6
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鈥?0
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鈥?3
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鈥?7
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鈥?1
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鈥?
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鈥?6
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:
|