10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru 90Sigor@sysoev.ru 100Sigor@sysoev.ru #if (NXT_INET6) 110Sigor@sysoev.ru static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end); 120Sigor@sysoev.ru #endif 130Sigor@sysoev.ru 140Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs); 150Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs); 160Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs); 170Sigor@sysoev.ru 180Sigor@sysoev.ru 190Sigor@sysoev.ru nxt_sockaddr_t * 20*65Sigor@sysoev.ru nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length) 210Sigor@sysoev.ru { 2213Sigor@sysoev.ru size_t size; 230Sigor@sysoev.ru nxt_sockaddr_t *sa; 240Sigor@sysoev.ru 2513Sigor@sysoev.ru size = offsetof(nxt_sockaddr_t, u) + socklen + address_length; 2613Sigor@sysoev.ru 270Sigor@sysoev.ru /* 280Sigor@sysoev.ru * The current struct sockaddr's define 32-bit fields at maximum 290Sigor@sysoev.ru * and may define 64-bit AF_INET6 fields in the future. Alignment 30*65Sigor@sysoev.ru * of memory allocated by nxt_mp_zalloc() is enough for these fields. 310Sigor@sysoev.ru * If 128-bit alignment will be required then nxt_mem_malloc() and 320Sigor@sysoev.ru * nxt_memzero() should be used instead. 330Sigor@sysoev.ru */ 3413Sigor@sysoev.ru 35*65Sigor@sysoev.ru sa = nxt_mp_zalloc(mp, size); 360Sigor@sysoev.ru 370Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 3813Sigor@sysoev.ru sa->socklen = socklen; 3913Sigor@sysoev.ru sa->length = address_length; 4013Sigor@sysoev.ru sa->sockaddr_size = size; 410Sigor@sysoev.ru } 420Sigor@sysoev.ru 430Sigor@sysoev.ru return sa; 440Sigor@sysoev.ru } 450Sigor@sysoev.ru 460Sigor@sysoev.ru 470Sigor@sysoev.ru nxt_sockaddr_t * 48*65Sigor@sysoev.ru nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length, 49*65Sigor@sysoev.ru size_t address_length) 500Sigor@sysoev.ru { 510Sigor@sysoev.ru size_t size, copy; 520Sigor@sysoev.ru nxt_sockaddr_t *sa; 530Sigor@sysoev.ru 5410Sigor@sysoev.ru size = length; 5510Sigor@sysoev.ru copy = length; 560Sigor@sysoev.ru 570Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 580Sigor@sysoev.ru 590Sigor@sysoev.ru /* 600Sigor@sysoev.ru * Unspecified Unix domain sockaddr_un form and length are very 610Sigor@sysoev.ru * platform depended (see comment in unix/socket.h). Here they are 620Sigor@sysoev.ru * normalized to the sockaddr_un with single zero byte sun_path[]. 630Sigor@sysoev.ru */ 640Sigor@sysoev.ru 650Sigor@sysoev.ru if (size <= offsetof(struct sockaddr_un, sun_path)) { 660Sigor@sysoev.ru /* 670Sigor@sysoev.ru * Small socket length means a short unspecified Unix domain 680Sigor@sysoev.ru * socket address: 690Sigor@sysoev.ru * 700Sigor@sysoev.ru * getsockname() and getpeername() on OpenBSD prior to 5.3 710Sigor@sysoev.ru * return zero length and does not update a passed sockaddr 720Sigor@sysoev.ru * buffer at all. 730Sigor@sysoev.ru * 740Sigor@sysoev.ru * Linux returns length equal to 2, i.e. sockaddr_un without 750Sigor@sysoev.ru * sun_path[], unix(7): 760Sigor@sysoev.ru * 770Sigor@sysoev.ru * unnamed: A stream socket that has not been bound 780Sigor@sysoev.ru * to a pathname using bind(2) has no name. Likewise, 790Sigor@sysoev.ru * the two sockets created by socketpair(2) are unnamed. 800Sigor@sysoev.ru * When the address of an unnamed socket is returned by 810Sigor@sysoev.ru * getsockname(2), getpeername(2), and accept(2), its 820Sigor@sysoev.ru * length is sizeof(sa_family_t), and sun_path should 830Sigor@sysoev.ru * not be inspected. 840Sigor@sysoev.ru */ 850Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1; 860Sigor@sysoev.ru 870Sigor@sysoev.ru #if !(NXT_LINUX) 880Sigor@sysoev.ru 890Sigor@sysoev.ru } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') { 900Sigor@sysoev.ru /* 910Sigor@sysoev.ru * Omit nonsignificant zeros of the unspecified Unix domain socket 920Sigor@sysoev.ru * address. This test is disabled for Linux since Linux abstract 930Sigor@sysoev.ru * socket address also starts with zero. However Linux unspecified 940Sigor@sysoev.ru * Unix domain socket address is short and is handled above. 950Sigor@sysoev.ru */ 960Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1; 970Sigor@sysoev.ru copy = size; 980Sigor@sysoev.ru 990Sigor@sysoev.ru #endif 1000Sigor@sysoev.ru } 1010Sigor@sysoev.ru 1020Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 1030Sigor@sysoev.ru 10413Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, size, address_length); 1050Sigor@sysoev.ru 1060Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 1070Sigor@sysoev.ru nxt_memcpy(&sa->u.sockaddr, sockaddr, copy); 1080Sigor@sysoev.ru 1090Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD) 1100Sigor@sysoev.ru 11110Sigor@sysoev.ru if (length == 0) { 1120Sigor@sysoev.ru sa->u.sockaddr.sa_family = AF_UNIX; 1130Sigor@sysoev.ru } 1140Sigor@sysoev.ru 1150Sigor@sysoev.ru #endif 1160Sigor@sysoev.ru } 1170Sigor@sysoev.ru 1180Sigor@sysoev.ru return sa; 1190Sigor@sysoev.ru } 1200Sigor@sysoev.ru 1210Sigor@sysoev.ru 1220Sigor@sysoev.ru nxt_sockaddr_t * 123*65Sigor@sysoev.ru nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src) 1240Sigor@sysoev.ru { 12510Sigor@sysoev.ru size_t length; 1260Sigor@sysoev.ru nxt_sockaddr_t *dst; 1270Sigor@sysoev.ru 12813Sigor@sysoev.ru length = offsetof(nxt_sockaddr_t, u) + src->socklen; 1290Sigor@sysoev.ru 130*65Sigor@sysoev.ru dst = nxt_mp_alloc(mp, length); 1310Sigor@sysoev.ru 1320Sigor@sysoev.ru if (nxt_fast_path(dst != NULL)) { 13310Sigor@sysoev.ru nxt_memcpy(dst, src, length); 1340Sigor@sysoev.ru } 1350Sigor@sysoev.ru 1360Sigor@sysoev.ru return dst; 1370Sigor@sysoev.ru } 1380Sigor@sysoev.ru 1390Sigor@sysoev.ru 1400Sigor@sysoev.ru nxt_sockaddr_t * 141*65Sigor@sysoev.ru nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s) 1420Sigor@sysoev.ru { 1430Sigor@sysoev.ru int ret; 14413Sigor@sysoev.ru size_t length; 1450Sigor@sysoev.ru socklen_t socklen; 1460Sigor@sysoev.ru nxt_sockaddr_buf_t sockaddr; 1470Sigor@sysoev.ru 1480Sigor@sysoev.ru socklen = NXT_SOCKADDR_LEN; 1490Sigor@sysoev.ru 1500Sigor@sysoev.ru ret = getsockname(s, &sockaddr.buf, &socklen); 1510Sigor@sysoev.ru 1520Sigor@sysoev.ru if (nxt_fast_path(ret == 0)) { 15313Sigor@sysoev.ru 15413Sigor@sysoev.ru switch (sockaddr.buf.sa_family) { 15513Sigor@sysoev.ru #if (NXT_INET6) 15613Sigor@sysoev.ru case AF_INET6: 15713Sigor@sysoev.ru length = NXT_INET6_ADDR_STR_LEN; 15813Sigor@sysoev.ru break; 15913Sigor@sysoev.ru #endif 16013Sigor@sysoev.ru 16113Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 16213Sigor@sysoev.ru case AF_UNIX: 16313Sigor@sysoev.ru length = sizeof("unix:") - 1 + socklen; 16413Sigor@sysoev.ru #endif 16513Sigor@sysoev.ru break; 16613Sigor@sysoev.ru 16713Sigor@sysoev.ru case AF_INET: 16813Sigor@sysoev.ru length = NXT_INET_ADDR_STR_LEN; 16913Sigor@sysoev.ru break; 17013Sigor@sysoev.ru 17113Sigor@sysoev.ru default: 17213Sigor@sysoev.ru length = 0; 17313Sigor@sysoev.ru break; 17413Sigor@sysoev.ru } 17513Sigor@sysoev.ru 17613Sigor@sysoev.ru return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length); 1770Sigor@sysoev.ru } 1780Sigor@sysoev.ru 17913Sigor@sysoev.ru nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno); 1800Sigor@sysoev.ru 1810Sigor@sysoev.ru return NULL; 1820Sigor@sysoev.ru } 1830Sigor@sysoev.ru 1840Sigor@sysoev.ru 18513Sigor@sysoev.ru void 18613Sigor@sysoev.ru nxt_sockaddr_text(nxt_sockaddr_t *sa) 1870Sigor@sysoev.ru { 18813Sigor@sysoev.ru size_t offset; 18913Sigor@sysoev.ru u_char *p, *start, *end, *octet; 19013Sigor@sysoev.ru uint32_t port; 19113Sigor@sysoev.ru 19213Sigor@sysoev.ru end = (u_char *) sa + sa->sockaddr_size; 19313Sigor@sysoev.ru 19413Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 19513Sigor@sysoev.ru 19613Sigor@sysoev.ru case AF_INET: 19713Sigor@sysoev.ru offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in); 19813Sigor@sysoev.ru 19913Sigor@sysoev.ru sa->start = offset; 20013Sigor@sysoev.ru sa->address_start = offset; 20113Sigor@sysoev.ru 20213Sigor@sysoev.ru start = (u_char *) sa + offset; 20313Sigor@sysoev.ru octet = (u_char *) &sa->u.sockaddr_in.sin_addr; 20413Sigor@sysoev.ru 20513Sigor@sysoev.ru p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud", 20613Sigor@sysoev.ru octet[0], octet[1], octet[2], octet[3]); 20713Sigor@sysoev.ru 20813Sigor@sysoev.ru sa->address_length = p - start; 20913Sigor@sysoev.ru sa->port_start = sa->address_length + 1; 2100Sigor@sysoev.ru 21113Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port; 21213Sigor@sysoev.ru 21313Sigor@sysoev.ru break; 21413Sigor@sysoev.ru 21513Sigor@sysoev.ru #if (NXT_INET6) 21613Sigor@sysoev.ru 21713Sigor@sysoev.ru case AF_INET6: 21813Sigor@sysoev.ru offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6); 21913Sigor@sysoev.ru 22013Sigor@sysoev.ru sa->start = offset; 22113Sigor@sysoev.ru sa->address_start = offset; 22213Sigor@sysoev.ru 22313Sigor@sysoev.ru start = (u_char *) sa + offset; 22413Sigor@sysoev.ru p = start; 22513Sigor@sysoev.ru 22613Sigor@sysoev.ru *p++ = '['; 22713Sigor@sysoev.ru 22813Sigor@sysoev.ru p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 22913Sigor@sysoev.ru 23013Sigor@sysoev.ru sa->address_length = p - (start + 1); 23113Sigor@sysoev.ru sa->port_start = sa->address_length + 2; 23220Sigor@sysoev.ru 23313Sigor@sysoev.ru *p++ = ']'; 2340Sigor@sysoev.ru 23513Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port; 23613Sigor@sysoev.ru 23713Sigor@sysoev.ru break; 23813Sigor@sysoev.ru 23913Sigor@sysoev.ru #endif 24013Sigor@sysoev.ru 24113Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 24213Sigor@sysoev.ru 24313Sigor@sysoev.ru case AF_UNIX: 24413Sigor@sysoev.ru 24513Sigor@sysoev.ru offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_un); 2460Sigor@sysoev.ru 24713Sigor@sysoev.ru sa->start = offset; 24813Sigor@sysoev.ru sa->address_start = offset; 24913Sigor@sysoev.ru 25013Sigor@sysoev.ru start = (u_char *) sa + offset; 25113Sigor@sysoev.ru p = start; 2520Sigor@sysoev.ru 25313Sigor@sysoev.ru #if (NXT_LINUX) 25413Sigor@sysoev.ru 25513Sigor@sysoev.ru p = (u_char *) sa->u.sockaddr_un.sun_path; 25613Sigor@sysoev.ru 25713Sigor@sysoev.ru if (p[0] == '\0') { 25813Sigor@sysoev.ru int length; 2590Sigor@sysoev.ru 26013Sigor@sysoev.ru /* Linux abstract socket address has no trailing zero. */ 26113Sigor@sysoev.ru length = sa->socklen - offsetof(struct sockaddr_un, sun_path); 26213Sigor@sysoev.ru 26313Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1); 26413Sigor@sysoev.ru 26513Sigor@sysoev.ru } else { 26613Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:%s", p); 26713Sigor@sysoev.ru } 26813Sigor@sysoev.ru 26913Sigor@sysoev.ru #else /* !(NXT_LINUX) */ 27013Sigor@sysoev.ru 27113Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:%s", p); 2720Sigor@sysoev.ru 27313Sigor@sysoev.ru #endif 27413Sigor@sysoev.ru 27513Sigor@sysoev.ru sa->address_length = p - start; 27613Sigor@sysoev.ru sa->port_start = sa->address_length; 27713Sigor@sysoev.ru sa->length = p - start; 27813Sigor@sysoev.ru 27913Sigor@sysoev.ru return; 28013Sigor@sysoev.ru 28113Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 28213Sigor@sysoev.ru 28313Sigor@sysoev.ru default: 28413Sigor@sysoev.ru return; 2850Sigor@sysoev.ru } 2860Sigor@sysoev.ru 28713Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%d", ntohs(port)); 28813Sigor@sysoev.ru 28913Sigor@sysoev.ru sa->length = p - start; 2900Sigor@sysoev.ru } 2910Sigor@sysoev.ru 2920Sigor@sysoev.ru 2930Sigor@sysoev.ru uint32_t 29413Sigor@sysoev.ru nxt_sockaddr_port_number(nxt_sockaddr_t *sa) 2950Sigor@sysoev.ru { 2960Sigor@sysoev.ru uint32_t port; 2970Sigor@sysoev.ru 2980Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 2990Sigor@sysoev.ru 3000Sigor@sysoev.ru #if (NXT_INET6) 3010Sigor@sysoev.ru 3020Sigor@sysoev.ru case AF_INET6: 3030Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port; 3040Sigor@sysoev.ru break; 3050Sigor@sysoev.ru 3060Sigor@sysoev.ru #endif 3070Sigor@sysoev.ru 3080Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 3090Sigor@sysoev.ru 3100Sigor@sysoev.ru case AF_UNIX: 3110Sigor@sysoev.ru return 0; 3120Sigor@sysoev.ru 3130Sigor@sysoev.ru #endif 3140Sigor@sysoev.ru 3150Sigor@sysoev.ru default: 3160Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port; 3170Sigor@sysoev.ru break; 3180Sigor@sysoev.ru } 3190Sigor@sysoev.ru 3200Sigor@sysoev.ru return ntohs((uint16_t) port); 3210Sigor@sysoev.ru } 3220Sigor@sysoev.ru 3230Sigor@sysoev.ru 3240Sigor@sysoev.ru nxt_bool_t 3250Sigor@sysoev.ru nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) 3260Sigor@sysoev.ru { 32713Sigor@sysoev.ru if (sa1->socklen != sa2->socklen) { 3280Sigor@sysoev.ru return 0; 3290Sigor@sysoev.ru } 3300Sigor@sysoev.ru 3310Sigor@sysoev.ru if (sa1->type != sa2->type) { 3320Sigor@sysoev.ru return 0; 3330Sigor@sysoev.ru } 3340Sigor@sysoev.ru 3350Sigor@sysoev.ru if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) { 3360Sigor@sysoev.ru return 0; 3370Sigor@sysoev.ru } 3380Sigor@sysoev.ru 3390Sigor@sysoev.ru /* 3400Sigor@sysoev.ru * sockaddr struct's cannot be compared in whole since kernel 3410Sigor@sysoev.ru * may fill some fields in inherited sockaddr struct's. 3420Sigor@sysoev.ru */ 3430Sigor@sysoev.ru 3440Sigor@sysoev.ru switch (sa1->u.sockaddr.sa_family) { 3450Sigor@sysoev.ru 3460Sigor@sysoev.ru #if (NXT_INET6) 3470Sigor@sysoev.ru 3480Sigor@sysoev.ru case AF_INET6: 3490Sigor@sysoev.ru if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) { 3500Sigor@sysoev.ru return 0; 3510Sigor@sysoev.ru } 3520Sigor@sysoev.ru 3530Sigor@sysoev.ru if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr, 3540Sigor@sysoev.ru &sa2->u.sockaddr_in6.sin6_addr, 16) 3550Sigor@sysoev.ru != 0) 3560Sigor@sysoev.ru { 3570Sigor@sysoev.ru return 0; 3580Sigor@sysoev.ru } 3590Sigor@sysoev.ru 3600Sigor@sysoev.ru return 1; 3610Sigor@sysoev.ru 3620Sigor@sysoev.ru #endif 3630Sigor@sysoev.ru 3640Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 3650Sigor@sysoev.ru 3660Sigor@sysoev.ru case AF_UNIX: 3670Sigor@sysoev.ru { 36810Sigor@sysoev.ru size_t length; 3690Sigor@sysoev.ru 37013Sigor@sysoev.ru length = sa1->socklen - offsetof(struct sockaddr_un, sun_path); 3710Sigor@sysoev.ru 3720Sigor@sysoev.ru if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path, 37310Sigor@sysoev.ru &sa2->u.sockaddr_un.sun_path, length) 3740Sigor@sysoev.ru != 0) 3750Sigor@sysoev.ru { 3760Sigor@sysoev.ru return 0; 3770Sigor@sysoev.ru } 3780Sigor@sysoev.ru 3790Sigor@sysoev.ru return 1; 3800Sigor@sysoev.ru } 3810Sigor@sysoev.ru 3820Sigor@sysoev.ru #endif 3830Sigor@sysoev.ru 3840Sigor@sysoev.ru default: /* AF_INET */ 3850Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) { 3860Sigor@sysoev.ru return 0; 3870Sigor@sysoev.ru } 3880Sigor@sysoev.ru 3890Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_addr.s_addr 3900Sigor@sysoev.ru != sa2->u.sockaddr_in.sin_addr.s_addr) 3910Sigor@sysoev.ru { 3920Sigor@sysoev.ru return 0; 3930Sigor@sysoev.ru } 3940Sigor@sysoev.ru 3950Sigor@sysoev.ru return 1; 3960Sigor@sysoev.ru } 3970Sigor@sysoev.ru } 3980Sigor@sysoev.ru 3990Sigor@sysoev.ru 4000Sigor@sysoev.ru size_t 4010Sigor@sysoev.ru nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port) 4020Sigor@sysoev.ru { 4030Sigor@sysoev.ru u_char *p; 4040Sigor@sysoev.ru 4050Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 4060Sigor@sysoev.ru 4070Sigor@sysoev.ru case AF_INET: 4080Sigor@sysoev.ru p = (u_char *) &sa->u.sockaddr_in.sin_addr; 4090Sigor@sysoev.ru 4100Sigor@sysoev.ru if (port) { 4110Sigor@sysoev.ru p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d", 4120Sigor@sysoev.ru p[0], p[1], p[2], p[3], 4130Sigor@sysoev.ru ntohs(sa->u.sockaddr_in.sin_port)); 4140Sigor@sysoev.ru } else { 4150Sigor@sysoev.ru p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud", 4160Sigor@sysoev.ru p[0], p[1], p[2], p[3]); 4170Sigor@sysoev.ru } 4180Sigor@sysoev.ru 4190Sigor@sysoev.ru return p - buf; 4200Sigor@sysoev.ru 4210Sigor@sysoev.ru #if (NXT_INET6) 4220Sigor@sysoev.ru 4230Sigor@sysoev.ru case AF_INET6: 4240Sigor@sysoev.ru p = buf; 4250Sigor@sysoev.ru 4260Sigor@sysoev.ru if (port) { 4270Sigor@sysoev.ru *p++ = '['; 4280Sigor@sysoev.ru } 4290Sigor@sysoev.ru 4300Sigor@sysoev.ru p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 4310Sigor@sysoev.ru 4320Sigor@sysoev.ru if (port) { 4330Sigor@sysoev.ru p = nxt_sprintf(p, end, "]:%d", 4340Sigor@sysoev.ru ntohs(sa->u.sockaddr_in6.sin6_port)); 4350Sigor@sysoev.ru } 4360Sigor@sysoev.ru 4370Sigor@sysoev.ru return p - buf; 4380Sigor@sysoev.ru #endif 4390Sigor@sysoev.ru 4400Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 4410Sigor@sysoev.ru 4420Sigor@sysoev.ru case AF_UNIX: 4430Sigor@sysoev.ru 4440Sigor@sysoev.ru #if (NXT_LINUX) 4450Sigor@sysoev.ru 4460Sigor@sysoev.ru p = (u_char *) sa->u.sockaddr_un.sun_path; 4470Sigor@sysoev.ru 4480Sigor@sysoev.ru if (p[0] == '\0') { 44910Sigor@sysoev.ru int length; 4500Sigor@sysoev.ru 4510Sigor@sysoev.ru /* Linux abstract socket address has no trailing zero. */ 4520Sigor@sysoev.ru 45313Sigor@sysoev.ru length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1; 45410Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1); 4550Sigor@sysoev.ru 4560Sigor@sysoev.ru } else { 4570Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:%s", p); 4580Sigor@sysoev.ru } 4590Sigor@sysoev.ru 4600Sigor@sysoev.ru #else /* !(NXT_LINUX) */ 4610Sigor@sysoev.ru 4620Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path); 4630Sigor@sysoev.ru 4640Sigor@sysoev.ru #endif 4650Sigor@sysoev.ru 4660Sigor@sysoev.ru return p - buf; 4670Sigor@sysoev.ru 4680Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 4690Sigor@sysoev.ru 4700Sigor@sysoev.ru default: 4710Sigor@sysoev.ru return 0; 4720Sigor@sysoev.ru } 4730Sigor@sysoev.ru } 4740Sigor@sysoev.ru 4750Sigor@sysoev.ru 4760Sigor@sysoev.ru #if (NXT_INET6) 4770Sigor@sysoev.ru 4780Sigor@sysoev.ru static u_char * 4790Sigor@sysoev.ru nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end) 4800Sigor@sysoev.ru { 4810Sigor@sysoev.ru u_char *p; 4820Sigor@sysoev.ru size_t zero_groups, last_zero_groups, ipv6_bytes; 4830Sigor@sysoev.ru nxt_uint_t i, zero_start, last_zero_start; 4840Sigor@sysoev.ru 4850Sigor@sysoev.ru if (buf + NXT_INET6_ADDR_STR_LEN > end) { 4860Sigor@sysoev.ru return buf; 4870Sigor@sysoev.ru } 4880Sigor@sysoev.ru 4890Sigor@sysoev.ru zero_start = 8; 4900Sigor@sysoev.ru zero_groups = 0; 4910Sigor@sysoev.ru last_zero_start = 8; 4920Sigor@sysoev.ru last_zero_groups = 0; 4930Sigor@sysoev.ru 4940Sigor@sysoev.ru for (i = 0; i < 16; i += 2) { 4950Sigor@sysoev.ru 4960Sigor@sysoev.ru if (addr[i] == 0 && addr[i + 1] == 0) { 4970Sigor@sysoev.ru 4980Sigor@sysoev.ru if (last_zero_groups == 0) { 4990Sigor@sysoev.ru last_zero_start = i; 5000Sigor@sysoev.ru } 5010Sigor@sysoev.ru 5020Sigor@sysoev.ru last_zero_groups++; 5030Sigor@sysoev.ru 5040Sigor@sysoev.ru } else { 5050Sigor@sysoev.ru if (zero_groups < last_zero_groups) { 5060Sigor@sysoev.ru zero_groups = last_zero_groups; 5070Sigor@sysoev.ru zero_start = last_zero_start; 5080Sigor@sysoev.ru } 5090Sigor@sysoev.ru 5100Sigor@sysoev.ru last_zero_groups = 0; 5110Sigor@sysoev.ru } 5120Sigor@sysoev.ru } 5130Sigor@sysoev.ru 5140Sigor@sysoev.ru if (zero_groups < last_zero_groups) { 5150Sigor@sysoev.ru zero_groups = last_zero_groups; 5160Sigor@sysoev.ru zero_start = last_zero_start; 5170Sigor@sysoev.ru } 5180Sigor@sysoev.ru 5190Sigor@sysoev.ru ipv6_bytes = 16; 5200Sigor@sysoev.ru p = buf; 5210Sigor@sysoev.ru 5220Sigor@sysoev.ru if (zero_start == 0) { 5230Sigor@sysoev.ru 5240Sigor@sysoev.ru /* IPv4-mapped address */ 5250Sigor@sysoev.ru if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff) 5260Sigor@sysoev.ru /* IPv4-compatible address */ 5270Sigor@sysoev.ru || (zero_groups == 6) 5280Sigor@sysoev.ru /* not IPv6 loopback address */ 5290Sigor@sysoev.ru || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1)) 5300Sigor@sysoev.ru { 5310Sigor@sysoev.ru ipv6_bytes = 12; 5320Sigor@sysoev.ru } 5330Sigor@sysoev.ru 5340Sigor@sysoev.ru *p++ = ':'; 5350Sigor@sysoev.ru } 5360Sigor@sysoev.ru 5370Sigor@sysoev.ru for (i = 0; i < ipv6_bytes; i += 2) { 5380Sigor@sysoev.ru 5390Sigor@sysoev.ru if (i == zero_start) { 5400Sigor@sysoev.ru /* Output maximum number of consecutive zero groups as "::". */ 5410Sigor@sysoev.ru i += (zero_groups - 1) * 2; 5420Sigor@sysoev.ru *p++ = ':'; 5430Sigor@sysoev.ru continue; 5440Sigor@sysoev.ru } 5450Sigor@sysoev.ru 5460Sigor@sysoev.ru p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]); 5470Sigor@sysoev.ru 5480Sigor@sysoev.ru if (i < 14) { 5490Sigor@sysoev.ru *p++ = ':'; 5500Sigor@sysoev.ru } 5510Sigor@sysoev.ru } 5520Sigor@sysoev.ru 5530Sigor@sysoev.ru if (ipv6_bytes == 12) { 5540Sigor@sysoev.ru p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud", 5550Sigor@sysoev.ru addr[12], addr[13], addr[14], addr[15]); 5560Sigor@sysoev.ru } 5570Sigor@sysoev.ru 5580Sigor@sysoev.ru return p; 5590Sigor@sysoev.ru } 5600Sigor@sysoev.ru 5610Sigor@sysoev.ru #endif 5620Sigor@sysoev.ru 5630Sigor@sysoev.ru 5640Sigor@sysoev.ru void 5650Sigor@sysoev.ru nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs) 5660Sigor@sysoev.ru { 5670Sigor@sysoev.ru u_char *p; 56810Sigor@sysoev.ru size_t length; 5690Sigor@sysoev.ru nxt_int_t ret; 5700Sigor@sysoev.ru nxt_work_handler_t handler; 5710Sigor@sysoev.ru 5720Sigor@sysoev.ru nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse"); 5730Sigor@sysoev.ru 57410Sigor@sysoev.ru length = jbs->addr.length; 57510Sigor@sysoev.ru p = jbs->addr.start; 5760Sigor@sysoev.ru 57710Sigor@sysoev.ru if (length > 6 && nxt_memcmp(p, (u_char *) "unix:", 5) == 0) { 5780Sigor@sysoev.ru ret = nxt_job_sockaddr_unix_parse(jbs); 5790Sigor@sysoev.ru 58010Sigor@sysoev.ru } else if (length != 0 && *p == '[') { 5810Sigor@sysoev.ru ret = nxt_job_sockaddr_inet6_parse(jbs); 5820Sigor@sysoev.ru 5830Sigor@sysoev.ru } else { 5840Sigor@sysoev.ru ret = nxt_job_sockaddr_inet_parse(jbs); 5850Sigor@sysoev.ru } 5860Sigor@sysoev.ru 5870Sigor@sysoev.ru switch (ret) { 5880Sigor@sysoev.ru 5890Sigor@sysoev.ru case NXT_OK: 5900Sigor@sysoev.ru handler = jbs->resolve.ready_handler; 5910Sigor@sysoev.ru break; 5920Sigor@sysoev.ru 5930Sigor@sysoev.ru case NXT_ERROR: 5940Sigor@sysoev.ru handler = jbs->resolve.error_handler; 5950Sigor@sysoev.ru break; 5960Sigor@sysoev.ru 5970Sigor@sysoev.ru default: /* NXT_AGAIN */ 5980Sigor@sysoev.ru return; 5990Sigor@sysoev.ru } 6000Sigor@sysoev.ru 6014Sigor@sysoev.ru nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler); 6020Sigor@sysoev.ru } 6030Sigor@sysoev.ru 6040Sigor@sysoev.ru 6050Sigor@sysoev.ru static nxt_int_t 6060Sigor@sysoev.ru nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs) 6070Sigor@sysoev.ru { 6080Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 60910Sigor@sysoev.ru size_t length, socklen; 6100Sigor@sysoev.ru u_char *path; 611*65Sigor@sysoev.ru nxt_mp_t *mp; 6120Sigor@sysoev.ru nxt_sockaddr_t *sa; 6130Sigor@sysoev.ru 6140Sigor@sysoev.ru /* 6150Sigor@sysoev.ru * Actual sockaddr_un length can be lesser or even larger than defined 6160Sigor@sysoev.ru * struct sockaddr_un length (see comment in unix/nxt_socket.h). So 6170Sigor@sysoev.ru * limit maximum Unix domain socket address length by defined sun_path[] 6180Sigor@sysoev.ru * length because some OSes accept addresses twice larger than defined 6190Sigor@sysoev.ru * struct sockaddr_un. Also reserve space for a trailing zero to avoid 6200Sigor@sysoev.ru * ambiguity, since many OSes accept Unix domain socket addresses 6210Sigor@sysoev.ru * without a trailing zero. 6220Sigor@sysoev.ru */ 6230Sigor@sysoev.ru const size_t max_len = sizeof(struct sockaddr_un) 6240Sigor@sysoev.ru - offsetof(struct sockaddr_un, sun_path) - 1; 6250Sigor@sysoev.ru 6260Sigor@sysoev.ru /* cutting "unix:" */ 62710Sigor@sysoev.ru length = jbs->addr.length - 5; 62810Sigor@sysoev.ru path = jbs->addr.start + 5; 6290Sigor@sysoev.ru 63010Sigor@sysoev.ru if (length > max_len) { 6310Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 6320Sigor@sysoev.ru "unix domain socket \"%V\" name is too long", 6330Sigor@sysoev.ru &jbs->addr); 6340Sigor@sysoev.ru return NXT_ERROR; 6350Sigor@sysoev.ru } 6360Sigor@sysoev.ru 63710Sigor@sysoev.ru socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; 6380Sigor@sysoev.ru 6390Sigor@sysoev.ru #if (NXT_LINUX) 6400Sigor@sysoev.ru 6410Sigor@sysoev.ru /* 6420Sigor@sysoev.ru * Linux unix(7): 6430Sigor@sysoev.ru * 6440Sigor@sysoev.ru * abstract: an abstract socket address is distinguished by the fact 6450Sigor@sysoev.ru * that sun_path[0] is a null byte ('\0'). The socket's address in 6460Sigor@sysoev.ru * this namespace is given by the additional bytes in sun_path that 6470Sigor@sysoev.ru * are covered by the specified length of the address structure. 6480Sigor@sysoev.ru * (Null bytes in the name have no special significance.) 6490Sigor@sysoev.ru */ 6500Sigor@sysoev.ru if (path[0] == '\0') { 6510Sigor@sysoev.ru socklen--; 6520Sigor@sysoev.ru } 6530Sigor@sysoev.ru 6540Sigor@sysoev.ru #endif 6550Sigor@sysoev.ru 6560Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 6570Sigor@sysoev.ru 658*65Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 6590Sigor@sysoev.ru 6600Sigor@sysoev.ru if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) { 66113Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length); 6620Sigor@sysoev.ru 6630Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 6640Sigor@sysoev.ru jbs->resolve.count = 1; 6650Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 6660Sigor@sysoev.ru 6670Sigor@sysoev.ru sa->u.sockaddr_un.sun_family = AF_UNIX; 66810Sigor@sysoev.ru nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length); 6690Sigor@sysoev.ru 6700Sigor@sysoev.ru return NXT_OK; 6710Sigor@sysoev.ru } 6720Sigor@sysoev.ru } 6730Sigor@sysoev.ru 6740Sigor@sysoev.ru return NXT_ERROR; 6750Sigor@sysoev.ru 6760Sigor@sysoev.ru #else /* !(NXT_HAVE_UNIX_DOMAIN) */ 6770Sigor@sysoev.ru 6780Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 6790Sigor@sysoev.ru "unix domain socket \"%V\" is not supported", 6800Sigor@sysoev.ru &jbs->addr); 6810Sigor@sysoev.ru return NXT_ERROR; 6820Sigor@sysoev.ru 6830Sigor@sysoev.ru #endif 6840Sigor@sysoev.ru } 6850Sigor@sysoev.ru 6860Sigor@sysoev.ru 6870Sigor@sysoev.ru static nxt_int_t 6880Sigor@sysoev.ru nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs) 6890Sigor@sysoev.ru { 6900Sigor@sysoev.ru #if (NXT_INET6) 6910Sigor@sysoev.ru u_char *p, *addr, *addr_end; 69210Sigor@sysoev.ru size_t length; 693*65Sigor@sysoev.ru nxt_mp_t *mp; 6940Sigor@sysoev.ru nxt_int_t port; 6950Sigor@sysoev.ru nxt_sockaddr_t *sa; 6960Sigor@sysoev.ru struct in6_addr *in6_addr; 6970Sigor@sysoev.ru 69810Sigor@sysoev.ru length = jbs->addr.length - 1; 69910Sigor@sysoev.ru addr = jbs->addr.start + 1; 7000Sigor@sysoev.ru 70110Sigor@sysoev.ru addr_end = nxt_memchr(addr, ']', length); 7020Sigor@sysoev.ru 7030Sigor@sysoev.ru if (addr_end == NULL) { 7040Sigor@sysoev.ru goto invalid_address; 7050Sigor@sysoev.ru } 7060Sigor@sysoev.ru 7070Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 7080Sigor@sysoev.ru 709*65Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 7100Sigor@sysoev.ru 7110Sigor@sysoev.ru if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 7120Sigor@sysoev.ru return NXT_ERROR; 7130Sigor@sysoev.ru } 7140Sigor@sysoev.ru 7150Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6)); 7160Sigor@sysoev.ru 7170Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 7180Sigor@sysoev.ru return NXT_ERROR; 7190Sigor@sysoev.ru } 7200Sigor@sysoev.ru 7210Sigor@sysoev.ru jbs->resolve.count = 1; 7220Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 7230Sigor@sysoev.ru 7240Sigor@sysoev.ru in6_addr = &sa->u.sockaddr_in6.sin6_addr; 7250Sigor@sysoev.ru 7260Sigor@sysoev.ru if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) { 7270Sigor@sysoev.ru goto invalid_address; 7280Sigor@sysoev.ru } 7290Sigor@sysoev.ru 7300Sigor@sysoev.ru p = addr_end + 1; 73110Sigor@sysoev.ru length = (addr + length) - p; 7320Sigor@sysoev.ru 73310Sigor@sysoev.ru if (length == 0) { 7340Sigor@sysoev.ru jbs->no_port = 1; 7350Sigor@sysoev.ru port = jbs->resolve.port; 7360Sigor@sysoev.ru goto found; 7370Sigor@sysoev.ru } 7380Sigor@sysoev.ru 7390Sigor@sysoev.ru if (*p == ':') { 74010Sigor@sysoev.ru port = nxt_int_parse(p + 1, length - 1); 7410Sigor@sysoev.ru 7420Sigor@sysoev.ru if (port >= 1 && port <= 65535) { 7430Sigor@sysoev.ru port = htons((in_port_t) port); 7440Sigor@sysoev.ru goto found; 7450Sigor@sysoev.ru } 7460Sigor@sysoev.ru } 7470Sigor@sysoev.ru 7480Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 7490Sigor@sysoev.ru "invalid port in \"%V\"", &jbs->addr); 7500Sigor@sysoev.ru 7510Sigor@sysoev.ru return NXT_ERROR; 7520Sigor@sysoev.ru 7530Sigor@sysoev.ru found: 7540Sigor@sysoev.ru 7550Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_family = AF_INET6; 7560Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_port = (in_port_t) port; 7570Sigor@sysoev.ru 7580Sigor@sysoev.ru if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) { 7590Sigor@sysoev.ru jbs->wildcard = 1; 7600Sigor@sysoev.ru } 7610Sigor@sysoev.ru 7620Sigor@sysoev.ru return NXT_OK; 7630Sigor@sysoev.ru 7640Sigor@sysoev.ru invalid_address: 7650Sigor@sysoev.ru 7660Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 7670Sigor@sysoev.ru "invalid IPv6 address in \"%V\"", &jbs->addr); 7680Sigor@sysoev.ru return NXT_ERROR; 7690Sigor@sysoev.ru 7700Sigor@sysoev.ru #else 7710Sigor@sysoev.ru 7720Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 7730Sigor@sysoev.ru "IPv6 socket \"%V\" is not supported", &jbs->addr); 7740Sigor@sysoev.ru return NXT_ERROR; 7750Sigor@sysoev.ru 7760Sigor@sysoev.ru #endif 7770Sigor@sysoev.ru } 7780Sigor@sysoev.ru 7790Sigor@sysoev.ru 7800Sigor@sysoev.ru static nxt_int_t 7810Sigor@sysoev.ru nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs) 7820Sigor@sysoev.ru { 7830Sigor@sysoev.ru u_char *p, *host; 78410Sigor@sysoev.ru size_t length; 785*65Sigor@sysoev.ru nxt_mp_t *mp; 7860Sigor@sysoev.ru nxt_int_t port; 787*65Sigor@sysoev.ru in_addr_t addr; 7880Sigor@sysoev.ru nxt_sockaddr_t *sa; 7890Sigor@sysoev.ru 7900Sigor@sysoev.ru addr = INADDR_ANY; 7910Sigor@sysoev.ru 79210Sigor@sysoev.ru length = jbs->addr.length; 79310Sigor@sysoev.ru host = jbs->addr.start; 7940Sigor@sysoev.ru 79510Sigor@sysoev.ru p = nxt_memchr(host, ':', length); 7960Sigor@sysoev.ru 7970Sigor@sysoev.ru if (p == NULL) { 7980Sigor@sysoev.ru 7990Sigor@sysoev.ru /* single value port, address, or host name */ 8000Sigor@sysoev.ru 80110Sigor@sysoev.ru port = nxt_int_parse(host, length); 8020Sigor@sysoev.ru 8030Sigor@sysoev.ru if (port > 0) { 8040Sigor@sysoev.ru if (port < 1 || port > 65535) { 8050Sigor@sysoev.ru goto invalid_port; 8060Sigor@sysoev.ru } 8070Sigor@sysoev.ru 8080Sigor@sysoev.ru /* "*:XX" */ 8090Sigor@sysoev.ru port = htons((in_port_t) port); 8100Sigor@sysoev.ru jbs->resolve.port = (in_port_t) port; 8110Sigor@sysoev.ru 8120Sigor@sysoev.ru } else { 8130Sigor@sysoev.ru jbs->no_port = 1; 8140Sigor@sysoev.ru 81510Sigor@sysoev.ru addr = nxt_inet_addr(host, length); 8160Sigor@sysoev.ru 8170Sigor@sysoev.ru if (addr == INADDR_NONE) { 81810Sigor@sysoev.ru jbs->resolve.name.length = length; 81910Sigor@sysoev.ru jbs->resolve.name.start = host; 8200Sigor@sysoev.ru 8210Sigor@sysoev.ru nxt_job_resolve(&jbs->resolve); 8220Sigor@sysoev.ru return NXT_AGAIN; 8230Sigor@sysoev.ru } 8240Sigor@sysoev.ru 8250Sigor@sysoev.ru /* "x.x.x.x" */ 8260Sigor@sysoev.ru port = jbs->resolve.port; 8270Sigor@sysoev.ru } 8280Sigor@sysoev.ru 8290Sigor@sysoev.ru } else { 8300Sigor@sysoev.ru 8310Sigor@sysoev.ru /* x.x.x.x:XX or host:XX */ 8320Sigor@sysoev.ru 8330Sigor@sysoev.ru p++; 83410Sigor@sysoev.ru length = (host + length) - p; 83510Sigor@sysoev.ru port = nxt_int_parse(p, length); 8360Sigor@sysoev.ru 8370Sigor@sysoev.ru if (port < 1 || port > 65535) { 8380Sigor@sysoev.ru goto invalid_port; 8390Sigor@sysoev.ru } 8400Sigor@sysoev.ru 8410Sigor@sysoev.ru port = htons((in_port_t) port); 8420Sigor@sysoev.ru 84310Sigor@sysoev.ru length = (p - 1) - host; 8440Sigor@sysoev.ru 84510Sigor@sysoev.ru if (length != 1 || host[0] != '*') { 84610Sigor@sysoev.ru addr = nxt_inet_addr(host, length); 8470Sigor@sysoev.ru 8480Sigor@sysoev.ru if (addr == INADDR_NONE) { 84910Sigor@sysoev.ru jbs->resolve.name.length = length; 85010Sigor@sysoev.ru jbs->resolve.name.start = host; 8510Sigor@sysoev.ru jbs->resolve.port = (in_port_t) port; 8520Sigor@sysoev.ru 8530Sigor@sysoev.ru nxt_job_resolve(&jbs->resolve); 8540Sigor@sysoev.ru return NXT_AGAIN; 8550Sigor@sysoev.ru } 8560Sigor@sysoev.ru 8570Sigor@sysoev.ru /* "x.x.x.x:XX" */ 8580Sigor@sysoev.ru } 8590Sigor@sysoev.ru } 8600Sigor@sysoev.ru 8610Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 8620Sigor@sysoev.ru 863*65Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 8640Sigor@sysoev.ru if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 8650Sigor@sysoev.ru return NXT_ERROR; 8660Sigor@sysoev.ru } 8670Sigor@sysoev.ru 86813Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), 86913Sigor@sysoev.ru NXT_INET_ADDR_STR_LEN); 8700Sigor@sysoev.ru 8710Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 8720Sigor@sysoev.ru jbs->resolve.count = 1; 8730Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 8740Sigor@sysoev.ru 8750Sigor@sysoev.ru jbs->wildcard = (addr == INADDR_ANY); 8760Sigor@sysoev.ru 8770Sigor@sysoev.ru sa->u.sockaddr_in.sin_family = AF_INET; 8780Sigor@sysoev.ru sa->u.sockaddr_in.sin_port = (in_port_t) port; 8790Sigor@sysoev.ru sa->u.sockaddr_in.sin_addr.s_addr = addr; 8800Sigor@sysoev.ru 8810Sigor@sysoev.ru return NXT_OK; 8820Sigor@sysoev.ru } 8830Sigor@sysoev.ru 8840Sigor@sysoev.ru return NXT_ERROR; 8850Sigor@sysoev.ru 8860Sigor@sysoev.ru invalid_port: 8870Sigor@sysoev.ru 8880Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 8890Sigor@sysoev.ru "invalid port in \"%V\"", &jbs->addr); 8900Sigor@sysoev.ru 8910Sigor@sysoev.ru return NXT_ERROR; 8920Sigor@sysoev.ru } 8930Sigor@sysoev.ru 8940Sigor@sysoev.ru 8950Sigor@sysoev.ru in_addr_t 89610Sigor@sysoev.ru nxt_inet_addr(u_char *buf, size_t length) 8970Sigor@sysoev.ru { 8980Sigor@sysoev.ru u_char c, *end; 8990Sigor@sysoev.ru in_addr_t addr; 9000Sigor@sysoev.ru nxt_uint_t digit, octet, dots; 9010Sigor@sysoev.ru 9020Sigor@sysoev.ru addr = 0; 9030Sigor@sysoev.ru octet = 0; 9040Sigor@sysoev.ru dots = 0; 9050Sigor@sysoev.ru 90610Sigor@sysoev.ru end = buf + length; 9070Sigor@sysoev.ru 9080Sigor@sysoev.ru while (buf < end) { 9090Sigor@sysoev.ru 9100Sigor@sysoev.ru c = *buf++; 9110Sigor@sysoev.ru 9120Sigor@sysoev.ru digit = c - '0'; 9130Sigor@sysoev.ru /* values below '0' become large unsigned integers */ 9140Sigor@sysoev.ru 9150Sigor@sysoev.ru if (digit < 10) { 9160Sigor@sysoev.ru octet = octet * 10 + digit; 9170Sigor@sysoev.ru continue; 9180Sigor@sysoev.ru } 9190Sigor@sysoev.ru 9200Sigor@sysoev.ru if (c == '.' && octet < 256) { 9210Sigor@sysoev.ru addr = (addr << 8) + octet; 9220Sigor@sysoev.ru octet = 0; 9230Sigor@sysoev.ru dots++; 9240Sigor@sysoev.ru continue; 9250Sigor@sysoev.ru } 9260Sigor@sysoev.ru 9270Sigor@sysoev.ru return INADDR_NONE; 9280Sigor@sysoev.ru } 9290Sigor@sysoev.ru 9300Sigor@sysoev.ru if (dots == 3 && octet < 256) { 9310Sigor@sysoev.ru addr = (addr << 8) + octet; 9320Sigor@sysoev.ru return htonl(addr); 9330Sigor@sysoev.ru } 9340Sigor@sysoev.ru 9350Sigor@sysoev.ru return INADDR_NONE; 9360Sigor@sysoev.ru } 9370Sigor@sysoev.ru 9380Sigor@sysoev.ru 9390Sigor@sysoev.ru #if (NXT_INET6) 9400Sigor@sysoev.ru 9410Sigor@sysoev.ru nxt_int_t 94210Sigor@sysoev.ru nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length) 9430Sigor@sysoev.ru { 9440Sigor@sysoev.ru u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end; 9450Sigor@sysoev.ru nxt_uint_t digit, group, nibbles, groups_left; 9460Sigor@sysoev.ru 94710Sigor@sysoev.ru if (length == 0) { 9480Sigor@sysoev.ru return NXT_ERROR; 9490Sigor@sysoev.ru } 9500Sigor@sysoev.ru 95110Sigor@sysoev.ru end = buf + length; 9520Sigor@sysoev.ru 9530Sigor@sysoev.ru if (buf[0] == ':') { 9540Sigor@sysoev.ru buf++; 9550Sigor@sysoev.ru } 9560Sigor@sysoev.ru 9570Sigor@sysoev.ru addr = in6_addr->s6_addr; 9580Sigor@sysoev.ru zero_start = NULL; 9590Sigor@sysoev.ru groups_left = 8; 9600Sigor@sysoev.ru nibbles = 0; 9610Sigor@sysoev.ru group = 0; 9620Sigor@sysoev.ru ipv4 = NULL; 9630Sigor@sysoev.ru 9640Sigor@sysoev.ru while (buf < end) { 9650Sigor@sysoev.ru c = *buf++; 9660Sigor@sysoev.ru 9670Sigor@sysoev.ru if (c == ':') { 9680Sigor@sysoev.ru if (nibbles != 0) { 9690Sigor@sysoev.ru ipv4 = buf; 9700Sigor@sysoev.ru 9710Sigor@sysoev.ru *addr++ = (u_char) (group >> 8); 9720Sigor@sysoev.ru *addr++ = (u_char) (group & 0xff); 9730Sigor@sysoev.ru groups_left--; 9740Sigor@sysoev.ru 9750Sigor@sysoev.ru if (groups_left != 0) { 9760Sigor@sysoev.ru nibbles = 0; 9770Sigor@sysoev.ru group = 0; 9780Sigor@sysoev.ru continue; 9790Sigor@sysoev.ru } 9800Sigor@sysoev.ru 9810Sigor@sysoev.ru } else { 9820Sigor@sysoev.ru if (zero_start == NULL) { 9830Sigor@sysoev.ru ipv4 = buf; 9840Sigor@sysoev.ru zero_start = addr; 9850Sigor@sysoev.ru continue; 9860Sigor@sysoev.ru } 9870Sigor@sysoev.ru } 9880Sigor@sysoev.ru 9890Sigor@sysoev.ru return NXT_ERROR; 9900Sigor@sysoev.ru } 9910Sigor@sysoev.ru 9920Sigor@sysoev.ru if (c == '.' && nibbles != 0) { 9930Sigor@sysoev.ru 9940Sigor@sysoev.ru if (groups_left < 2 || ipv4 == NULL) { 9950Sigor@sysoev.ru return NXT_ERROR; 9960Sigor@sysoev.ru } 9970Sigor@sysoev.ru 9980Sigor@sysoev.ru group = nxt_inet_addr(ipv4, end - ipv4); 9990Sigor@sysoev.ru if (group == INADDR_NONE) { 10000Sigor@sysoev.ru return NXT_ERROR; 10010Sigor@sysoev.ru } 10020Sigor@sysoev.ru 10030Sigor@sysoev.ru group = ntohl(group); 10040Sigor@sysoev.ru 10050Sigor@sysoev.ru *addr++ = (u_char) ((group >> 24) & 0xff); 10060Sigor@sysoev.ru *addr++ = (u_char) ((group >> 16) & 0xff); 10070Sigor@sysoev.ru groups_left--; 10080Sigor@sysoev.ru 10090Sigor@sysoev.ru /* the low 16-bit are copied below */ 10100Sigor@sysoev.ru break; 10110Sigor@sysoev.ru } 10120Sigor@sysoev.ru 10130Sigor@sysoev.ru nibbles++; 10140Sigor@sysoev.ru 10150Sigor@sysoev.ru if (nibbles > 4) { 10160Sigor@sysoev.ru return NXT_ERROR; 10170Sigor@sysoev.ru } 10180Sigor@sysoev.ru 10190Sigor@sysoev.ru group <<= 4; 10200Sigor@sysoev.ru 10210Sigor@sysoev.ru digit = c - '0'; 10220Sigor@sysoev.ru /* values below '0' become large unsigned integers */ 10230Sigor@sysoev.ru 10240Sigor@sysoev.ru if (digit < 10) { 10250Sigor@sysoev.ru group += digit; 10260Sigor@sysoev.ru continue; 10270Sigor@sysoev.ru } 10280Sigor@sysoev.ru 10290Sigor@sysoev.ru c |= 0x20; 10300Sigor@sysoev.ru digit = c - 'a'; 10310Sigor@sysoev.ru /* values below 'a' become large unsigned integers */ 10320Sigor@sysoev.ru 10330Sigor@sysoev.ru if (digit < 6) { 10340Sigor@sysoev.ru group += 10 + digit; 10350Sigor@sysoev.ru continue; 10360Sigor@sysoev.ru } 10370Sigor@sysoev.ru 10380Sigor@sysoev.ru return NXT_ERROR; 10390Sigor@sysoev.ru } 10400Sigor@sysoev.ru 10410Sigor@sysoev.ru if (nibbles == 0 && zero_start == NULL) { 10420Sigor@sysoev.ru return NXT_ERROR; 10430Sigor@sysoev.ru } 10440Sigor@sysoev.ru 10450Sigor@sysoev.ru *addr++ = (u_char) (group >> 8); 10460Sigor@sysoev.ru *addr++ = (u_char) (group & 0xff); 10470Sigor@sysoev.ru groups_left--; 10480Sigor@sysoev.ru 10490Sigor@sysoev.ru if (groups_left != 0) { 10500Sigor@sysoev.ru 10510Sigor@sysoev.ru if (zero_start != NULL) { 10520Sigor@sysoev.ru 10530Sigor@sysoev.ru /* moving part before consecutive zero groups to the end */ 10540Sigor@sysoev.ru 10550Sigor@sysoev.ru groups_left *= 2; 10560Sigor@sysoev.ru src = addr - 1; 10570Sigor@sysoev.ru dst = src + groups_left; 10580Sigor@sysoev.ru 10590Sigor@sysoev.ru while (src >= zero_start) { 10600Sigor@sysoev.ru *dst-- = *src--; 10610Sigor@sysoev.ru } 10620Sigor@sysoev.ru 10630Sigor@sysoev.ru nxt_memzero(zero_start, groups_left); 10640Sigor@sysoev.ru 10650Sigor@sysoev.ru return NXT_OK; 10660Sigor@sysoev.ru } 10670Sigor@sysoev.ru 10680Sigor@sysoev.ru } else { 10690Sigor@sysoev.ru if (zero_start == NULL) { 10700Sigor@sysoev.ru return NXT_OK; 10710Sigor@sysoev.ru } 10720Sigor@sysoev.ru } 10730Sigor@sysoev.ru 10740Sigor@sysoev.ru return NXT_ERROR; 10750Sigor@sysoev.ru } 10760Sigor@sysoev.ru 10770Sigor@sysoev.ru #endif 1078