[ Team LiB ] Previous Section Next Section

11.16 udp_server Function

Our final UDP function that provides a simpler interface to getaddrinfo is udp_server.

#include "unp.h"

int udp_server (const char *hostname, const char *service, socklen_t *lenptr);

Returns: unconnected socket descriptor if OK, no return on error

The arguments are the same as for tcp_listen: an optional hostname, a required service (so its port number can be bound), and an optional pointer to a variable in which the size of the socket address structure is returned.

Figure 11.18 shows the source code.

Figure 11.18 udp_server function: creates an unconnected socket for a UDP server.

lib/udp_server.c

 1 #include     "unp.h"

 2 int
 3 udp_server(const char *host, const char *serv, socklen_t *addrlenp)
 4 {
 5     int     sockfd, n;
 6     struct addrinfo hints, *res, *ressave;

 7     bzero(&hints, sizeof(struct addrinfo));
 8     hints.ai_flags = AI_PASSIVE;
 9     hints.ai_family = AF_UNSPEC;
10     hints.ai_socktype = SOCK_DGRAM;

11     if ( (n = getaddrinfo (host, serv, &hints, &res)) != 0)
12         err_quit ("udp_server error for %s, %s: %s",
13                   host, serv, gai_strerror(n));
14     ressave = res;

15     do {
16         sockfd = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
17         if (sockfd < 0)
18             continue;          /* error - try next one */

19         if (bind (sockfd, res->ai_addr, res->ai_addrlen) == 0)
20             break;             /* success */

21         Close (sockfd);        /* bind error - close and try next one */
22     } while ( (res = res->ai_next) != NULL);

23     if (res == NULL)           /* errno from final socket() or bind() */
24         err_sys ("udp_server error for %s, %s", host, serv);

25     if (addrlenp)
26         *addrlenp = res->ai_addrlen     * return size of protocol address */

27     freeaddrinfo (ressave) ;

28     return (sockfd);
29 }

This function is nearly identical to tcp_listen, but without the call to listen. We set the address family to AF_UNSPEC, but the caller can use the same technique that we described with Figure 11.14 to force a particular protocol (IPv4 or IPv6).

We do not set the SO_REUSEADDR socket option for the UDP socket because this socket option can allow multiple sockets to bind the same UDP port on hosts that support multicasting, as we described in Section 7.5. Since there is nothing like TCP's TIME_WAIT state for a UDP socket, there is no need to set this socket option when the server is started.

Example: Protocol-Independent Daytime Server

Figure 11.19 shows our daytime server, modified from Figure 11.14 to use UDP.

Figure 11.19 Protocol-independent UDP daytime server.

names/daytimeudpsrv2.c

 1 #include     "unp.h"
 2 #include     <time.h>

 3 int
 4 main (int argc, char **argv)
 5 {
 6     int     sockfd;
 7     ssize_t n;
 8     char     buff[MAXLINE];
 9     time_t ticks;
10     socklen_t len;
11     struct sockaddr_storage cliaddr;

12     if (argc == 2)
13         sockfd = Udp_server (NULL, argv [1] NULL);
14     else if (argc == 3)
15         sockfd = Udp_server (argv [1], argv [2], NULL);
16     else
17         err_quit ("usage: daytimeudpsrv [ <host> ] <service or port>");

18     for ( ; ; ) {
19         len = sizeof (cliaddr) ;
20         n = Recvfrom (sockfd, buff, MAXLINE, 0, (SA *) &cliaddr, &len);
21         printf ("datagram from %s\n", Sock_ntop ((SA *) &cliaddr, len));

22         ticks = time (NULL) ;
23         snprintf (buff, sizeof (buff), "%.24s\r\n", ctime (&ticks) ) ;
24         Sendto (sockfd, buff, strlen (buff), 0, (SA *) &cliaddr, len) ;
25     }
26 }
    [ Team LiB ] Previous Section Next Section