Unix Network Programming Episode 25

‘sock_ntop’ and Related Functions

A 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.

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.

#include "unp.h"
char *sock_ntop(const struct sockaddr *sockaddr, socklen_t addrlen);

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).

char *sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
    char portstr[8];
    static char str[128];

    switch(sa->sa_family)
    {
        case AF_INET:
        {
            struct sockaddr_in *sin=(struct sockaddr_in *)sa;
            
            if(inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))==NULL)
                return NULL;
            if(ntohs(sin->sin_port)!=0)
            {
                snprintf(portstr, sizeof(portstr),":%d", ntohs(sin->sin_port));
                strcat(sr, portstr);
            }
            return str;
        }
    }
}

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.

#include "unp.h"
int sock_bind_wild(int sockfd, int family);

int sock_cmp_addr(const struct sockaddr *sockaddr1, const struct sockaddr *sockaddr2, socklen_t addrlen);

int sock_cmp_port(const struct sockaddr *sockaddr1, const struct sockaddr *sockaddr2, socklen_t addrlen);

int sock_get_port(const struct sockaddr *sockaddr, socklen_t addrlen);

char *sock_ntop_host(const struct sockaddr *sockaddr, socklen_t addrlen);

void sock_set_addr(const struct sockaddr *sockaddr, socklen_t addrlen, void *ptr);
void sock_set_port(const struct sockaddr *sockaddr, socklen_t addrlen, int port);
void sock_set_wild(struct sockaddr *sockaddr, socklen_t addrlen);

你可能感兴趣的:(Unix,Network,Programming)