11.14 udp_client FunctionOur 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.
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 ClientWe 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 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 |