龙空技术网

inet_pton函数源码分析(ipv4地址转换成数字)

爱吃鱼的工程师 139

前言:

眼前同学们对“inet_ntop源码”大约比较重视,兄弟们都需要剖析一些“inet_ntop源码”的相关文章。那么小编在网摘上汇集了一些有关“inet_ntop源码””的相关内容,希望兄弟们能喜欢,朋友们快快来学习一下吧!

简介

inet_pton的作用是将可读的IP地址(ipv4和ipv6均支持)字符串转换成网络序的函数,此函数的实现不在编译器中、也不在操作系统源码中,在C运行库的代码中实现。本文介绍的是Linux的C运行库:glibc对inet_pton函数的实现。

怎么找到glibc的inet_pton

fh@Feihu-3 glibc-2.34 % grep -nwr 'inet_pton' ./ | grep -nw 'weak_alias'7:.//resolv/inet_pton.c:72:weak_alias (__inet_pton, inet_pton)fh@Feihu-3 glibc-2.34 %
fh@Feihu-3 glibc-2.34 % vim include/libc-symbols.h

里面涉及到强引用和弱引用,请自行查阅相关资料。

接口源码实现

#include <string.h>#include <stdio.h>#include <nameser.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>// ipv4是4个字节,xxx.yyy.mmm.nnn// 注意:每个八位组第一个不能为0// 每个八位组值不能大于255// 只能有4个八位组// 整个ip字符串中只能有数字和'.'符号// dst的结构体不需要理会,只需要知道dst为接收内存且长度只能是4字节,其他随意static int inet_pton4(const char *src, const char *end, unsigned char *dst){    int saw_digit; // 每个八位组是否遇到数字标记,新的八位组将会清除标记    int octets;     // 八位组的个数,ip地址合法,则为4个    int ch;         // 遍历字符串,每次获得的字符    // NS_INADDRSZ长度是4个字节, 宏定义在nameser.h中    // 注意tmp不是字符串,仅仅是用来存放4个字节的数据,无'\0'    unsigned char tmp[NS_INADDRSZ];    unsigned char *tp;      // tp指的是八位组        saw_digit = 0;    octets = 0;    *(tp = tmp) = 0; // *tp = 0;初始化必须为0,计算数值的时候会有依赖        // 本函数实际上是转换成网络序的,所以方向是src -> end    // 如果仅仅转换成二进制,方向是end -> src    while (src < end)    {        ch = *src++; // 得到获得的ASCII值,src指向下一个字符        if (ch >= '0' && ch <= '9')        {            // 八位组迭代,比如192.168.8.217            // 以192为例:            // 0 -> 0 * 10 + 1 = 1 -> 1 * 10 + 9 = 19 -> 19 * 10 + 2 = 192            // 在将192赋值到tmp的第一个字节上(第一个八位组)            unsigned int new = *tp * 10 + (ch - '0');                        // 八位组中不能以0开头,比如192.168.08.217是错误的            if (saw_digit && *tp == 0)                return 0;            // 某一个八位组值不能超过255            if (new > 255)                return 0;                        // 八位组赋值            *tp = new;                        // 一般是在遇到'.'的时候,(! saw_digit)为0            // 而在'.'之后的第一个数字置为1            // 统计八位组的数目,由于在运行中,所以值不得超过4            if (! saw_digit)            {                if (++octets > 4)                    return 0;                saw_digit = 1;            }        }        else if (ch == '.' && saw_digit)        {            if (octets == 4)                return 0;                        // 下一个八位组赋值,必须为0,方面迭代            // saw_digit标记为未遇到数值            *++tp = 0;            saw_digit = 0;        }        else            return 0; // 其他字符,直接返回错误    }    if (octets < 4)        return 0;    memcpy (dst, tmp, NS_INADDRSZ);    return 1;}static int hex_digit_value(char ch){    if ('0' <= ch && ch <= '9')        return ch - '0';    if ('a' <= ch && ch <= 'f')        return ch - 'a' + 10;    if ('A' <= ch && ch <= 'F')        return ch - 'A' + 10;    return -1;}static int inet_pton6(const char *src, const char *src_endp, unsigned char *dst){    unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;    const char *curtok;    int ch;    size_t xdigits_seen;    /* Number of hex digits since colon.  */    unsigned int val;        tp = memset (tmp, '\0', NS_IN6ADDRSZ);    endp = tp + NS_IN6ADDRSZ;    colonp = NULL;        /* Leading :: requires some special handling.  */    if (src == src_endp)        return 0;    if (*src == ':')    {        ++src;        if (src == src_endp || *src != ':')            return 0;    }        curtok = src;    xdigits_seen = 0;    val = 0;    while (src < src_endp)    {        ch = *src++;        int digit = hex_digit_value (ch);        if (digit >= 0)        {            if (xdigits_seen == 4)                return 0;            val <<= 4;            val |= digit;            if (val > 0xffff)                return 0;            ++xdigits_seen;            continue;        }        if (ch == ':')        {            curtok = src;            if (xdigits_seen == 0)            {                if (colonp)                    return 0;                colonp = tp;                continue;            }            else if (src == src_endp)                return 0;            if (tp + NS_INT16SZ > endp)                return 0;            *tp++ = (unsigned char) (val >> 8) & 0xff;            *tp++ = (unsigned char) val & 0xff;            xdigits_seen = 0;            val = 0;            continue;        }        if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)            && inet_pton4 (curtok, src_endp, tp) > 0)        {            tp += NS_INADDRSZ;            xdigits_seen = 0;            break;  /* '\0' was seen by inet_pton4.  */        }        return 0;    }    if (xdigits_seen > 0)    {        if (tp + NS_INT16SZ > endp)            return 0;        *tp++ = (unsigned char) (val >> 8) & 0xff;        *tp++ = (unsigned char) val & 0xff;    }    if (colonp != NULL)    {        /* Replace :: with zeros.  */        if (tp == endp)        /* :: would expand to a zero-width field.  */            return 0;        size_t n = tp - colonp;        memmove (endp - n, colonp, n);        memset (colonp, 0, endp - n - colonp);        tp = endp;    }    if (tp != endp)        return 0;    memcpy (dst, tmp, NS_IN6ADDRSZ);    return 1;}static int __inet_pton_length(int af, const char *src, size_t srclen, void *dst){    switch (af)    {        case AF_INET:            return inet_pton4(src, src + srclen, dst);        case AF_INET6:            return inet_pton6(src, src + srclen, dst);        default:            printf("invalid AF, af: %d.\n", af);            return -1;    }    return -1;}static int pton(int af, const char *src, void *dst){    return __inet_pton_length(af, src, strlen(src), dst);}void AddrConvertTest(void){    char szIpv4[INET_ADDRSTRLEN] = "192.168.8.217";    //char szIpv4[INET_ADDRSTRLEN] = "192.168.10.1";    unsigned int ulIpv4 = 3232237785;    printf("ip: %s, dec: %u, little-endian-hex: %#x, big-endian-hex: %#x\n", szIpv4, ulIpv4, ulIpv4, htonl(ulIpv4));        struct in_addr stIpv4Addr = {0};    int lRet = 0;    lRet = pton(AF_INET, szIpv4, &stIpv4Addr);    printf("pton ret: %d, ip: %s, s_addr: %#x.\n", lRet, szIpv4, stIpv4Addr.s_addr);    return;}void AddrConvertLibcTest(void){    char szStrIp[] = "192.168.8.217";    unsigned int ulIp = 3232237785;    printf("ip: %s, dec: %u, little-endian-hex: %#x, big-endian-hex: %#x\n", szStrIp, ulIp, ulIp, htonl(ulIp));    char *pcTmp = NULL;    int lRet = 0;    struct in_addr stInAddr = {0};    stInAddr.s_addr = inet_addr("192.168.8.217");    pcTmp = inet_ntoa(stInAddr);    printf("inet_ntoa, ret: %s, s_addr: %#x.\n", pcTmp, stInAddr.s_addr);        /** inet_addr 处理255.255.255.255以及错误的ip返回的结果为0xffffffff     */    stInAddr.s_addr = inet_addr("259.255.255.255");    printf("inet_addr s_addr: %#x.\n", stInAddr.s_addr);        char szIp[INET_ADDRSTRLEN] = "192.168.8.217";    struct in_addr stOutAddr = {0};    lRet = inet_aton(szIp, &stOutAddr);    printf("inet_aton ret: %d, ip: %s, s_addr: %#x.\n", lRet, szIp, stOutAddr.s_addr);        struct in_addr stAddr2 = {0};    char szIp2[INET_ADDRSTRLEN] = "192.168.8.217";    // 文本字符串格式转换成网络字节序的二进制地址    lRet = inet_pton(AF_INET, szIp2, &stAddr2);    int ipv4StructSize = sizeof(struct in_addr);    printf("inet_pton ret: %d, ip: %s, s_addr: %#x.\n", lRet, szIp2, stAddr2.s_addr);        const char *pcTmp2 = NULL;    memset(szIp2, 0, sizeof(szIp2));    // 网络字节序的二进制地址转换成文本字符串格式    pcTmp2 = inet_ntop(AF_INET, &stAddr2, szIp2, INET_ADDRSTRLEN);    printf("inet_ntop ret: %s, ip: %s.\n", pcTmp2, szIp2);}

标签: #inet_ntop源码