1 2/* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include <nxt_main.h> 8 9 10#if (NXT_INET6) 11static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end); 12#endif 13 14static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs); 15static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs); 16static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs); 17 18 19nxt_sockaddr_t *
| 1 2/* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include <nxt_main.h> 8 9 10#if (NXT_INET6) 11static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end); 12#endif 13 14static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs); 15static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs); 16static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs); 17 18 19nxt_sockaddr_t *
|
20nxt_sockaddr_alloc(nxt_mem_pool_t *mp, socklen_t len)
| 20nxt_sockaddr_alloc(nxt_mem_pool_t *mp, socklen_t length)
|
21{ 22 nxt_sockaddr_t *sa; 23 24 /* 25 * The current struct sockaddr's define 32-bit fields at maximum 26 * and may define 64-bit AF_INET6 fields in the future. Alignment 27 * of memory allocated by nxt_mem_zalloc() is enough for these fields. 28 * If 128-bit alignment will be required then nxt_mem_malloc() and 29 * nxt_memzero() should be used instead. 30 */
| 21{ 22 nxt_sockaddr_t *sa; 23 24 /* 25 * The current struct sockaddr's define 32-bit fields at maximum 26 * and may define 64-bit AF_INET6 fields in the future. Alignment 27 * of memory allocated by nxt_mem_zalloc() is enough for these fields. 28 * If 128-bit alignment will be required then nxt_mem_malloc() and 29 * nxt_memzero() should be used instead. 30 */
|
31 sa = nxt_mem_zalloc(mp, offsetof(nxt_sockaddr_t, u) + len);
| 31 sa = nxt_mem_zalloc(mp, offsetof(nxt_sockaddr_t, u) + length);
|
32 33 if (nxt_fast_path(sa != NULL)) {
| 32 33 if (nxt_fast_path(sa != NULL)) {
|
34 nxt_socklen_set(sa, len);
| 34 nxt_socklen_set(sa, length);
|
35 } 36 37 return sa; 38} 39 40 41nxt_sockaddr_t * 42nxt_sockaddr_create(nxt_mem_pool_t *mp, struct sockaddr *sockaddr,
| 35 } 36 37 return sa; 38} 39 40 41nxt_sockaddr_t * 42nxt_sockaddr_create(nxt_mem_pool_t *mp, struct sockaddr *sockaddr,
|
43 socklen_t len)
| 43 socklen_t length)
|
44{ 45 size_t size, copy; 46 nxt_sockaddr_t *sa; 47
| 44{ 45 size_t size, copy; 46 nxt_sockaddr_t *sa; 47
|
48 size = len; 49 copy = len;
| 48 size = length; 49 copy = length;
|
50 51#if (NXT_HAVE_UNIX_DOMAIN) 52 53 /* 54 * Unspecified Unix domain sockaddr_un form and length are very 55 * platform depended (see comment in unix/socket.h). Here they are 56 * normalized to the sockaddr_un with single zero byte sun_path[]. 57 */ 58 59 if (size <= offsetof(struct sockaddr_un, sun_path)) { 60 /* 61 * Small socket length means a short unspecified Unix domain 62 * socket address: 63 * 64 * getsockname() and getpeername() on OpenBSD prior to 5.3 65 * return zero length and does not update a passed sockaddr 66 * buffer at all. 67 * 68 * Linux returns length equal to 2, i.e. sockaddr_un without 69 * sun_path[], unix(7): 70 * 71 * unnamed: A stream socket that has not been bound 72 * to a pathname using bind(2) has no name. Likewise, 73 * the two sockets created by socketpair(2) are unnamed. 74 * When the address of an unnamed socket is returned by 75 * getsockname(2), getpeername(2), and accept(2), its 76 * length is sizeof(sa_family_t), and sun_path should 77 * not be inspected. 78 */ 79 size = offsetof(struct sockaddr_un, sun_path) + 1; 80 81#if !(NXT_LINUX) 82 83 } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') { 84 /* 85 * Omit nonsignificant zeros of the unspecified Unix domain socket 86 * address. This test is disabled for Linux since Linux abstract 87 * socket address also starts with zero. However Linux unspecified 88 * Unix domain socket address is short and is handled above. 89 */ 90 size = offsetof(struct sockaddr_un, sun_path) + 1; 91 copy = size; 92 93#endif 94 } 95 96#endif /* NXT_HAVE_UNIX_DOMAIN */ 97 98 sa = nxt_sockaddr_alloc(mp, size); 99 100 if (nxt_fast_path(sa != NULL)) { 101 102 nxt_memcpy(&sa->u.sockaddr, sockaddr, copy); 103 104#if (NXT_SOCKADDR_SA_LEN) 105 106 /* Update shortcut sockaddr length overwritten by nxt_memcpy(). */ 107 nxt_socklen_set(sa, size); 108 109#endif 110 111#if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD) 112
| 50 51#if (NXT_HAVE_UNIX_DOMAIN) 52 53 /* 54 * Unspecified Unix domain sockaddr_un form and length are very 55 * platform depended (see comment in unix/socket.h). Here they are 56 * normalized to the sockaddr_un with single zero byte sun_path[]. 57 */ 58 59 if (size <= offsetof(struct sockaddr_un, sun_path)) { 60 /* 61 * Small socket length means a short unspecified Unix domain 62 * socket address: 63 * 64 * getsockname() and getpeername() on OpenBSD prior to 5.3 65 * return zero length and does not update a passed sockaddr 66 * buffer at all. 67 * 68 * Linux returns length equal to 2, i.e. sockaddr_un without 69 * sun_path[], unix(7): 70 * 71 * unnamed: A stream socket that has not been bound 72 * to a pathname using bind(2) has no name. Likewise, 73 * the two sockets created by socketpair(2) are unnamed. 74 * When the address of an unnamed socket is returned by 75 * getsockname(2), getpeername(2), and accept(2), its 76 * length is sizeof(sa_family_t), and sun_path should 77 * not be inspected. 78 */ 79 size = offsetof(struct sockaddr_un, sun_path) + 1; 80 81#if !(NXT_LINUX) 82 83 } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') { 84 /* 85 * Omit nonsignificant zeros of the unspecified Unix domain socket 86 * address. This test is disabled for Linux since Linux abstract 87 * socket address also starts with zero. However Linux unspecified 88 * Unix domain socket address is short and is handled above. 89 */ 90 size = offsetof(struct sockaddr_un, sun_path) + 1; 91 copy = size; 92 93#endif 94 } 95 96#endif /* NXT_HAVE_UNIX_DOMAIN */ 97 98 sa = nxt_sockaddr_alloc(mp, size); 99 100 if (nxt_fast_path(sa != NULL)) { 101 102 nxt_memcpy(&sa->u.sockaddr, sockaddr, copy); 103 104#if (NXT_SOCKADDR_SA_LEN) 105 106 /* Update shortcut sockaddr length overwritten by nxt_memcpy(). */ 107 nxt_socklen_set(sa, size); 108 109#endif 110 111#if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD) 112
|
113 if (len == 0) {
| 113 if (length == 0) {
|
114 sa->u.sockaddr.sa_family = AF_UNIX; 115 } 116 117#endif 118 } 119 120 return sa; 121} 122 123 124nxt_sockaddr_t * 125nxt_sockaddr_copy(nxt_mem_pool_t *mp, nxt_sockaddr_t *src) 126{
| 114 sa->u.sockaddr.sa_family = AF_UNIX; 115 } 116 117#endif 118 } 119 120 return sa; 121} 122 123 124nxt_sockaddr_t * 125nxt_sockaddr_copy(nxt_mem_pool_t *mp, nxt_sockaddr_t *src) 126{
|
127 size_t len;
| 127 size_t length;
|
128 nxt_sockaddr_t *dst; 129
| 128 nxt_sockaddr_t *dst; 129
|
130 len = offsetof(nxt_sockaddr_t, u) + nxt_socklen(src);
| 130 length = offsetof(nxt_sockaddr_t, u) + nxt_socklen(src);
|
131
| 131
|
132 dst = nxt_mem_alloc(mp, len);
| 132 dst = nxt_mem_alloc(mp, length);
|
133 134 if (nxt_fast_path(dst != NULL)) {
| 133 134 if (nxt_fast_path(dst != NULL)) {
|
135 nxt_memcpy(dst, src, len);
| 135 nxt_memcpy(dst, src, length);
|
136 } 137 138 return dst; 139} 140 141 142nxt_sockaddr_t * 143nxt_getsockname(nxt_mem_pool_t *mp, nxt_socket_t s) 144{ 145 int ret; 146 socklen_t socklen; 147 nxt_sockaddr_buf_t sockaddr; 148 149 socklen = NXT_SOCKADDR_LEN; 150 151 ret = getsockname(s, &sockaddr.buf, &socklen); 152 153 if (nxt_fast_path(ret == 0)) { 154 return nxt_sockaddr_create(mp, &sockaddr.buf, socklen); 155 } 156 157 nxt_thread_log_error(NXT_LOG_ERR, "getsockname(%d) failed %E", 158 s, nxt_errno); 159 160 return NULL; 161} 162 163 164nxt_int_t 165nxt_sockaddr_text(nxt_mem_pool_t *mp, nxt_sockaddr_t *sa, nxt_bool_t port) 166{
| 136 } 137 138 return dst; 139} 140 141 142nxt_sockaddr_t * 143nxt_getsockname(nxt_mem_pool_t *mp, nxt_socket_t s) 144{ 145 int ret; 146 socklen_t socklen; 147 nxt_sockaddr_buf_t sockaddr; 148 149 socklen = NXT_SOCKADDR_LEN; 150 151 ret = getsockname(s, &sockaddr.buf, &socklen); 152 153 if (nxt_fast_path(ret == 0)) { 154 return nxt_sockaddr_create(mp, &sockaddr.buf, socklen); 155 } 156 157 nxt_thread_log_error(NXT_LOG_ERR, "getsockname(%d) failed %E", 158 s, nxt_errno); 159 160 return NULL; 161} 162 163 164nxt_int_t 165nxt_sockaddr_text(nxt_mem_pool_t *mp, nxt_sockaddr_t *sa, nxt_bool_t port) 166{
|
167 size_t len;
| 167 size_t length;
|
168 u_char *p; 169 u_char buf[NXT_SOCKADDR_STR_LEN + NXT_SOCKPORT_STR_LEN]; 170
| 168 u_char *p; 169 u_char buf[NXT_SOCKADDR_STR_LEN + NXT_SOCKPORT_STR_LEN]; 170
|
171 len = NXT_SOCKADDR_STR_LEN + NXT_SOCKPORT_STR_LEN;
| 171 length = NXT_SOCKADDR_STR_LEN + NXT_SOCKPORT_STR_LEN;
|
172
| 172
|
173 len = nxt_sockaddr_ntop(sa, buf, buf + len, port);
| 173 length = nxt_sockaddr_ntop(sa, buf, buf + length, port);
|
174
| 174
|
175 p = nxt_mem_alloc(mp, len);
| 175 p = nxt_mem_alloc(mp, length);
|
176 177 if (nxt_fast_path(p != NULL)) { 178 179 sa->text = p;
| 176 177 if (nxt_fast_path(p != NULL)) { 178 179 sa->text = p;
|
180 sa->text_len = len; 181 nxt_memcpy(p, buf, len);
| 180 sa->text_len = length; 181 nxt_memcpy(p, buf, length);
|
182 183 return NXT_OK; 184 } 185 186 return NXT_ERROR; 187} 188 189 190uint32_t 191nxt_sockaddr_port(nxt_sockaddr_t *sa) 192{ 193 uint32_t port; 194 195 switch (sa->u.sockaddr.sa_family) { 196 197#if (NXT_INET6) 198 199 case AF_INET6: 200 port = sa->u.sockaddr_in6.sin6_port; 201 break; 202 203#endif 204 205#if (NXT_HAVE_UNIX_DOMAIN) 206 207 case AF_UNIX: 208 return 0; 209 210#endif 211 212 default: 213 port = sa->u.sockaddr_in.sin_port; 214 break; 215 } 216 217 return ntohs((uint16_t) port); 218} 219 220 221nxt_bool_t 222nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) 223{ 224 if (nxt_socklen(sa1) != nxt_socklen(sa2)) { 225 return 0; 226 } 227 228 if (sa1->type != sa2->type) { 229 return 0; 230 } 231 232 if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) { 233 return 0; 234 } 235 236 /* 237 * sockaddr struct's cannot be compared in whole since kernel 238 * may fill some fields in inherited sockaddr struct's. 239 */ 240 241 switch (sa1->u.sockaddr.sa_family) { 242 243#if (NXT_INET6) 244 245 case AF_INET6: 246 if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) { 247 return 0; 248 } 249 250 if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr, 251 &sa2->u.sockaddr_in6.sin6_addr, 16) 252 != 0) 253 { 254 return 0; 255 } 256 257 return 1; 258 259#endif 260 261#if (NXT_HAVE_UNIX_DOMAIN) 262 263 case AF_UNIX: 264 {
| 182 183 return NXT_OK; 184 } 185 186 return NXT_ERROR; 187} 188 189 190uint32_t 191nxt_sockaddr_port(nxt_sockaddr_t *sa) 192{ 193 uint32_t port; 194 195 switch (sa->u.sockaddr.sa_family) { 196 197#if (NXT_INET6) 198 199 case AF_INET6: 200 port = sa->u.sockaddr_in6.sin6_port; 201 break; 202 203#endif 204 205#if (NXT_HAVE_UNIX_DOMAIN) 206 207 case AF_UNIX: 208 return 0; 209 210#endif 211 212 default: 213 port = sa->u.sockaddr_in.sin_port; 214 break; 215 } 216 217 return ntohs((uint16_t) port); 218} 219 220 221nxt_bool_t 222nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) 223{ 224 if (nxt_socklen(sa1) != nxt_socklen(sa2)) { 225 return 0; 226 } 227 228 if (sa1->type != sa2->type) { 229 return 0; 230 } 231 232 if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) { 233 return 0; 234 } 235 236 /* 237 * sockaddr struct's cannot be compared in whole since kernel 238 * may fill some fields in inherited sockaddr struct's. 239 */ 240 241 switch (sa1->u.sockaddr.sa_family) { 242 243#if (NXT_INET6) 244 245 case AF_INET6: 246 if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) { 247 return 0; 248 } 249 250 if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr, 251 &sa2->u.sockaddr_in6.sin6_addr, 16) 252 != 0) 253 { 254 return 0; 255 } 256 257 return 1; 258 259#endif 260 261#if (NXT_HAVE_UNIX_DOMAIN) 262 263 case AF_UNIX: 264 {
|
265 size_t len;
| 265 size_t length;
|
266
| 266
|
267 len = nxt_socklen(sa1) - offsetof(struct sockaddr_un, sun_path);
| 267 length = nxt_socklen(sa1) - offsetof(struct sockaddr_un, sun_path);
|
268 269 if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path,
| 268 269 if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path,
|
270 &sa2->u.sockaddr_un.sun_path, len)
| 270 &sa2->u.sockaddr_un.sun_path, length)
|
271 != 0) 272 { 273 return 0; 274 } 275 276 return 1; 277 } 278 279#endif 280 281 default: /* AF_INET */ 282 if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) { 283 return 0; 284 } 285 286 if (sa1->u.sockaddr_in.sin_addr.s_addr 287 != sa2->u.sockaddr_in.sin_addr.s_addr) 288 { 289 return 0; 290 } 291 292 return 1; 293 } 294} 295 296 297size_t 298nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port) 299{ 300 u_char *p; 301 302 switch (sa->u.sockaddr.sa_family) { 303 304 case AF_INET: 305 p = (u_char *) &sa->u.sockaddr_in.sin_addr; 306 307 if (port) { 308 p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d", 309 p[0], p[1], p[2], p[3], 310 ntohs(sa->u.sockaddr_in.sin_port)); 311 } else { 312 p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud", 313 p[0], p[1], p[2], p[3]); 314 } 315 316 return p - buf; 317 318#if (NXT_INET6) 319 320 case AF_INET6: 321 p = buf; 322 323 if (port) { 324 *p++ = '['; 325 } 326 327 p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 328 329 if (port) { 330 p = nxt_sprintf(p, end, "]:%d", 331 ntohs(sa->u.sockaddr_in6.sin6_port)); 332 } 333 334 return p - buf; 335#endif 336 337#if (NXT_HAVE_UNIX_DOMAIN) 338 339 case AF_UNIX: 340 341#if (NXT_LINUX) 342 343 p = (u_char *) sa->u.sockaddr_un.sun_path; 344 345 if (p[0] == '\0') {
| 271 != 0) 272 { 273 return 0; 274 } 275 276 return 1; 277 } 278 279#endif 280 281 default: /* AF_INET */ 282 if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) { 283 return 0; 284 } 285 286 if (sa1->u.sockaddr_in.sin_addr.s_addr 287 != sa2->u.sockaddr_in.sin_addr.s_addr) 288 { 289 return 0; 290 } 291 292 return 1; 293 } 294} 295 296 297size_t 298nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port) 299{ 300 u_char *p; 301 302 switch (sa->u.sockaddr.sa_family) { 303 304 case AF_INET: 305 p = (u_char *) &sa->u.sockaddr_in.sin_addr; 306 307 if (port) { 308 p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d", 309 p[0], p[1], p[2], p[3], 310 ntohs(sa->u.sockaddr_in.sin_port)); 311 } else { 312 p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud", 313 p[0], p[1], p[2], p[3]); 314 } 315 316 return p - buf; 317 318#if (NXT_INET6) 319 320 case AF_INET6: 321 p = buf; 322 323 if (port) { 324 *p++ = '['; 325 } 326 327 p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 328 329 if (port) { 330 p = nxt_sprintf(p, end, "]:%d", 331 ntohs(sa->u.sockaddr_in6.sin6_port)); 332 } 333 334 return p - buf; 335#endif 336 337#if (NXT_HAVE_UNIX_DOMAIN) 338 339 case AF_UNIX: 340 341#if (NXT_LINUX) 342 343 p = (u_char *) sa->u.sockaddr_un.sun_path; 344 345 if (p[0] == '\0') {
|
346 int len;
| 346 int length;
|
347 348 /* Linux abstract socket address has no trailing zero. */ 349
| 347 348 /* Linux abstract socket address has no trailing zero. */ 349
|
350 len = nxt_socklen(sa) - offsetof(struct sockaddr_un, sun_path) - 1; 351 p = nxt_sprintf(buf, end, "unix:\\0%*s", len, p + 1);
| 350 length = nxt_socklen(sa) 351 - offsetof(struct sockaddr_un, sun_path) - 1; 352 p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1);
|
352 353 } else { 354 p = nxt_sprintf(buf, end, "unix:%s", p); 355 } 356 357#else /* !(NXT_LINUX) */ 358 359 p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path); 360 361#endif 362 363 return p - buf; 364 365#endif /* NXT_HAVE_UNIX_DOMAIN */ 366 367 default: 368 return 0; 369 } 370} 371 372 373#if (NXT_INET6) 374 375static u_char * 376nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end) 377{ 378 u_char *p; 379 size_t zero_groups, last_zero_groups, ipv6_bytes; 380 nxt_uint_t i, zero_start, last_zero_start; 381 382 if (buf + NXT_INET6_ADDR_STR_LEN > end) { 383 return buf; 384 } 385 386 zero_start = 8; 387 zero_groups = 0; 388 last_zero_start = 8; 389 last_zero_groups = 0; 390 391 for (i = 0; i < 16; i += 2) { 392 393 if (addr[i] == 0 && addr[i + 1] == 0) { 394 395 if (last_zero_groups == 0) { 396 last_zero_start = i; 397 } 398 399 last_zero_groups++; 400 401 } else { 402 if (zero_groups < last_zero_groups) { 403 zero_groups = last_zero_groups; 404 zero_start = last_zero_start; 405 } 406 407 last_zero_groups = 0; 408 } 409 } 410 411 if (zero_groups < last_zero_groups) { 412 zero_groups = last_zero_groups; 413 zero_start = last_zero_start; 414 } 415 416 ipv6_bytes = 16; 417 p = buf; 418 419 if (zero_start == 0) { 420 421 /* IPv4-mapped address */ 422 if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff) 423 /* IPv4-compatible address */ 424 || (zero_groups == 6) 425 /* not IPv6 loopback address */ 426 || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1)) 427 { 428 ipv6_bytes = 12; 429 } 430 431 *p++ = ':'; 432 } 433 434 for (i = 0; i < ipv6_bytes; i += 2) { 435 436 if (i == zero_start) { 437 /* Output maximum number of consecutive zero groups as "::". */ 438 i += (zero_groups - 1) * 2; 439 *p++ = ':'; 440 continue; 441 } 442 443 p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]); 444 445 if (i < 14) { 446 *p++ = ':'; 447 } 448 } 449 450 if (ipv6_bytes == 12) { 451 p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud", 452 addr[12], addr[13], addr[14], addr[15]); 453 } 454 455 return p; 456} 457 458#endif 459 460 461void 462nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs) 463{ 464 u_char *p;
| 353 354 } else { 355 p = nxt_sprintf(buf, end, "unix:%s", p); 356 } 357 358#else /* !(NXT_LINUX) */ 359 360 p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path); 361 362#endif 363 364 return p - buf; 365 366#endif /* NXT_HAVE_UNIX_DOMAIN */ 367 368 default: 369 return 0; 370 } 371} 372 373 374#if (NXT_INET6) 375 376static u_char * 377nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end) 378{ 379 u_char *p; 380 size_t zero_groups, last_zero_groups, ipv6_bytes; 381 nxt_uint_t i, zero_start, last_zero_start; 382 383 if (buf + NXT_INET6_ADDR_STR_LEN > end) { 384 return buf; 385 } 386 387 zero_start = 8; 388 zero_groups = 0; 389 last_zero_start = 8; 390 last_zero_groups = 0; 391 392 for (i = 0; i < 16; i += 2) { 393 394 if (addr[i] == 0 && addr[i + 1] == 0) { 395 396 if (last_zero_groups == 0) { 397 last_zero_start = i; 398 } 399 400 last_zero_groups++; 401 402 } else { 403 if (zero_groups < last_zero_groups) { 404 zero_groups = last_zero_groups; 405 zero_start = last_zero_start; 406 } 407 408 last_zero_groups = 0; 409 } 410 } 411 412 if (zero_groups < last_zero_groups) { 413 zero_groups = last_zero_groups; 414 zero_start = last_zero_start; 415 } 416 417 ipv6_bytes = 16; 418 p = buf; 419 420 if (zero_start == 0) { 421 422 /* IPv4-mapped address */ 423 if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff) 424 /* IPv4-compatible address */ 425 || (zero_groups == 6) 426 /* not IPv6 loopback address */ 427 || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1)) 428 { 429 ipv6_bytes = 12; 430 } 431 432 *p++ = ':'; 433 } 434 435 for (i = 0; i < ipv6_bytes; i += 2) { 436 437 if (i == zero_start) { 438 /* Output maximum number of consecutive zero groups as "::". */ 439 i += (zero_groups - 1) * 2; 440 *p++ = ':'; 441 continue; 442 } 443 444 p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]); 445 446 if (i < 14) { 447 *p++ = ':'; 448 } 449 } 450 451 if (ipv6_bytes == 12) { 452 p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud", 453 addr[12], addr[13], addr[14], addr[15]); 454 } 455 456 return p; 457} 458 459#endif 460 461 462void 463nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs) 464{ 465 u_char *p;
|
465 size_t len;
| 466 size_t length;
|
466 nxt_int_t ret; 467 nxt_work_handler_t handler; 468 469 nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse"); 470
| 467 nxt_int_t ret; 468 nxt_work_handler_t handler; 469 470 nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse"); 471
|
471 len = jbs->addr.len; 472 p = jbs->addr.data;
| 472 length = jbs->addr.length; 473 p = jbs->addr.start;
|
473
| 474
|
474 if (len > 6 && nxt_memcmp(p, (u_char *) "unix:", 5) == 0) {
| 475 if (length > 6 && nxt_memcmp(p, (u_char *) "unix:", 5) == 0) {
|
475 ret = nxt_job_sockaddr_unix_parse(jbs); 476
| 476 ret = nxt_job_sockaddr_unix_parse(jbs); 477
|
477 } else if (len != 0 && *p == '[') {
| 478 } else if (length != 0 && *p == '[') {
|
478 ret = nxt_job_sockaddr_inet6_parse(jbs); 479 480 } else { 481 ret = nxt_job_sockaddr_inet_parse(jbs); 482 } 483 484 switch (ret) { 485 486 case NXT_OK: 487 handler = jbs->resolve.ready_handler; 488 break; 489 490 case NXT_ERROR: 491 handler = jbs->resolve.error_handler; 492 break; 493 494 default: /* NXT_AGAIN */ 495 return; 496 } 497 498 nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler); 499} 500 501 502static nxt_int_t 503nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs) 504{ 505#if (NXT_HAVE_UNIX_DOMAIN)
| 479 ret = nxt_job_sockaddr_inet6_parse(jbs); 480 481 } else { 482 ret = nxt_job_sockaddr_inet_parse(jbs); 483 } 484 485 switch (ret) { 486 487 case NXT_OK: 488 handler = jbs->resolve.ready_handler; 489 break; 490 491 case NXT_ERROR: 492 handler = jbs->resolve.error_handler; 493 break; 494 495 default: /* NXT_AGAIN */ 496 return; 497 } 498 499 nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler); 500} 501 502 503static nxt_int_t 504nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs) 505{ 506#if (NXT_HAVE_UNIX_DOMAIN)
|
506 size_t len, socklen;
| 507 size_t length, socklen;
|
507 u_char *path; 508 nxt_mem_pool_t *mp; 509 nxt_sockaddr_t *sa; 510 511 /* 512 * Actual sockaddr_un length can be lesser or even larger than defined 513 * struct sockaddr_un length (see comment in unix/nxt_socket.h). So 514 * limit maximum Unix domain socket address length by defined sun_path[] 515 * length because some OSes accept addresses twice larger than defined 516 * struct sockaddr_un. Also reserve space for a trailing zero to avoid 517 * ambiguity, since many OSes accept Unix domain socket addresses 518 * without a trailing zero. 519 */ 520 const size_t max_len = sizeof(struct sockaddr_un) 521 - offsetof(struct sockaddr_un, sun_path) - 1; 522 523 /* cutting "unix:" */
| 508 u_char *path; 509 nxt_mem_pool_t *mp; 510 nxt_sockaddr_t *sa; 511 512 /* 513 * Actual sockaddr_un length can be lesser or even larger than defined 514 * struct sockaddr_un length (see comment in unix/nxt_socket.h). So 515 * limit maximum Unix domain socket address length by defined sun_path[] 516 * length because some OSes accept addresses twice larger than defined 517 * struct sockaddr_un. Also reserve space for a trailing zero to avoid 518 * ambiguity, since many OSes accept Unix domain socket addresses 519 * without a trailing zero. 520 */ 521 const size_t max_len = sizeof(struct sockaddr_un) 522 - offsetof(struct sockaddr_un, sun_path) - 1; 523 524 /* cutting "unix:" */
|
524 len = jbs->addr.len - 5; 525 path = jbs->addr.data + 5;
| 525 length = jbs->addr.length - 5; 526 path = jbs->addr.start + 5;
|
526
| 527
|
527 if (len > max_len) {
| 528 if (length > max_len) {
|
528 nxt_thread_log_error(jbs->resolve.log_level, 529 "unix domain socket \"%V\" name is too long", 530 &jbs->addr); 531 return NXT_ERROR; 532 } 533
| 529 nxt_thread_log_error(jbs->resolve.log_level, 530 "unix domain socket \"%V\" name is too long", 531 &jbs->addr); 532 return NXT_ERROR; 533 } 534
|
534 socklen = offsetof(struct sockaddr_un, sun_path) + len + 1;
| 535 socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
|
535 536#if (NXT_LINUX) 537 538 /* 539 * Linux unix(7): 540 * 541 * abstract: an abstract socket address is distinguished by the fact 542 * that sun_path[0] is a null byte ('\0'). The socket's address in 543 * this namespace is given by the additional bytes in sun_path that 544 * are covered by the specified length of the address structure. 545 * (Null bytes in the name have no special significance.) 546 */ 547 if (path[0] == '\0') { 548 socklen--; 549 } 550 551#endif 552 553 mp = jbs->resolve.job.mem_pool; 554 555 jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 556 557 if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) { 558 sa = nxt_sockaddr_alloc(mp, socklen); 559 560 if (nxt_fast_path(sa != NULL)) { 561 jbs->resolve.count = 1; 562 jbs->resolve.sockaddrs[0] = sa; 563 564 sa->u.sockaddr_un.sun_family = AF_UNIX;
| 536 537#if (NXT_LINUX) 538 539 /* 540 * Linux unix(7): 541 * 542 * abstract: an abstract socket address is distinguished by the fact 543 * that sun_path[0] is a null byte ('\0'). The socket's address in 544 * this namespace is given by the additional bytes in sun_path that 545 * are covered by the specified length of the address structure. 546 * (Null bytes in the name have no special significance.) 547 */ 548 if (path[0] == '\0') { 549 socklen--; 550 } 551 552#endif 553 554 mp = jbs->resolve.job.mem_pool; 555 556 jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 557 558 if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) { 559 sa = nxt_sockaddr_alloc(mp, socklen); 560 561 if (nxt_fast_path(sa != NULL)) { 562 jbs->resolve.count = 1; 563 jbs->resolve.sockaddrs[0] = sa; 564 565 sa->u.sockaddr_un.sun_family = AF_UNIX;
|
565 nxt_memcpy(sa->u.sockaddr_un.sun_path, path, len);
| 566 nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
|
566 567 return NXT_OK; 568 } 569 } 570 571 return NXT_ERROR; 572 573#else /* !(NXT_HAVE_UNIX_DOMAIN) */ 574 575 nxt_thread_log_error(jbs->resolve.log_level, 576 "unix domain socket \"%V\" is not supported", 577 &jbs->addr); 578 return NXT_ERROR; 579 580#endif 581} 582 583 584static nxt_int_t 585nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs) 586{ 587#if (NXT_INET6) 588 u_char *p, *addr, *addr_end;
| 567 568 return NXT_OK; 569 } 570 } 571 572 return NXT_ERROR; 573 574#else /* !(NXT_HAVE_UNIX_DOMAIN) */ 575 576 nxt_thread_log_error(jbs->resolve.log_level, 577 "unix domain socket \"%V\" is not supported", 578 &jbs->addr); 579 return NXT_ERROR; 580 581#endif 582} 583 584 585static nxt_int_t 586nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs) 587{ 588#if (NXT_INET6) 589 u_char *p, *addr, *addr_end;
|
589 size_t len;
| 590 size_t length;
|
590 nxt_int_t port; 591 nxt_mem_pool_t *mp; 592 nxt_sockaddr_t *sa; 593 struct in6_addr *in6_addr; 594
| 591 nxt_int_t port; 592 nxt_mem_pool_t *mp; 593 nxt_sockaddr_t *sa; 594 struct in6_addr *in6_addr; 595
|
595 len = jbs->addr.len - 1; 596 addr = jbs->addr.data + 1;
| 596 length = jbs->addr.length - 1; 597 addr = jbs->addr.start + 1;
|
597
| 598
|
598 addr_end = nxt_memchr(addr, ']', len);
| 599 addr_end = nxt_memchr(addr, ']', length);
|
599 600 if (addr_end == NULL) { 601 goto invalid_address; 602 } 603 604 mp = jbs->resolve.job.mem_pool; 605 606 jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 607 608 if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 609 return NXT_ERROR; 610 } 611 612 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6)); 613 614 if (nxt_slow_path(sa == NULL)) { 615 return NXT_ERROR; 616 } 617 618 jbs->resolve.count = 1; 619 jbs->resolve.sockaddrs[0] = sa; 620 621 in6_addr = &sa->u.sockaddr_in6.sin6_addr; 622 623 if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) { 624 goto invalid_address; 625 } 626 627 p = addr_end + 1;
| 600 601 if (addr_end == NULL) { 602 goto invalid_address; 603 } 604 605 mp = jbs->resolve.job.mem_pool; 606 607 jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 608 609 if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 610 return NXT_ERROR; 611 } 612 613 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6)); 614 615 if (nxt_slow_path(sa == NULL)) { 616 return NXT_ERROR; 617 } 618 619 jbs->resolve.count = 1; 620 jbs->resolve.sockaddrs[0] = sa; 621 622 in6_addr = &sa->u.sockaddr_in6.sin6_addr; 623 624 if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) { 625 goto invalid_address; 626 } 627 628 p = addr_end + 1;
|
628 len = (addr + len) - p;
| 629 length = (addr + length) - p;
|
629
| 630
|
630 if (len == 0) {
| 631 if (length == 0) {
|
631 jbs->no_port = 1; 632 port = jbs->resolve.port; 633 goto found; 634 } 635 636 if (*p == ':') {
| 632 jbs->no_port = 1; 633 port = jbs->resolve.port; 634 goto found; 635 } 636 637 if (*p == ':') {
|
637 port = nxt_int_parse(p + 1, len - 1);
| 638 port = nxt_int_parse(p + 1, length - 1);
|
638 639 if (port >= 1 && port <= 65535) { 640 port = htons((in_port_t) port); 641 goto found; 642 } 643 } 644 645 nxt_thread_log_error(jbs->resolve.log_level, 646 "invalid port in \"%V\"", &jbs->addr); 647 648 return NXT_ERROR; 649 650found: 651 652 sa->u.sockaddr_in6.sin6_family = AF_INET6; 653 sa->u.sockaddr_in6.sin6_port = (in_port_t) port; 654 655 if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) { 656 jbs->wildcard = 1; 657 } 658 659 return NXT_OK; 660 661invalid_address: 662 663 nxt_thread_log_error(jbs->resolve.log_level, 664 "invalid IPv6 address in \"%V\"", &jbs->addr); 665 return NXT_ERROR; 666 667#else 668 669 nxt_thread_log_error(jbs->resolve.log_level, 670 "IPv6 socket \"%V\" is not supported", &jbs->addr); 671 return NXT_ERROR; 672 673#endif 674} 675 676 677static nxt_int_t 678nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs) 679{ 680 u_char *p, *host;
| 639 640 if (port >= 1 && port <= 65535) { 641 port = htons((in_port_t) port); 642 goto found; 643 } 644 } 645 646 nxt_thread_log_error(jbs->resolve.log_level, 647 "invalid port in \"%V\"", &jbs->addr); 648 649 return NXT_ERROR; 650 651found: 652 653 sa->u.sockaddr_in6.sin6_family = AF_INET6; 654 sa->u.sockaddr_in6.sin6_port = (in_port_t) port; 655 656 if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) { 657 jbs->wildcard = 1; 658 } 659 660 return NXT_OK; 661 662invalid_address: 663 664 nxt_thread_log_error(jbs->resolve.log_level, 665 "invalid IPv6 address in \"%V\"", &jbs->addr); 666 return NXT_ERROR; 667 668#else 669 670 nxt_thread_log_error(jbs->resolve.log_level, 671 "IPv6 socket \"%V\" is not supported", &jbs->addr); 672 return NXT_ERROR; 673 674#endif 675} 676 677 678static nxt_int_t 679nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs) 680{ 681 u_char *p, *host;
|
681 size_t len;
| 682 size_t length;
|
682 in_addr_t addr; 683 nxt_int_t port; 684 nxt_mem_pool_t *mp; 685 nxt_sockaddr_t *sa; 686 687 addr = INADDR_ANY; 688
| 683 in_addr_t addr; 684 nxt_int_t port; 685 nxt_mem_pool_t *mp; 686 nxt_sockaddr_t *sa; 687 688 addr = INADDR_ANY; 689
|
689 len = jbs->addr.len; 690 host = jbs->addr.data;
| 690 length = jbs->addr.length; 691 host = jbs->addr.start;
|
691
| 692
|
692 p = nxt_memchr(host, ':', len);
| 693 p = nxt_memchr(host, ':', length);
|
693 694 if (p == NULL) { 695 696 /* single value port, address, or host name */ 697
| 694 695 if (p == NULL) { 696 697 /* single value port, address, or host name */ 698
|
698 port = nxt_int_parse(host, len);
| 699 port = nxt_int_parse(host, length);
|
699 700 if (port > 0) { 701 if (port < 1 || port > 65535) { 702 goto invalid_port; 703 } 704 705 /* "*:XX" */ 706 port = htons((in_port_t) port); 707 jbs->resolve.port = (in_port_t) port; 708 709 } else { 710 jbs->no_port = 1; 711
| 700 701 if (port > 0) { 702 if (port < 1 || port > 65535) { 703 goto invalid_port; 704 } 705 706 /* "*:XX" */ 707 port = htons((in_port_t) port); 708 jbs->resolve.port = (in_port_t) port; 709 710 } else { 711 jbs->no_port = 1; 712
|
712 addr = nxt_inet_addr(host, len);
| 713 addr = nxt_inet_addr(host, length);
|
713 714 if (addr == INADDR_NONE) {
| 714 715 if (addr == INADDR_NONE) {
|
715 jbs->resolve.name.len = len; 716 jbs->resolve.name.data = host;
| 716 jbs->resolve.name.length = length; 717 jbs->resolve.name.start = host;
|
717 718 nxt_job_resolve(&jbs->resolve); 719 return NXT_AGAIN; 720 } 721 722 /* "x.x.x.x" */ 723 port = jbs->resolve.port; 724 } 725 726 } else { 727 728 /* x.x.x.x:XX or host:XX */ 729 730 p++;
| 718 719 nxt_job_resolve(&jbs->resolve); 720 return NXT_AGAIN; 721 } 722 723 /* "x.x.x.x" */ 724 port = jbs->resolve.port; 725 } 726 727 } else { 728 729 /* x.x.x.x:XX or host:XX */ 730 731 p++;
|
731 len = (host + len) - p; 732 port = nxt_int_parse(p, len);
| 732 length = (host + length) - p; 733 port = nxt_int_parse(p, length);
|
733 734 if (port < 1 || port > 65535) { 735 goto invalid_port; 736 } 737 738 port = htons((in_port_t) port); 739
| 734 735 if (port < 1 || port > 65535) { 736 goto invalid_port; 737 } 738 739 port = htons((in_port_t) port); 740
|
740 len = (p - 1) - host;
| 741 length = (p - 1) - host;
|
741
| 742
|
742 if (len != 1 || host[0] != '*') { 743 addr = nxt_inet_addr(host, len);
| 743 if (length != 1 || host[0] != '*') { 744 addr = nxt_inet_addr(host, length);
|
744 745 if (addr == INADDR_NONE) {
| 745 746 if (addr == INADDR_NONE) {
|
746 jbs->resolve.name.len = len; 747 jbs->resolve.name.data = host;
| 747 jbs->resolve.name.length = length; 748 jbs->resolve.name.start = host;
|
748 jbs->resolve.port = (in_port_t) port; 749 750 nxt_job_resolve(&jbs->resolve); 751 return NXT_AGAIN; 752 } 753 754 /* "x.x.x.x:XX" */ 755 } 756 } 757 758 mp = jbs->resolve.job.mem_pool; 759 760 jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 761 if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 762 return NXT_ERROR; 763 } 764 765 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in)); 766 767 if (nxt_fast_path(sa != NULL)) { 768 jbs->resolve.count = 1; 769 jbs->resolve.sockaddrs[0] = sa; 770 771 jbs->wildcard = (addr == INADDR_ANY); 772 773 sa->u.sockaddr_in.sin_family = AF_INET; 774 sa->u.sockaddr_in.sin_port = (in_port_t) port; 775 sa->u.sockaddr_in.sin_addr.s_addr = addr; 776 777 return NXT_OK; 778 } 779 780 return NXT_ERROR; 781 782invalid_port: 783 784 nxt_thread_log_error(jbs->resolve.log_level, 785 "invalid port in \"%V\"", &jbs->addr); 786 787 return NXT_ERROR; 788} 789 790 791in_addr_t
| 749 jbs->resolve.port = (in_port_t) port; 750 751 nxt_job_resolve(&jbs->resolve); 752 return NXT_AGAIN; 753 } 754 755 /* "x.x.x.x:XX" */ 756 } 757 } 758 759 mp = jbs->resolve.job.mem_pool; 760 761 jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 762 if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 763 return NXT_ERROR; 764 } 765 766 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in)); 767 768 if (nxt_fast_path(sa != NULL)) { 769 jbs->resolve.count = 1; 770 jbs->resolve.sockaddrs[0] = sa; 771 772 jbs->wildcard = (addr == INADDR_ANY); 773 774 sa->u.sockaddr_in.sin_family = AF_INET; 775 sa->u.sockaddr_in.sin_port = (in_port_t) port; 776 sa->u.sockaddr_in.sin_addr.s_addr = addr; 777 778 return NXT_OK; 779 } 780 781 return NXT_ERROR; 782 783invalid_port: 784 785 nxt_thread_log_error(jbs->resolve.log_level, 786 "invalid port in \"%V\"", &jbs->addr); 787 788 return NXT_ERROR; 789} 790 791 792in_addr_t
|
792nxt_inet_addr(u_char *buf, size_t len)
| 793nxt_inet_addr(u_char *buf, size_t length)
|
793{ 794 u_char c, *end; 795 in_addr_t addr; 796 nxt_uint_t digit, octet, dots; 797 798 addr = 0; 799 octet = 0; 800 dots = 0; 801
| 794{ 795 u_char c, *end; 796 in_addr_t addr; 797 nxt_uint_t digit, octet, dots; 798 799 addr = 0; 800 octet = 0; 801 dots = 0; 802
|
802 end = buf + len;
| 803 end = buf + length;
|
803 804 while (buf < end) { 805 806 c = *buf++; 807 808 digit = c - '0'; 809 /* values below '0' become large unsigned integers */ 810 811 if (digit < 10) { 812 octet = octet * 10 + digit; 813 continue; 814 } 815 816 if (c == '.' && octet < 256) { 817 addr = (addr << 8) + octet; 818 octet = 0; 819 dots++; 820 continue; 821 } 822 823 return INADDR_NONE; 824 } 825 826 if (dots == 3 && octet < 256) { 827 addr = (addr << 8) + octet; 828 return htonl(addr); 829 } 830 831 return INADDR_NONE; 832} 833 834 835#if (NXT_INET6) 836 837nxt_int_t
| 804 805 while (buf < end) { 806 807 c = *buf++; 808 809 digit = c - '0'; 810 /* values below '0' become large unsigned integers */ 811 812 if (digit < 10) { 813 octet = octet * 10 + digit; 814 continue; 815 } 816 817 if (c == '.' && octet < 256) { 818 addr = (addr << 8) + octet; 819 octet = 0; 820 dots++; 821 continue; 822 } 823 824 return INADDR_NONE; 825 } 826 827 if (dots == 3 && octet < 256) { 828 addr = (addr << 8) + octet; 829 return htonl(addr); 830 } 831 832 return INADDR_NONE; 833} 834 835 836#if (NXT_INET6) 837 838nxt_int_t
|
838nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t len)
| 839nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length)
|
839{ 840 u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end; 841 nxt_uint_t digit, group, nibbles, groups_left; 842
| 840{ 841 u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end; 842 nxt_uint_t digit, group, nibbles, groups_left; 843
|
843 if (len == 0) {
| 844 if (length == 0) {
|
844 return NXT_ERROR; 845 } 846
| 845 return NXT_ERROR; 846 } 847
|
847 end = buf + len;
| 848 end = buf + length;
|
848 849 if (buf[0] == ':') { 850 buf++; 851 } 852 853 addr = in6_addr->s6_addr; 854 zero_start = NULL; 855 groups_left = 8; 856 nibbles = 0; 857 group = 0; 858 ipv4 = NULL; 859 860 while (buf < end) { 861 c = *buf++; 862 863 if (c == ':') { 864 if (nibbles != 0) { 865 ipv4 = buf; 866 867 *addr++ = (u_char) (group >> 8); 868 *addr++ = (u_char) (group & 0xff); 869 groups_left--; 870 871 if (groups_left != 0) { 872 nibbles = 0; 873 group = 0; 874 continue; 875 } 876 877 } else { 878 if (zero_start == NULL) { 879 ipv4 = buf; 880 zero_start = addr; 881 continue; 882 } 883 } 884 885 return NXT_ERROR; 886 } 887 888 if (c == '.' && nibbles != 0) { 889 890 if (groups_left < 2 || ipv4 == NULL) { 891 return NXT_ERROR; 892 } 893 894 group = nxt_inet_addr(ipv4, end - ipv4); 895 if (group == INADDR_NONE) { 896 return NXT_ERROR; 897 } 898 899 group = ntohl(group); 900 901 *addr++ = (u_char) ((group >> 24) & 0xff); 902 *addr++ = (u_char) ((group >> 16) & 0xff); 903 groups_left--; 904 905 /* the low 16-bit are copied below */ 906 break; 907 } 908 909 nibbles++; 910 911 if (nibbles > 4) { 912 return NXT_ERROR; 913 } 914 915 group <<= 4; 916 917 digit = c - '0'; 918 /* values below '0' become large unsigned integers */ 919 920 if (digit < 10) { 921 group += digit; 922 continue; 923 } 924 925 c |= 0x20; 926 digit = c - 'a'; 927 /* values below 'a' become large unsigned integers */ 928 929 if (digit < 6) { 930 group += 10 + digit; 931 continue; 932 } 933 934 return NXT_ERROR; 935 } 936 937 if (nibbles == 0 && zero_start == NULL) { 938 return NXT_ERROR; 939 } 940 941 *addr++ = (u_char) (group >> 8); 942 *addr++ = (u_char) (group & 0xff); 943 groups_left--; 944 945 if (groups_left != 0) { 946 947 if (zero_start != NULL) { 948 949 /* moving part before consecutive zero groups to the end */ 950 951 groups_left *= 2; 952 src = addr - 1; 953 dst = src + groups_left; 954 955 while (src >= zero_start) { 956 *dst-- = *src--; 957 } 958 959 nxt_memzero(zero_start, groups_left); 960 961 return NXT_OK; 962 } 963 964 } else { 965 if (zero_start == NULL) { 966 return NXT_OK; 967 } 968 } 969 970 return NXT_ERROR; 971} 972 973#endif
| 849 850 if (buf[0] == ':') { 851 buf++; 852 } 853 854 addr = in6_addr->s6_addr; 855 zero_start = NULL; 856 groups_left = 8; 857 nibbles = 0; 858 group = 0; 859 ipv4 = NULL; 860 861 while (buf < end) { 862 c = *buf++; 863 864 if (c == ':') { 865 if (nibbles != 0) { 866 ipv4 = buf; 867 868 *addr++ = (u_char) (group >> 8); 869 *addr++ = (u_char) (group & 0xff); 870 groups_left--; 871 872 if (groups_left != 0) { 873 nibbles = 0; 874 group = 0; 875 continue; 876 } 877 878 } else { 879 if (zero_start == NULL) { 880 ipv4 = buf; 881 zero_start = addr; 882 continue; 883 } 884 } 885 886 return NXT_ERROR; 887 } 888 889 if (c == '.' && nibbles != 0) { 890 891 if (groups_left < 2 || ipv4 == NULL) { 892 return NXT_ERROR; 893 } 894 895 group = nxt_inet_addr(ipv4, end - ipv4); 896 if (group == INADDR_NONE) { 897 return NXT_ERROR; 898 } 899 900 group = ntohl(group); 901 902 *addr++ = (u_char) ((group >> 24) & 0xff); 903 *addr++ = (u_char) ((group >> 16) & 0xff); 904 groups_left--; 905 906 /* the low 16-bit are copied below */ 907 break; 908 } 909 910 nibbles++; 911 912 if (nibbles > 4) { 913 return NXT_ERROR; 914 } 915 916 group <<= 4; 917 918 digit = c - '0'; 919 /* values below '0' become large unsigned integers */ 920 921 if (digit < 10) { 922 group += digit; 923 continue; 924 } 925 926 c |= 0x20; 927 digit = c - 'a'; 928 /* values below 'a' become large unsigned integers */ 929 930 if (digit < 6) { 931 group += 10 + digit; 932 continue; 933 } 934 935 return NXT_ERROR; 936 } 937 938 if (nibbles == 0 && zero_start == NULL) { 939 return NXT_ERROR; 940 } 941 942 *addr++ = (u_char) (group >> 8); 943 *addr++ = (u_char) (group & 0xff); 944 groups_left--; 945 946 if (groups_left != 0) { 947 948 if (zero_start != NULL) { 949 950 /* moving part before consecutive zero groups to the end */ 951 952 groups_left *= 2; 953 src = addr - 1; 954 dst = src + groups_left; 955 956 while (src >= zero_start) { 957 *dst-- = *src--; 958 } 959 960 nxt_memzero(zero_start, groups_left); 961 962 return NXT_OK; 963 } 964 965 } else { 966 if (zero_start == NULL) { 967 return NXT_OK; 968 } 969 } 970 971 return NXT_ERROR; 972} 973 974#endif
|