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 |
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 }
1217 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