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;
}
|