|
24 | 24 | #include "libc/sysv/consts/inaddr.h"
|
25 | 25 | #include "libc/sysv/errfuns.h"
|
26 | 26 |
|
| 27 | +static inline void add_set(unsigned __int128 *pResTemp, uint16_t *pCurrentSet, |
| 28 | + unsigned *pDigitsLeft) { |
| 29 | + *pDigitsLeft -= *pDigitsLeft % 4; |
| 30 | + *pResTemp = (*pResTemp << 16) | *pCurrentSet; |
| 31 | + *pCurrentSet = 0; |
| 32 | +} |
| 33 | + |
| 34 | +static int inet_pton_inet6_impl(const char *src, uint8_t *dst) { |
| 35 | + enum STATES { |
| 36 | + COLON_OK = 1 << 0, |
| 37 | + COLON_WAS = 1 << 1, |
| 38 | + DIGIT_OK = 1 << 2, |
| 39 | + COLON_OR_DIGIT = COLON_OK | DIGIT_OK, |
| 40 | + }; |
| 41 | + |
| 42 | + unsigned __int128 res = 0; |
| 43 | + unsigned __int128 resTemp = 0; |
| 44 | + char c; |
| 45 | + enum STATES state = COLON_OR_DIGIT; |
| 46 | + unsigned digitsLeft = 32; |
| 47 | + bool zeroFound = false; |
| 48 | + uint16_t currentSet = 0; |
| 49 | + while (c = *src++) { |
| 50 | + if (digitsLeft == 0) { |
| 51 | + return 0; |
| 52 | + } |
| 53 | + |
| 54 | + if (state & COLON_OK) { |
| 55 | + if (c == ':') { |
| 56 | + if (state & COLON_WAS) { |
| 57 | + if (zeroFound) { |
| 58 | + return 0; |
| 59 | + } |
| 60 | + res = resTemp << (4 * digitsLeft); |
| 61 | + resTemp = 0; |
| 62 | + digitsLeft -= 4; |
| 63 | + zeroFound = true; |
| 64 | + state = DIGIT_OK; |
| 65 | + } else { |
| 66 | + if (digitsLeft % 4) { |
| 67 | + add_set(&resTemp, ¤tSet, &digitsLeft); |
| 68 | + } else if (digitsLeft == 32) { |
| 69 | + state = COLON_OK; |
| 70 | + } else { |
| 71 | + state = COLON_OR_DIGIT; |
| 72 | + } |
| 73 | + state |= COLON_WAS; |
| 74 | + } |
| 75 | + continue; |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + if (state & DIGIT_OK) { |
| 80 | + if ((c >= '0') && ((c < ':') || ((c >= 'A') && (c < 'G')) || |
| 81 | + ((c >= 'a') && (c < 'g')))) { |
| 82 | + state &= (~COLON_WAS); |
| 83 | + uint8_t digit; |
| 84 | + if (c < ':') { |
| 85 | + digit = c - '0'; |
| 86 | + } else if (c < 'G') { |
| 87 | + digit = c - 'A' + 10; |
| 88 | + } else { |
| 89 | + digit = c - 'a' + 10; |
| 90 | + } |
| 91 | + currentSet = (currentSet << 4) | digit; |
| 92 | + digitsLeft--; |
| 93 | + if (!(digitsLeft % 4)) { |
| 94 | + state = COLON_OK; |
| 95 | + add_set(&resTemp, ¤tSet, &digitsLeft); |
| 96 | + } else if ((state == DIGIT_OK) && (digitsLeft > 4)) { |
| 97 | + state = COLON_OR_DIGIT; |
| 98 | + } |
| 99 | + continue; |
| 100 | + } else if ((c == '.') && (digitsLeft >= 5) && (digitsLeft <= 27) && |
| 101 | + (digitsLeft % 4)) { |
| 102 | + uint8_t ipv4[4]; |
| 103 | + const unsigned digitsRead = 4 - digitsLeft % 4; |
| 104 | + if (inet_pton(AF_INET, src - (1 + digitsRead), &ipv4) == 1) { |
| 105 | + state &= (~COLON_WAS); |
| 106 | + digitsLeft += digitsRead; |
| 107 | + currentSet = (ipv4[0] << 8) | ipv4[1]; |
| 108 | + digitsLeft -= 4; |
| 109 | + add_set(&resTemp, ¤tSet, &digitsLeft); |
| 110 | + currentSet = (ipv4[2] << 8) | ipv4[3]; |
| 111 | + digitsLeft -= 4; |
| 112 | + add_set(&resTemp, ¤tSet, &digitsLeft); |
| 113 | + break; |
| 114 | + } |
| 115 | + } |
| 116 | + } |
| 117 | + return 0; |
| 118 | + } |
| 119 | + if (state & COLON_WAS) { |
| 120 | + return 0; |
| 121 | + } else if (digitsLeft % 4) { |
| 122 | + add_set(&resTemp, ¤tSet, &digitsLeft); |
| 123 | + } |
| 124 | + if (!zeroFound && (digitsLeft != 0)) { |
| 125 | + return 0; |
| 126 | + } |
| 127 | + |
| 128 | + res |= resTemp; |
| 129 | + dst[0] = res >> (15 * 8); |
| 130 | + dst[1] = res >> (14 * 8); |
| 131 | + dst[2] = res >> (13 * 8); |
| 132 | + dst[3] = res >> (12 * 8); |
| 133 | + dst[4] = res >> (11 * 8); |
| 134 | + dst[5] = res >> (10 * 8); |
| 135 | + dst[6] = res >> (9 * 8); |
| 136 | + dst[7] = res >> (8 * 8); |
| 137 | + dst[8] = res >> (7 * 8); |
| 138 | + dst[9] = res >> (6 * 8); |
| 139 | + dst[10] = res >> (5 * 8); |
| 140 | + dst[11] = res >> (4 * 8); |
| 141 | + dst[12] = res >> (3 * 8); |
| 142 | + dst[13] = res >> (2 * 8); |
| 143 | + dst[14] = res >> (1 * 8); |
| 144 | + dst[15] = res >> (0 * 8); |
| 145 | + return 1; |
| 146 | +} |
| 147 | + |
27 | 148 | /**
|
28 | 149 | * Converts internet address string to binary.
|
29 | 150 | *
|
30 |
| - * @param af can be AF_INET |
| 151 | + * @param af can be AF_INET or AF_INET6 |
31 | 152 | * @param src is the ASCII-encoded address
|
32 | 153 | * @param dst is where the binary-encoded net-order address goes
|
33 | 154 | * @return 1 on success, 0 on src malformed, or -1 w/ errno
|
34 | 155 | */
|
35 | 156 | int inet_pton(int af, const char *src, void *dst) {
|
36 | 157 | uint8_t *p;
|
37 | 158 | int b, c, j;
|
| 159 | + if (af == AF_INET6) return inet_pton_inet6_impl(src, dst); |
38 | 160 | if (af != AF_INET) return eafnosupport();
|
39 | 161 | j = 0;
|
40 | 162 | p = dst;
|
|
0 commit comments