[ Team LiB ] Previous Section Next Section

11.14 udp_client Function

Our functions that provide a simpler interface to getaddrinfo change with UDP because we provide one client function that creates an unconnected UDP socket, and another in the next section that creates a connected UDP socket.

#include "unp.h"

int udp_client (const char *hostname, const char *service, struct sockaddr **saptr, socklen_t *lenp);

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

This function creates an unconnected UDP socket, returning three items. First, the return value is the socket descriptor. Second, saptr is the address of a pointer (declared by the caller) to a socket address structure (allocated dynamically by udp_client), and in that structure, the function stores the destination IP address and port for future calls to sendto. The size of the socket address structure is returned in the variable pointed to by lenp. This final argument cannot be a null pointer (as we allowed for the final argument to tcp_listen) because the length of the socket address structure is required in any calls to sendto and recvfrom.

Figure 11.15 shows the source code for this function.

Figure 11.15 udp_client function: creates an unconnected UDP socket.

lib/udp_client.c

 1 #include     "unp.h"

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

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

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

14     do {
15         sockfd = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
16         if (sockfd >= 0)
17             break;               /* success */
18     } while ( (res = res->ai_next) ! = NULL);

19     if (res == NULL)             /* errno set from final socket () */
20         err_sys ("udp_client error for %s, %s", host, serv);

21     *saptr = Malloc (res->ai_addrlen);
22     memcpy (*saptr, res->ai_addr, res->ai_addrlen);
23     *lenp = res->ai_addrlen;

24     freeaddrinfo (ressave);

25     return (sockfd);
26 }

getaddrinfo converts the hostname and service arguments. A datagram socket is created. Memory is allocated for one socket address structure, and the socket address structure corresponding to the socket that was created is copied into the memory.

Example: Protocol-Independent Daytime Client

We now recode our daytime client from Figure 11.11 to use UDP and our udp_client function. Figure 11.16 shows the protocol-independent source code.

Figure 11.16 UDP daytime client using our udp_client function.

names/daytimeudpcli1.c

 1 #include     "unp.h"

 2 int
 3 main(int argc, char **argv)
 4 {
 5     int       sockfd, n;
 6     char      recvline [MAXLINE + 1];
 7     socklen_t salen;
 8     struct sockaddr *sa;

 9     if (argc ! = 3)
10         err_quit
11             ("usage: daytimeudpclil <hostname/IPaddress> <service/port#>");

12     sockfd = Udp_client (argv [1], argv [2], (void **) &sa, &salen);

13     printf ("sending to %s\n", Sock_ntop_host (sa, salen));

14     Sendto (sockfd, "", 1, 0, sa, salen);     /* send 1-byte datagram */

15     n = Recvfrom (sockfd, recvline, MAXLINE, 0 NULL, NULL);
16     recvline [n] = '\0';         /* null terminate */
17     Fputs (recvline, stdout);

18     exit (0);
19 }

12–17 We call our udp_client function and then print the IP address and port of the server to which we will send the UDP datagram. We send a one-byte datagram and then read and print the reply.

We need to send only a zero-byte UDP datagram, as what triggers the daytime server's response is just the arrival of a datagram, regardless of its length and contents. But, many SVR4 implementations do not allow a zero-length UDP datagram.

We run our client specifying a hostname that has a AAAA record and an A record. Since the structure with the AAAA record is returned first by getaddrinfo, an IPv6 socket is created.


freebsd % daytimeudpcli1 aix daytime
sending to 3ffe:b80:1f8d:2:204:acff:fe17:bf38
Sun Jul 27 23:21:12 2003

Next, we specify the dotted-decimal address of the same host, resulting in an IPv4 socket.


freebsd % daytimeudpclil 192.168.42.2 daytime
sending to 192.168.42.2
Sun Jul 27 23:21:40 2003



    [ Team LiB ] Previous Section Next Section