[ Team LiB ] Previous Section Next Section

Chapter 22

22.1

22.1 Recall that sock_ntop uses its own static buffer to hold the result. If we call it twice as arguments in a call to printf, the second call overwrites the result of the first call.

22.2

Yes, if the reply contains 0 bytes of user data (i.e., just an hdr structure).

22.3

Since select does not modify the timeval structure that specifies its time limit, you need to note the time when the first packet is sent (this is already returned in units of milliseconds by rtt_ts). If select returns with the socket being readable, note the current time, and if recvmsg is called again, calculate the new timeout for select.

22.4

The common technique is to create one socket per interface address, as we did in Section 22.6, and send the reply from the same socket on which the request arrived.

22.5

Calling getaddrinfo without a hostname argument and without the AI_PASSIVE flag set causes it to assume the local host address: 0::1 (IPv6) and 127.0.0.1 (IPv4). Recall that an IPv6 socket address structure is returned before an IPv4 socket address structure by getaddrinfo, assuming IPv6 is supported. If both protocols are supported on the host, the call to socket in udp_client will succeed with the family equal to AF_INET6.

Figure E.15 is the protocol-independent version of this program.

Figure E.15 Protocol-independent version of program from Section 22.6.

advio/udpserv04.c

 1 #include "unpifi.h"

 2 void mydg_echo(int, SA *, socklen_t);

 3 int
 4 main(int argc, char **argv)
 5 {
 6     int sockfd, family, port;
 7     const int on = 1;
 8     pid_t pid;
 9     socklen_t salen;
10     struct sockaddr *sa, *wild;
11     struct ifi_info *ifi, *ifihead;

12     if (argc == 2)
13         sockfd = Udp_client(NULL, argv[1], (void **) &sa, &salen);
14     else if (argc == 3)
15         sockfd = Udp_client(argv[1], argv[2], (void **) &sa, &salen);
16     else
17         err_quit("usage: udpserv04 [ <host> ] <service or port>");
18     family = sa->sa_family;
19     port = sock_get_port(sa, salen);
20     Close(sockfd);              /* we just want family, port, salen */

21     for (ifihead = ifi = Get_ifi_info(family, 1);
22          ifi != NULL; ifi = ifi->ifi_next) {

23             /* bind unicast address */
24         sockfd = Socket(family, SOCK_DGRAM, 0);
25         Setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

26         sock_set_port(ifi->ifi_addr, salen, port);
27         Bind(sockfd, ifi->ifi_addr, salen);
28         printf("bound %s\n", Sock_ntop(ifi->ifi_addr, salen));

29         if ( (pid = Fork()) == 0) { /* child */
30             mydg_echo(sockfd, ifi->ifi_addr, salen);
31             exit(0);            /* never executed */
32         }

33         if (ifi->ifi_flags & IFF_BROADCAST) {
34                 /* try to bind broadcast address */
35             sockfd = Socket(family, SOCK_DGRAM, 0);
36             Setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

37             sock_set_port(ifi->ifi_brdaddr, salen, port);
38             if (bind(sockfd, ifi->ifi_brdaddr, salen) < 0) {
39                 if (errno == EADDRINUSE) {
40                     printf("EADDRINUSE: %s\n",
41                            Sock_ntop(ifi->ifi_brdaddr, salen));
42                     Close(sockfd);
43                     continue;
44                 } else
45                     err_sys("bind error for %s",
46                             Sock_ntop(ifi->ifi_brdaddr, salen));
47             }
48             printf("bound %s\n", Sock_ntop(ifi->ifi_brdaddr, salen));

49             if ( (pid = Fork()) == 0) { /* child */
50                 mydg_echo(sockfd, ifi->ifi_brdaddr, salen);
51                 exit(0);        /* never executed */
52             }
53         }
54     }

55         /* bind wildcard address */
56     sockfd = Socket(family, SOCK_DGRAM, 0);
57     Setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

58     wild = Malloc(salen);
59     memcpy(wild, sa, salen);    /* copy family and port */
60     sock_set_wild(wild, salen);

61     Bind(sockfd, wild, salen);
62     printf("bound %s\n", Sock_ntop(wild, salen));

63     if ( (pid = Fork()) == 0) {  /* child */
64         mydg_echo(sockfd, wild, salen);
65         exit(0);                /* never executed */
66     }
67     exit(0);
68 }
69 void
70 mydg_echo(int sockfd, SA *myaddr, socklen_t salen)
71 {
72     int     n;
73     char    mesg[MAXLINE];
74     socklen_t len;
75     struct sockaddr *cli;

76     cli = Malloc(salen);

77     for ( ; ; ) {
78         len = salen;
79         n = Recvfrom(sockfd, mesg, MAXLINE, 0, cli, &len);
80         printf("child %d, datagram from %s", getpid(), Sock_ntop(cli, len));
81         printf(", to %s\n", Sock_ntop(myaddr, salen));

82         Sendto(sockfd, mesg, n, 0, cli, len);
83     }
84 }


    [ Team LiB ] Previous Section Next Section