File: iptostr.c

package info (click to toggle)
tinyssh 20250501-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,388 kB
  • sloc: ansic: 20,245; sh: 1,582; python: 1,449; makefile: 913
file content (133 lines) | stat: -rw-r--r-- 3,035 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
20130604
20241207 - reformated using clang-format
Jan Mojzis
Public domain.
*/

#include "byte.h"
#include "iptostr.h"

static char *iptostr4(char *, const unsigned char *);
static char *iptostr6(char *, const unsigned char *);

/*
The 'iptostr(strbuf,ip)' function converts IP address 'ip'
from network byte order into the 0-terminated string.
The 'ip' length is always 16 bytes. The caller must
allocate at least IPTOSTR_LEN bytes for 'strbuf'.
*/
char *iptostr(char *strbuf, const unsigned char *ip) {

    static char staticbuf[IPTOSTR_LEN];

    if (!strbuf) strbuf = staticbuf; /* not thread-safe */

    if (byte_isequal("\0\0\0\0\0\0\0\0\0\0\377\377", 12, ip)) {
        return iptostr4(strbuf, ip + 12);
    }
    return iptostr6(strbuf, ip);
}

/* convert IPv4 address */
static char *iptostr4(char *strbuf, const unsigned char *ip) {

    long long i, len = 0;
    unsigned long long num;

    for (i = 3; i >= 0; --i) {
        num = ip[i];
        do {
            num /= 10;
            ++len;
        } while (num);
        if (i > 0) ++len;
    }
    strbuf += len;

    for (i = 3; i >= 0; --i) {
        num = ip[i];
        do {
            *--strbuf = '0' + (num % 10);
            num /= 10;
        } while (num);
        if (i > 0) *--strbuf = '.';
    }

    while (len < IPTOSTR_LEN) strbuf[len++] = 0;
    return strbuf;
}

/*
The 'ip' is splited into 8 16-bit blocks and
the 'countz' function counts successive zeros and
searches for largest zero-block.
'first' ... first position of the zero-block
'last'  ...  last position of the zero-block
*/
static void countz(long long *first, long long *last,
                   const unsigned long long *ip) {

    long long i, j, e;
    long long count[8];

    for (i = 7; i >= 0; --i) count[i] = 0;

    e = 8;
    for (i = 7; i >= 0; --i) {
        if (!ip[i]) {
            for (j = i; j < e; ++j) ++count[j];
        }
        else { e = i; }
    }

    e = 0;
    j = 0;
    for (i = 7; i >= 0; --i) {
        if (count[i]) {
            if (count[i] >= e) {
                e = count[i];
                j = i;
            }
        }
    }

    *first = j - count[j] + 1;
    *last = j;
}

/* convert IPv6 address */
static char *iptostr6(char *strbuf, const unsigned char *ip) {

    long long first, last, i;
    unsigned long long ip2[8];
    char *s = strbuf;

    for (i = 7; i >= 0; --i) {
        ip2[i] = ip[2 * i];
        ip2[i] <<= 8;
        ip2[i] += ip[2 * i + 1];
    }

    countz(&first, &last, ip2);

    strbuf += IPTOSTR_LEN - 1;
    *strbuf = 0;

    for (i = 7; i >= 0; --i) {
        if (i <= last && i >= first && first != last) {
            if (i == last) *--strbuf = ':';
            if (i == 7) *--strbuf = ':';
            continue;
        }
        do {
            *--strbuf = "0123456789abcdef"[ip2[i] & 15];
            ip2[i] >>= 4;
        } while (ip2[i]);
        if (i > 0) *--strbuf = ':';
    }
    i = strbuf - s;
    byte_copy(s, IPTOSTR_LEN - i, strbuf);
    byte_zero(s + IPTOSTR_LEN - i, i);
    return s;
}