[ Team LiB ] |
3.8 sock_ntop and Related FunctionsA basic problem with inet_ntop is that it requires the caller to pass a pointer to a binary address. This address is normally contained in a socket address structure, requiring the caller to know the format of the structure and the address family. That is, to use it, we must write code of the form struct sockaddr_in addr; inet_ntop(AF_INET, &addr.sin_addr, str, sizeof(str)); for IPv4, or struct sockaddr_in6 addr6; inet_ntop(AF_INET6, &addr6.sin6_addr, str, sizeof(str)); for IPv6. This makes our code protocol-dependent. To solve this, we will write our own function named sock_ntop that takes a pointer to a socket address structure, looks inside the structure, and calls the appropriate function to return the presentation format of the address.
sockaddr points to a socket address structure whose length is addrlen. The function uses its own static buffer to hold the result and a pointer to this buffer is the return value.
The presentation format is the dotted-decimal form of an IPv4 address or the hex string form of an IPv6 address surrounded by brackets, followed by a terminator (we use a colon, similar to URL syntax), followed by the decimal port number, followed by a null character. Hence, the buffer size must be at least INET_ADDRSTRLEN plus 6 bytes for IPv4 (16 + 6 = 22), or INET6_ADDRSTRLEN plus 8 bytes for IPv6 (46 + 8 = 54). We show the source code for only the AF_INET case in Figure 3.14. Figure 3.14 Our sock_ntop function.lib/sock_ntop.c 5 char * 6 sock_ntop(const struct sockaddr *sa, socklen_t salen) 7 { 8 char portstr[8]; 9 static char str[128]; /* Unix domain is largest */ 10 switch (sa->sa_family) { 11 case AF_INET:{ 12 struct sockaddr_in *sin = (struct sockaddr_in *) sa; 13 if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) 14 return (NULL); 15 if (ntohs(sin->sin_port) != 0) { 16 snprintf(portstr, sizeof(portstr), ":%d", 17 ntohs(sin->sin_port)); 18 strcat(str, portstr); 19 } 20 return (str); 21 } There are a few other functions that we define to operate on socket address structures, and these will simplify the portability of our code between IPv4 and IPv6.
sock_bind_wild binds the wildcard address and an ephemeral port to a socket. sock_cmp_addr compares the address portion of two socket address structures, and sock_cmp_port compares the port number of two socket address structures. sock_get_port returns just the port number, and sock_ntop_host converts just the host portion of a socket address structure to presentation format (not the port number). sock_set_addr sets just the address portion of a socket address structure to the value pointed to by ptr, and sock_set_port sets just the port number of a socket address structure. sock_set_wild sets the address portion of a socket address structure to the wildcard. As with all the functions in the text, we provide a wrapper function whose name begins with "S" for all of these functions that return values other than void and normally call the wrapper function from our programs. We do not show the source code for all these functions, but it is freely available (see the Preface). |
[ Team LiB ] |