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 1499Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr); 1599Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr); 1699Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr); 1799Sigor@sysoev.ru 180Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs); 190Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs); 200Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs); 210Sigor@sysoev.ru 220Sigor@sysoev.ru 230Sigor@sysoev.ru nxt_sockaddr_t * 24358Sigor@sysoev.ru nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls) 25337Sigor@sysoev.ru { 26358Sigor@sysoev.ru uint8_t hint; 27358Sigor@sysoev.ru size_t size; 28358Sigor@sysoev.ru nxt_sockaddr_t *sa; 29337Sigor@sysoev.ru 30358Sigor@sysoev.ru hint = (uint8_t) -1; 31337Sigor@sysoev.ru size = offsetof(nxt_sockaddr_t, u) + ls->socklen + ls->address_length; 32337Sigor@sysoev.ru 33358Sigor@sysoev.ru sa = nxt_event_engine_mem_alloc(engine, &hint, size); 34337Sigor@sysoev.ru 35337Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 36337Sigor@sysoev.ru /* Zero only beginning of structure up to sockaddr_un.sun_path[1]. */ 37337Sigor@sysoev.ru nxt_memzero(sa, offsetof(nxt_sockaddr_t, u.sockaddr.sa_data[1])); 38337Sigor@sysoev.ru 39358Sigor@sysoev.ru sa->cache_hint = hint; 40337Sigor@sysoev.ru sa->socklen = ls->socklen; 41337Sigor@sysoev.ru sa->length = ls->address_length; 42337Sigor@sysoev.ru 43337Sigor@sysoev.ru sa->type = ls->sockaddr->type; 44337Sigor@sysoev.ru /* 45337Sigor@sysoev.ru * Set address family for unspecified Unix domain socket, 46337Sigor@sysoev.ru * because these sockaddr's are not updated by old BSD systems, 47337Sigor@sysoev.ru * see comment in nxt_conn_io_accept(). 48337Sigor@sysoev.ru */ 49337Sigor@sysoev.ru sa->u.sockaddr.sa_family = ls->sockaddr->u.sockaddr.sa_family; 50337Sigor@sysoev.ru } 51337Sigor@sysoev.ru 52337Sigor@sysoev.ru return sa; 53337Sigor@sysoev.ru } 54337Sigor@sysoev.ru 55337Sigor@sysoev.ru 56337Sigor@sysoev.ru void 57337Sigor@sysoev.ru nxt_sockaddr_cache_free(nxt_event_engine_t *engine, nxt_conn_t *c) 58337Sigor@sysoev.ru { 59358Sigor@sysoev.ru nxt_event_engine_mem_free(engine, &c->remote->cache_hint, c->remote); 60337Sigor@sysoev.ru } 61337Sigor@sysoev.ru 62337Sigor@sysoev.ru 63337Sigor@sysoev.ru nxt_sockaddr_t * 6465Sigor@sysoev.ru nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length) 650Sigor@sysoev.ru { 6613Sigor@sysoev.ru size_t size; 670Sigor@sysoev.ru nxt_sockaddr_t *sa; 680Sigor@sysoev.ru 6913Sigor@sysoev.ru size = offsetof(nxt_sockaddr_t, u) + socklen + address_length; 7013Sigor@sysoev.ru 710Sigor@sysoev.ru /* 720Sigor@sysoev.ru * The current struct sockaddr's define 32-bit fields at maximum 730Sigor@sysoev.ru * and may define 64-bit AF_INET6 fields in the future. Alignment 7465Sigor@sysoev.ru * of memory allocated by nxt_mp_zalloc() is enough for these fields. 750Sigor@sysoev.ru * If 128-bit alignment will be required then nxt_mem_malloc() and 760Sigor@sysoev.ru * nxt_memzero() should be used instead. 770Sigor@sysoev.ru */ 7813Sigor@sysoev.ru 7965Sigor@sysoev.ru sa = nxt_mp_zalloc(mp, size); 800Sigor@sysoev.ru 810Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 8213Sigor@sysoev.ru sa->socklen = socklen; 8313Sigor@sysoev.ru sa->length = address_length; 840Sigor@sysoev.ru } 850Sigor@sysoev.ru 860Sigor@sysoev.ru return sa; 870Sigor@sysoev.ru } 880Sigor@sysoev.ru 890Sigor@sysoev.ru 900Sigor@sysoev.ru nxt_sockaddr_t * 9165Sigor@sysoev.ru nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length, 9265Sigor@sysoev.ru size_t address_length) 930Sigor@sysoev.ru { 940Sigor@sysoev.ru size_t size, copy; 950Sigor@sysoev.ru nxt_sockaddr_t *sa; 960Sigor@sysoev.ru 9710Sigor@sysoev.ru size = length; 9810Sigor@sysoev.ru copy = length; 990Sigor@sysoev.ru 1000Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1010Sigor@sysoev.ru 1020Sigor@sysoev.ru /* 1030Sigor@sysoev.ru * Unspecified Unix domain sockaddr_un form and length are very 104211Sru@nginx.com * platform depended (see comment in nxt_socket.h). Here they are 1050Sigor@sysoev.ru * normalized to the sockaddr_un with single zero byte sun_path[]. 1060Sigor@sysoev.ru */ 1070Sigor@sysoev.ru 1080Sigor@sysoev.ru if (size <= offsetof(struct sockaddr_un, sun_path)) { 1090Sigor@sysoev.ru /* 1100Sigor@sysoev.ru * Small socket length means a short unspecified Unix domain 1110Sigor@sysoev.ru * socket address: 1120Sigor@sysoev.ru * 1130Sigor@sysoev.ru * getsockname() and getpeername() on OpenBSD prior to 5.3 1140Sigor@sysoev.ru * return zero length and does not update a passed sockaddr 1150Sigor@sysoev.ru * buffer at all. 1160Sigor@sysoev.ru * 1170Sigor@sysoev.ru * Linux returns length equal to 2, i.e. sockaddr_un without 1180Sigor@sysoev.ru * sun_path[], unix(7): 1190Sigor@sysoev.ru * 1200Sigor@sysoev.ru * unnamed: A stream socket that has not been bound 1210Sigor@sysoev.ru * to a pathname using bind(2) has no name. Likewise, 1220Sigor@sysoev.ru * the two sockets created by socketpair(2) are unnamed. 1230Sigor@sysoev.ru * When the address of an unnamed socket is returned by 1240Sigor@sysoev.ru * getsockname(2), getpeername(2), and accept(2), its 1250Sigor@sysoev.ru * length is sizeof(sa_family_t), and sun_path should 1260Sigor@sysoev.ru * not be inspected. 1270Sigor@sysoev.ru */ 1280Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1; 1290Sigor@sysoev.ru 1300Sigor@sysoev.ru #if !(NXT_LINUX) 1310Sigor@sysoev.ru 1320Sigor@sysoev.ru } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') { 1330Sigor@sysoev.ru /* 1340Sigor@sysoev.ru * Omit nonsignificant zeros of the unspecified Unix domain socket 1350Sigor@sysoev.ru * address. This test is disabled for Linux since Linux abstract 1360Sigor@sysoev.ru * socket address also starts with zero. However Linux unspecified 1370Sigor@sysoev.ru * Unix domain socket address is short and is handled above. 1380Sigor@sysoev.ru */ 1390Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1; 1400Sigor@sysoev.ru copy = size; 1410Sigor@sysoev.ru 1420Sigor@sysoev.ru #endif 1430Sigor@sysoev.ru } 1440Sigor@sysoev.ru 1450Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 1460Sigor@sysoev.ru 14713Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, size, address_length); 1480Sigor@sysoev.ru 1490Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 1500Sigor@sysoev.ru nxt_memcpy(&sa->u.sockaddr, sockaddr, copy); 1510Sigor@sysoev.ru 1520Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD) 1530Sigor@sysoev.ru 15410Sigor@sysoev.ru if (length == 0) { 1550Sigor@sysoev.ru sa->u.sockaddr.sa_family = AF_UNIX; 1560Sigor@sysoev.ru } 1570Sigor@sysoev.ru 1580Sigor@sysoev.ru #endif 1590Sigor@sysoev.ru } 1600Sigor@sysoev.ru 1610Sigor@sysoev.ru return sa; 1620Sigor@sysoev.ru } 1630Sigor@sysoev.ru 1640Sigor@sysoev.ru 1650Sigor@sysoev.ru nxt_sockaddr_t * 16665Sigor@sysoev.ru nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src) 1670Sigor@sysoev.ru { 16810Sigor@sysoev.ru size_t length; 1690Sigor@sysoev.ru nxt_sockaddr_t *dst; 1700Sigor@sysoev.ru 17113Sigor@sysoev.ru length = offsetof(nxt_sockaddr_t, u) + src->socklen; 1720Sigor@sysoev.ru 17365Sigor@sysoev.ru dst = nxt_mp_alloc(mp, length); 1740Sigor@sysoev.ru 1750Sigor@sysoev.ru if (nxt_fast_path(dst != NULL)) { 17610Sigor@sysoev.ru nxt_memcpy(dst, src, length); 1770Sigor@sysoev.ru } 1780Sigor@sysoev.ru 1790Sigor@sysoev.ru return dst; 1800Sigor@sysoev.ru } 1810Sigor@sysoev.ru 1820Sigor@sysoev.ru 1830Sigor@sysoev.ru nxt_sockaddr_t * 18465Sigor@sysoev.ru nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s) 1850Sigor@sysoev.ru { 1860Sigor@sysoev.ru int ret; 18713Sigor@sysoev.ru size_t length; 1880Sigor@sysoev.ru socklen_t socklen; 1890Sigor@sysoev.ru nxt_sockaddr_buf_t sockaddr; 1900Sigor@sysoev.ru 1910Sigor@sysoev.ru socklen = NXT_SOCKADDR_LEN; 1920Sigor@sysoev.ru 1930Sigor@sysoev.ru ret = getsockname(s, &sockaddr.buf, &socklen); 1940Sigor@sysoev.ru 1950Sigor@sysoev.ru if (nxt_fast_path(ret == 0)) { 19613Sigor@sysoev.ru 19713Sigor@sysoev.ru switch (sockaddr.buf.sa_family) { 19813Sigor@sysoev.ru #if (NXT_INET6) 19913Sigor@sysoev.ru case AF_INET6: 20013Sigor@sysoev.ru length = NXT_INET6_ADDR_STR_LEN; 20113Sigor@sysoev.ru break; 20213Sigor@sysoev.ru #endif 20313Sigor@sysoev.ru 20413Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 20513Sigor@sysoev.ru case AF_UNIX: 20613Sigor@sysoev.ru length = sizeof("unix:") - 1 + socklen; 20713Sigor@sysoev.ru #endif 20813Sigor@sysoev.ru break; 20913Sigor@sysoev.ru 21013Sigor@sysoev.ru case AF_INET: 21113Sigor@sysoev.ru length = NXT_INET_ADDR_STR_LEN; 21213Sigor@sysoev.ru break; 21313Sigor@sysoev.ru 21413Sigor@sysoev.ru default: 21513Sigor@sysoev.ru length = 0; 21613Sigor@sysoev.ru break; 21713Sigor@sysoev.ru } 21813Sigor@sysoev.ru 21913Sigor@sysoev.ru return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length); 2200Sigor@sysoev.ru } 2210Sigor@sysoev.ru 22213Sigor@sysoev.ru nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno); 2230Sigor@sysoev.ru 2240Sigor@sysoev.ru return NULL; 2250Sigor@sysoev.ru } 2260Sigor@sysoev.ru 2270Sigor@sysoev.ru 22813Sigor@sysoev.ru void 22913Sigor@sysoev.ru nxt_sockaddr_text(nxt_sockaddr_t *sa) 2300Sigor@sysoev.ru { 23113Sigor@sysoev.ru size_t offset; 23213Sigor@sysoev.ru u_char *p, *start, *end, *octet; 23313Sigor@sysoev.ru uint32_t port; 23413Sigor@sysoev.ru 235102Sigor@sysoev.ru offset = offsetof(nxt_sockaddr_t, u) + sa->socklen; 236102Sigor@sysoev.ru sa->start = offset; 237110Sigor@sysoev.ru sa->port_start = offset; 238102Sigor@sysoev.ru 239102Sigor@sysoev.ru start = nxt_pointer_to(sa, offset); 240358Sigor@sysoev.ru end = start + sa->length; 24113Sigor@sysoev.ru 24213Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 24313Sigor@sysoev.ru 24413Sigor@sysoev.ru case AF_INET: 24513Sigor@sysoev.ru sa->address_start = offset; 24613Sigor@sysoev.ru 24713Sigor@sysoev.ru octet = (u_char *) &sa->u.sockaddr_in.sin_addr; 24813Sigor@sysoev.ru 24913Sigor@sysoev.ru p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud", 25013Sigor@sysoev.ru octet[0], octet[1], octet[2], octet[3]); 25113Sigor@sysoev.ru 25213Sigor@sysoev.ru sa->address_length = p - start; 253110Sigor@sysoev.ru sa->port_start += sa->address_length + 1; 2540Sigor@sysoev.ru 25513Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port; 25613Sigor@sysoev.ru 25713Sigor@sysoev.ru break; 25813Sigor@sysoev.ru 25913Sigor@sysoev.ru #if (NXT_INET6) 26013Sigor@sysoev.ru 26113Sigor@sysoev.ru case AF_INET6: 262101Sigor@sysoev.ru sa->address_start = offset + 1; 26313Sigor@sysoev.ru 26413Sigor@sysoev.ru p = start; 26513Sigor@sysoev.ru *p++ = '['; 26613Sigor@sysoev.ru 26713Sigor@sysoev.ru p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 26813Sigor@sysoev.ru 26913Sigor@sysoev.ru sa->address_length = p - (start + 1); 270110Sigor@sysoev.ru sa->port_start += sa->address_length + 3; 27120Sigor@sysoev.ru 27213Sigor@sysoev.ru *p++ = ']'; 2730Sigor@sysoev.ru 27413Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port; 27513Sigor@sysoev.ru 27613Sigor@sysoev.ru break; 27713Sigor@sysoev.ru 27813Sigor@sysoev.ru #endif 27913Sigor@sysoev.ru 28013Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 28113Sigor@sysoev.ru 28213Sigor@sysoev.ru case AF_UNIX: 28313Sigor@sysoev.ru sa->address_start = offset; 28413Sigor@sysoev.ru 285100Sigor@sysoev.ru p = (u_char *) sa->u.sockaddr_un.sun_path; 2860Sigor@sysoev.ru 28713Sigor@sysoev.ru #if (NXT_LINUX) 28813Sigor@sysoev.ru 28913Sigor@sysoev.ru if (p[0] == '\0') { 290493Spluknet@nginx.com size_t length; 2910Sigor@sysoev.ru 29213Sigor@sysoev.ru /* Linux abstract socket address has no trailing zero. */ 29313Sigor@sysoev.ru length = sa->socklen - offsetof(struct sockaddr_un, sun_path); 29413Sigor@sysoev.ru 29513Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1); 29613Sigor@sysoev.ru 29713Sigor@sysoev.ru } else { 29813Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:%s", p); 29913Sigor@sysoev.ru } 30013Sigor@sysoev.ru 30113Sigor@sysoev.ru #else /* !(NXT_LINUX) */ 30213Sigor@sysoev.ru 30313Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:%s", p); 3040Sigor@sysoev.ru 30513Sigor@sysoev.ru #endif 30613Sigor@sysoev.ru 30713Sigor@sysoev.ru sa->address_length = p - start; 308110Sigor@sysoev.ru sa->port_start += sa->address_length; 30913Sigor@sysoev.ru sa->length = p - start; 31013Sigor@sysoev.ru 31113Sigor@sysoev.ru return; 31213Sigor@sysoev.ru 31313Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 31413Sigor@sysoev.ru 31513Sigor@sysoev.ru default: 31613Sigor@sysoev.ru return; 3170Sigor@sysoev.ru } 3180Sigor@sysoev.ru 31913Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%d", ntohs(port)); 32013Sigor@sysoev.ru 32113Sigor@sysoev.ru sa->length = p - start; 3220Sigor@sysoev.ru } 3230Sigor@sysoev.ru 3240Sigor@sysoev.ru 3250Sigor@sysoev.ru uint32_t 32613Sigor@sysoev.ru nxt_sockaddr_port_number(nxt_sockaddr_t *sa) 3270Sigor@sysoev.ru { 3280Sigor@sysoev.ru uint32_t port; 3290Sigor@sysoev.ru 3300Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 3310Sigor@sysoev.ru 3320Sigor@sysoev.ru #if (NXT_INET6) 3330Sigor@sysoev.ru 3340Sigor@sysoev.ru case AF_INET6: 3350Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port; 3360Sigor@sysoev.ru break; 3370Sigor@sysoev.ru 3380Sigor@sysoev.ru #endif 3390Sigor@sysoev.ru 3400Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 3410Sigor@sysoev.ru 3420Sigor@sysoev.ru case AF_UNIX: 3430Sigor@sysoev.ru return 0; 3440Sigor@sysoev.ru 3450Sigor@sysoev.ru #endif 3460Sigor@sysoev.ru 3470Sigor@sysoev.ru default: 3480Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port; 3490Sigor@sysoev.ru break; 3500Sigor@sysoev.ru } 3510Sigor@sysoev.ru 3520Sigor@sysoev.ru return ntohs((uint16_t) port); 3530Sigor@sysoev.ru } 3540Sigor@sysoev.ru 3550Sigor@sysoev.ru 3560Sigor@sysoev.ru nxt_bool_t 3570Sigor@sysoev.ru nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) 3580Sigor@sysoev.ru { 35913Sigor@sysoev.ru if (sa1->socklen != sa2->socklen) { 3600Sigor@sysoev.ru return 0; 3610Sigor@sysoev.ru } 3620Sigor@sysoev.ru 3630Sigor@sysoev.ru if (sa1->type != sa2->type) { 3640Sigor@sysoev.ru return 0; 3650Sigor@sysoev.ru } 3660Sigor@sysoev.ru 3670Sigor@sysoev.ru if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) { 3680Sigor@sysoev.ru return 0; 3690Sigor@sysoev.ru } 3700Sigor@sysoev.ru 3710Sigor@sysoev.ru /* 3720Sigor@sysoev.ru * sockaddr struct's cannot be compared in whole since kernel 3730Sigor@sysoev.ru * may fill some fields in inherited sockaddr struct's. 3740Sigor@sysoev.ru */ 3750Sigor@sysoev.ru 3760Sigor@sysoev.ru switch (sa1->u.sockaddr.sa_family) { 3770Sigor@sysoev.ru 3780Sigor@sysoev.ru #if (NXT_INET6) 3790Sigor@sysoev.ru 3800Sigor@sysoev.ru case AF_INET6: 3810Sigor@sysoev.ru if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) { 3820Sigor@sysoev.ru return 0; 3830Sigor@sysoev.ru } 3840Sigor@sysoev.ru 3850Sigor@sysoev.ru if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr, 3860Sigor@sysoev.ru &sa2->u.sockaddr_in6.sin6_addr, 16) 3870Sigor@sysoev.ru != 0) 3880Sigor@sysoev.ru { 3890Sigor@sysoev.ru return 0; 3900Sigor@sysoev.ru } 3910Sigor@sysoev.ru 3920Sigor@sysoev.ru return 1; 3930Sigor@sysoev.ru 3940Sigor@sysoev.ru #endif 3950Sigor@sysoev.ru 3960Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 3970Sigor@sysoev.ru 3980Sigor@sysoev.ru case AF_UNIX: 3990Sigor@sysoev.ru { 40010Sigor@sysoev.ru size_t length; 4010Sigor@sysoev.ru 40213Sigor@sysoev.ru length = sa1->socklen - offsetof(struct sockaddr_un, sun_path); 4030Sigor@sysoev.ru 4040Sigor@sysoev.ru if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path, 40510Sigor@sysoev.ru &sa2->u.sockaddr_un.sun_path, length) 4060Sigor@sysoev.ru != 0) 4070Sigor@sysoev.ru { 4080Sigor@sysoev.ru return 0; 4090Sigor@sysoev.ru } 4100Sigor@sysoev.ru 4110Sigor@sysoev.ru return 1; 4120Sigor@sysoev.ru } 4130Sigor@sysoev.ru 4140Sigor@sysoev.ru #endif 4150Sigor@sysoev.ru 4160Sigor@sysoev.ru default: /* AF_INET */ 4170Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) { 4180Sigor@sysoev.ru return 0; 4190Sigor@sysoev.ru } 4200Sigor@sysoev.ru 4210Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_addr.s_addr 4220Sigor@sysoev.ru != sa2->u.sockaddr_in.sin_addr.s_addr) 4230Sigor@sysoev.ru { 4240Sigor@sysoev.ru return 0; 4250Sigor@sysoev.ru } 4260Sigor@sysoev.ru 4270Sigor@sysoev.ru return 1; 4280Sigor@sysoev.ru } 4290Sigor@sysoev.ru } 4300Sigor@sysoev.ru 4310Sigor@sysoev.ru 4320Sigor@sysoev.ru size_t 4330Sigor@sysoev.ru nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port) 4340Sigor@sysoev.ru { 4350Sigor@sysoev.ru u_char *p; 4360Sigor@sysoev.ru 4370Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 4380Sigor@sysoev.ru 4390Sigor@sysoev.ru case AF_INET: 4400Sigor@sysoev.ru p = (u_char *) &sa->u.sockaddr_in.sin_addr; 4410Sigor@sysoev.ru 4420Sigor@sysoev.ru if (port) { 4430Sigor@sysoev.ru p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d", 4440Sigor@sysoev.ru p[0], p[1], p[2], p[3], 4450Sigor@sysoev.ru ntohs(sa->u.sockaddr_in.sin_port)); 4460Sigor@sysoev.ru } else { 4470Sigor@sysoev.ru p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud", 4480Sigor@sysoev.ru p[0], p[1], p[2], p[3]); 4490Sigor@sysoev.ru } 4500Sigor@sysoev.ru 4510Sigor@sysoev.ru return p - buf; 4520Sigor@sysoev.ru 4530Sigor@sysoev.ru #if (NXT_INET6) 4540Sigor@sysoev.ru 4550Sigor@sysoev.ru case AF_INET6: 4560Sigor@sysoev.ru p = buf; 4570Sigor@sysoev.ru 4580Sigor@sysoev.ru if (port) { 4590Sigor@sysoev.ru *p++ = '['; 4600Sigor@sysoev.ru } 4610Sigor@sysoev.ru 4620Sigor@sysoev.ru p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 4630Sigor@sysoev.ru 4640Sigor@sysoev.ru if (port) { 4650Sigor@sysoev.ru p = nxt_sprintf(p, end, "]:%d", 4660Sigor@sysoev.ru ntohs(sa->u.sockaddr_in6.sin6_port)); 4670Sigor@sysoev.ru } 4680Sigor@sysoev.ru 4690Sigor@sysoev.ru return p - buf; 4700Sigor@sysoev.ru #endif 4710Sigor@sysoev.ru 4720Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 4730Sigor@sysoev.ru 4740Sigor@sysoev.ru case AF_UNIX: 4750Sigor@sysoev.ru 4760Sigor@sysoev.ru #if (NXT_LINUX) 4770Sigor@sysoev.ru 4780Sigor@sysoev.ru p = (u_char *) sa->u.sockaddr_un.sun_path; 4790Sigor@sysoev.ru 4800Sigor@sysoev.ru if (p[0] == '\0') { 481493Spluknet@nginx.com size_t length; 4820Sigor@sysoev.ru 4830Sigor@sysoev.ru /* Linux abstract socket address has no trailing zero. */ 4840Sigor@sysoev.ru 48513Sigor@sysoev.ru length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1; 48610Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1); 4870Sigor@sysoev.ru 4880Sigor@sysoev.ru } else { 4890Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:%s", p); 4900Sigor@sysoev.ru } 4910Sigor@sysoev.ru 4920Sigor@sysoev.ru #else /* !(NXT_LINUX) */ 4930Sigor@sysoev.ru 4940Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path); 4950Sigor@sysoev.ru 4960Sigor@sysoev.ru #endif 4970Sigor@sysoev.ru 4980Sigor@sysoev.ru return p - buf; 4990Sigor@sysoev.ru 5000Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 5010Sigor@sysoev.ru 5020Sigor@sysoev.ru default: 5030Sigor@sysoev.ru return 0; 5040Sigor@sysoev.ru } 5050Sigor@sysoev.ru } 5060Sigor@sysoev.ru 5070Sigor@sysoev.ru 5080Sigor@sysoev.ru #if (NXT_INET6) 5090Sigor@sysoev.ru 5100Sigor@sysoev.ru static u_char * 5110Sigor@sysoev.ru nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end) 5120Sigor@sysoev.ru { 513101Sigor@sysoev.ru u_char *p; 514101Sigor@sysoev.ru size_t zero_groups, last_zero_groups, ipv6_bytes; 515101Sigor@sysoev.ru nxt_uint_t i, zero_start, last_zero_start; 5160Sigor@sysoev.ru 517101Sigor@sysoev.ru const size_t max_inet6_length = 518101Sigor@sysoev.ru sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") - 1; 519101Sigor@sysoev.ru 520101Sigor@sysoev.ru if (buf + max_inet6_length > end) { 5210Sigor@sysoev.ru return buf; 5220Sigor@sysoev.ru } 5230Sigor@sysoev.ru 5240Sigor@sysoev.ru zero_start = 8; 5250Sigor@sysoev.ru zero_groups = 0; 5260Sigor@sysoev.ru last_zero_start = 8; 5270Sigor@sysoev.ru last_zero_groups = 0; 5280Sigor@sysoev.ru 5290Sigor@sysoev.ru for (i = 0; i < 16; i += 2) { 5300Sigor@sysoev.ru 5310Sigor@sysoev.ru if (addr[i] == 0 && addr[i + 1] == 0) { 5320Sigor@sysoev.ru 5330Sigor@sysoev.ru if (last_zero_groups == 0) { 5340Sigor@sysoev.ru last_zero_start = i; 5350Sigor@sysoev.ru } 5360Sigor@sysoev.ru 5370Sigor@sysoev.ru last_zero_groups++; 5380Sigor@sysoev.ru 5390Sigor@sysoev.ru } else { 5400Sigor@sysoev.ru if (zero_groups < last_zero_groups) { 5410Sigor@sysoev.ru zero_groups = last_zero_groups; 5420Sigor@sysoev.ru zero_start = last_zero_start; 5430Sigor@sysoev.ru } 5440Sigor@sysoev.ru 5450Sigor@sysoev.ru last_zero_groups = 0; 5460Sigor@sysoev.ru } 5470Sigor@sysoev.ru } 5480Sigor@sysoev.ru 5490Sigor@sysoev.ru if (zero_groups < last_zero_groups) { 5500Sigor@sysoev.ru zero_groups = last_zero_groups; 5510Sigor@sysoev.ru zero_start = last_zero_start; 5520Sigor@sysoev.ru } 5530Sigor@sysoev.ru 5540Sigor@sysoev.ru ipv6_bytes = 16; 5550Sigor@sysoev.ru p = buf; 5560Sigor@sysoev.ru 5570Sigor@sysoev.ru if (zero_start == 0) { 5580Sigor@sysoev.ru 5590Sigor@sysoev.ru /* IPv4-mapped address */ 560*611Svbart@nginx.com if ((zero_groups == 5 && addr[10] == 0xFF && addr[11] == 0xFF) 5610Sigor@sysoev.ru /* IPv4-compatible address */ 5620Sigor@sysoev.ru || (zero_groups == 6) 5630Sigor@sysoev.ru /* not IPv6 loopback address */ 5640Sigor@sysoev.ru || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1)) 5650Sigor@sysoev.ru { 5660Sigor@sysoev.ru ipv6_bytes = 12; 5670Sigor@sysoev.ru } 5680Sigor@sysoev.ru 5690Sigor@sysoev.ru *p++ = ':'; 5700Sigor@sysoev.ru } 5710Sigor@sysoev.ru 5720Sigor@sysoev.ru for (i = 0; i < ipv6_bytes; i += 2) { 5730Sigor@sysoev.ru 5740Sigor@sysoev.ru if (i == zero_start) { 5750Sigor@sysoev.ru /* Output maximum number of consecutive zero groups as "::". */ 5760Sigor@sysoev.ru i += (zero_groups - 1) * 2; 5770Sigor@sysoev.ru *p++ = ':'; 5780Sigor@sysoev.ru continue; 5790Sigor@sysoev.ru } 5800Sigor@sysoev.ru 5810Sigor@sysoev.ru p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]); 5820Sigor@sysoev.ru 5830Sigor@sysoev.ru if (i < 14) { 5840Sigor@sysoev.ru *p++ = ':'; 5850Sigor@sysoev.ru } 5860Sigor@sysoev.ru } 5870Sigor@sysoev.ru 5880Sigor@sysoev.ru if (ipv6_bytes == 12) { 5890Sigor@sysoev.ru p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud", 5900Sigor@sysoev.ru addr[12], addr[13], addr[14], addr[15]); 5910Sigor@sysoev.ru } 5920Sigor@sysoev.ru 5930Sigor@sysoev.ru return p; 5940Sigor@sysoev.ru } 5950Sigor@sysoev.ru 5960Sigor@sysoev.ru #endif 5970Sigor@sysoev.ru 5980Sigor@sysoev.ru 59999Sigor@sysoev.ru nxt_sockaddr_t * 60099Sigor@sysoev.ru nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr) 60199Sigor@sysoev.ru { 60299Sigor@sysoev.ru nxt_sockaddr_t *sa; 60399Sigor@sysoev.ru 60499Sigor@sysoev.ru if (addr->length > 6 && nxt_memcmp(addr->start, "unix:", 5) == 0) { 60599Sigor@sysoev.ru sa = nxt_sockaddr_unix_parse(mp, addr); 60699Sigor@sysoev.ru 60799Sigor@sysoev.ru } else if (addr->length != 0 && addr->start[0] == '[') { 60899Sigor@sysoev.ru sa = nxt_sockaddr_inet6_parse(mp, addr); 60999Sigor@sysoev.ru 61099Sigor@sysoev.ru } else { 61199Sigor@sysoev.ru sa = nxt_sockaddr_inet_parse(mp, addr); 61299Sigor@sysoev.ru } 61399Sigor@sysoev.ru 61499Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 61599Sigor@sysoev.ru nxt_sockaddr_text(sa); 61699Sigor@sysoev.ru } 61799Sigor@sysoev.ru 61899Sigor@sysoev.ru return sa; 61999Sigor@sysoev.ru } 62099Sigor@sysoev.ru 62199Sigor@sysoev.ru 62299Sigor@sysoev.ru static nxt_sockaddr_t * 62399Sigor@sysoev.ru nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr) 62499Sigor@sysoev.ru { 62599Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 62699Sigor@sysoev.ru size_t length, socklen; 62799Sigor@sysoev.ru u_char *path; 62899Sigor@sysoev.ru nxt_sockaddr_t *sa; 62999Sigor@sysoev.ru 63099Sigor@sysoev.ru /* 63199Sigor@sysoev.ru * Actual sockaddr_un length can be lesser or even larger than defined 632211Sru@nginx.com * struct sockaddr_un length (see comment in nxt_socket.h). So 63399Sigor@sysoev.ru * limit maximum Unix domain socket address length by defined sun_path[] 63499Sigor@sysoev.ru * length because some OSes accept addresses twice larger than defined 63599Sigor@sysoev.ru * struct sockaddr_un. Also reserve space for a trailing zero to avoid 63699Sigor@sysoev.ru * ambiguity, since many OSes accept Unix domain socket addresses 63799Sigor@sysoev.ru * without a trailing zero. 63899Sigor@sysoev.ru */ 63999Sigor@sysoev.ru const size_t max_len = sizeof(struct sockaddr_un) 64099Sigor@sysoev.ru - offsetof(struct sockaddr_un, sun_path) - 1; 64199Sigor@sysoev.ru 64299Sigor@sysoev.ru /* Cutting "unix:". */ 64399Sigor@sysoev.ru length = addr->length - 5; 64499Sigor@sysoev.ru path = addr->start + 5; 64599Sigor@sysoev.ru 64699Sigor@sysoev.ru if (length > max_len) { 64799Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, 64899Sigor@sysoev.ru "unix domain socket \"%V\" name is too long", 64999Sigor@sysoev.ru addr); 65099Sigor@sysoev.ru return NULL; 65199Sigor@sysoev.ru } 65299Sigor@sysoev.ru 65399Sigor@sysoev.ru socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; 65499Sigor@sysoev.ru 65599Sigor@sysoev.ru #if (NXT_LINUX) 65699Sigor@sysoev.ru 65799Sigor@sysoev.ru /* 65899Sigor@sysoev.ru * Linux unix(7): 65999Sigor@sysoev.ru * 66099Sigor@sysoev.ru * abstract: an abstract socket address is distinguished by the fact 66199Sigor@sysoev.ru * that sun_path[0] is a null byte ('\0'). The socket's address in 66299Sigor@sysoev.ru * this namespace is given by the additional bytes in sun_path that 66399Sigor@sysoev.ru * are covered by the specified length of the address structure. 66499Sigor@sysoev.ru * (Null bytes in the name have no special significance.) 66599Sigor@sysoev.ru */ 66699Sigor@sysoev.ru if (path[0] == '@') { 66799Sigor@sysoev.ru path[0] = '\0'; 66899Sigor@sysoev.ru socklen--; 66999Sigor@sysoev.ru } 67099Sigor@sysoev.ru 67199Sigor@sysoev.ru #endif 67299Sigor@sysoev.ru 67399Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, socklen, addr->length); 67499Sigor@sysoev.ru 67599Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 67699Sigor@sysoev.ru sa->u.sockaddr_un.sun_family = AF_UNIX; 67799Sigor@sysoev.ru nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length); 67899Sigor@sysoev.ru } 67999Sigor@sysoev.ru 68099Sigor@sysoev.ru return sa; 68199Sigor@sysoev.ru 68299Sigor@sysoev.ru #else /* !(NXT_HAVE_UNIX_DOMAIN) */ 68399Sigor@sysoev.ru 68499Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, 68599Sigor@sysoev.ru "unix domain socket \"%V\" is not supported", addr); 68699Sigor@sysoev.ru 68799Sigor@sysoev.ru return NULL; 68899Sigor@sysoev.ru 68999Sigor@sysoev.ru #endif 69099Sigor@sysoev.ru } 69199Sigor@sysoev.ru 69299Sigor@sysoev.ru 69399Sigor@sysoev.ru static nxt_sockaddr_t * 69499Sigor@sysoev.ru nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr) 69599Sigor@sysoev.ru { 69699Sigor@sysoev.ru #if (NXT_INET6) 69799Sigor@sysoev.ru u_char *p, *start, *end; 69899Sigor@sysoev.ru size_t length; 69999Sigor@sysoev.ru nxt_int_t ret, port; 70099Sigor@sysoev.ru nxt_sockaddr_t *sa; 70199Sigor@sysoev.ru 70299Sigor@sysoev.ru length = addr->length - 1; 70399Sigor@sysoev.ru start = addr->start + 1; 70499Sigor@sysoev.ru 70599Sigor@sysoev.ru end = nxt_memchr(start, ']', length); 70699Sigor@sysoev.ru 70799Sigor@sysoev.ru if (end != NULL) { 70899Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6), 70999Sigor@sysoev.ru NXT_INET6_ADDR_STR_LEN); 71099Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 71199Sigor@sysoev.ru return NULL; 71299Sigor@sysoev.ru } 71399Sigor@sysoev.ru 71499Sigor@sysoev.ru ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start); 71599Sigor@sysoev.ru 71699Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 71799Sigor@sysoev.ru p = end + 1; 71899Sigor@sysoev.ru length = (start + length) - p; 71999Sigor@sysoev.ru 72099Sigor@sysoev.ru if (length > 2 && *p == ':') { 72199Sigor@sysoev.ru port = nxt_int_parse(p + 1, length - 1); 72299Sigor@sysoev.ru 72399Sigor@sysoev.ru if (port > 0 && port < 65536) { 72499Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port); 72599Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_family = AF_INET6; 72699Sigor@sysoev.ru 72799Sigor@sysoev.ru return sa; 72899Sigor@sysoev.ru } 72999Sigor@sysoev.ru } 73099Sigor@sysoev.ru 73199Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr); 73299Sigor@sysoev.ru 73399Sigor@sysoev.ru return NULL; 73499Sigor@sysoev.ru } 73599Sigor@sysoev.ru } 73699Sigor@sysoev.ru 73799Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"", addr); 73899Sigor@sysoev.ru 73999Sigor@sysoev.ru return NULL; 74099Sigor@sysoev.ru 74199Sigor@sysoev.ru #else /* !(NXT_INET6) */ 74299Sigor@sysoev.ru 74399Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "IPv6 socket \"%V\" is not supported", 74499Sigor@sysoev.ru addr); 74599Sigor@sysoev.ru return NULL; 74699Sigor@sysoev.ru 74799Sigor@sysoev.ru #endif 74899Sigor@sysoev.ru } 74999Sigor@sysoev.ru 75099Sigor@sysoev.ru 75199Sigor@sysoev.ru static nxt_sockaddr_t * 75299Sigor@sysoev.ru nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr) 75399Sigor@sysoev.ru { 75499Sigor@sysoev.ru u_char *p; 75599Sigor@sysoev.ru size_t length; 75699Sigor@sysoev.ru nxt_int_t port; 75799Sigor@sysoev.ru in_addr_t inaddr; 75899Sigor@sysoev.ru nxt_sockaddr_t *sa; 75999Sigor@sysoev.ru 76099Sigor@sysoev.ru p = nxt_memchr(addr->start, ':', addr->length); 76199Sigor@sysoev.ru 76299Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 76399Sigor@sysoev.ru inaddr = INADDR_ANY; 76499Sigor@sysoev.ru length = p - addr->start; 76599Sigor@sysoev.ru 76699Sigor@sysoev.ru if (length != 1 || addr->start[0] != '*') { 76799Sigor@sysoev.ru inaddr = nxt_inet_addr(addr->start, length); 76899Sigor@sysoev.ru 76999Sigor@sysoev.ru if (nxt_slow_path(inaddr == INADDR_NONE)) { 77099Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"", 77199Sigor@sysoev.ru addr); 77299Sigor@sysoev.ru return NULL; 77399Sigor@sysoev.ru } 77499Sigor@sysoev.ru } 77599Sigor@sysoev.ru 77699Sigor@sysoev.ru p++; 77799Sigor@sysoev.ru length = (addr->start + addr->length) - p; 77899Sigor@sysoev.ru port = nxt_int_parse(p, length); 77999Sigor@sysoev.ru 78099Sigor@sysoev.ru if (port > 0 && port < 65536) { 78199Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), 78299Sigor@sysoev.ru NXT_INET_ADDR_STR_LEN); 78399Sigor@sysoev.ru 78499Sigor@sysoev.ru if (nxt_slow_path(sa != NULL)) { 78599Sigor@sysoev.ru sa->u.sockaddr_in.sin_family = AF_INET; 78699Sigor@sysoev.ru sa->u.sockaddr_in.sin_port = htons((in_port_t) port); 78799Sigor@sysoev.ru sa->u.sockaddr_in.sin_addr.s_addr = inaddr; 78899Sigor@sysoev.ru } 78999Sigor@sysoev.ru 79099Sigor@sysoev.ru return sa; 79199Sigor@sysoev.ru } 79299Sigor@sysoev.ru } 79399Sigor@sysoev.ru 79499Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr); 79599Sigor@sysoev.ru 79699Sigor@sysoev.ru return NULL; 79799Sigor@sysoev.ru } 79899Sigor@sysoev.ru 79999Sigor@sysoev.ru 8000Sigor@sysoev.ru void 8010Sigor@sysoev.ru nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs) 8020Sigor@sysoev.ru { 8030Sigor@sysoev.ru u_char *p; 80410Sigor@sysoev.ru size_t length; 8050Sigor@sysoev.ru nxt_int_t ret; 8060Sigor@sysoev.ru nxt_work_handler_t handler; 8070Sigor@sysoev.ru 8080Sigor@sysoev.ru nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse"); 8090Sigor@sysoev.ru 81010Sigor@sysoev.ru length = jbs->addr.length; 81110Sigor@sysoev.ru p = jbs->addr.start; 8120Sigor@sysoev.ru 81371Svbart@nginx.com if (length > 6 && nxt_memcmp(p, "unix:", 5) == 0) { 8140Sigor@sysoev.ru ret = nxt_job_sockaddr_unix_parse(jbs); 8150Sigor@sysoev.ru 81610Sigor@sysoev.ru } else if (length != 0 && *p == '[') { 8170Sigor@sysoev.ru ret = nxt_job_sockaddr_inet6_parse(jbs); 8180Sigor@sysoev.ru 8190Sigor@sysoev.ru } else { 8200Sigor@sysoev.ru ret = nxt_job_sockaddr_inet_parse(jbs); 8210Sigor@sysoev.ru } 8220Sigor@sysoev.ru 8230Sigor@sysoev.ru switch (ret) { 8240Sigor@sysoev.ru 8250Sigor@sysoev.ru case NXT_OK: 8260Sigor@sysoev.ru handler = jbs->resolve.ready_handler; 8270Sigor@sysoev.ru break; 8280Sigor@sysoev.ru 8290Sigor@sysoev.ru case NXT_ERROR: 8300Sigor@sysoev.ru handler = jbs->resolve.error_handler; 8310Sigor@sysoev.ru break; 8320Sigor@sysoev.ru 8330Sigor@sysoev.ru default: /* NXT_AGAIN */ 8340Sigor@sysoev.ru return; 8350Sigor@sysoev.ru } 8360Sigor@sysoev.ru 8374Sigor@sysoev.ru nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler); 8380Sigor@sysoev.ru } 8390Sigor@sysoev.ru 8400Sigor@sysoev.ru 8410Sigor@sysoev.ru static nxt_int_t 8420Sigor@sysoev.ru nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs) 8430Sigor@sysoev.ru { 8440Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 84510Sigor@sysoev.ru size_t length, socklen; 8460Sigor@sysoev.ru u_char *path; 84765Sigor@sysoev.ru nxt_mp_t *mp; 8480Sigor@sysoev.ru nxt_sockaddr_t *sa; 8490Sigor@sysoev.ru 8500Sigor@sysoev.ru /* 8510Sigor@sysoev.ru * Actual sockaddr_un length can be lesser or even larger than defined 852211Sru@nginx.com * struct sockaddr_un length (see comment in nxt_socket.h). So 8530Sigor@sysoev.ru * limit maximum Unix domain socket address length by defined sun_path[] 8540Sigor@sysoev.ru * length because some OSes accept addresses twice larger than defined 8550Sigor@sysoev.ru * struct sockaddr_un. Also reserve space for a trailing zero to avoid 8560Sigor@sysoev.ru * ambiguity, since many OSes accept Unix domain socket addresses 8570Sigor@sysoev.ru * without a trailing zero. 8580Sigor@sysoev.ru */ 8590Sigor@sysoev.ru const size_t max_len = sizeof(struct sockaddr_un) 8600Sigor@sysoev.ru - offsetof(struct sockaddr_un, sun_path) - 1; 8610Sigor@sysoev.ru 8620Sigor@sysoev.ru /* cutting "unix:" */ 86310Sigor@sysoev.ru length = jbs->addr.length - 5; 86410Sigor@sysoev.ru path = jbs->addr.start + 5; 8650Sigor@sysoev.ru 86610Sigor@sysoev.ru if (length > max_len) { 8670Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 8680Sigor@sysoev.ru "unix domain socket \"%V\" name is too long", 8690Sigor@sysoev.ru &jbs->addr); 8700Sigor@sysoev.ru return NXT_ERROR; 8710Sigor@sysoev.ru } 8720Sigor@sysoev.ru 87310Sigor@sysoev.ru socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; 8740Sigor@sysoev.ru 8750Sigor@sysoev.ru #if (NXT_LINUX) 8760Sigor@sysoev.ru 8770Sigor@sysoev.ru /* 8780Sigor@sysoev.ru * Linux unix(7): 8790Sigor@sysoev.ru * 8800Sigor@sysoev.ru * abstract: an abstract socket address is distinguished by the fact 8810Sigor@sysoev.ru * that sun_path[0] is a null byte ('\0'). The socket's address in 8820Sigor@sysoev.ru * this namespace is given by the additional bytes in sun_path that 8830Sigor@sysoev.ru * are covered by the specified length of the address structure. 8840Sigor@sysoev.ru * (Null bytes in the name have no special significance.) 8850Sigor@sysoev.ru */ 8860Sigor@sysoev.ru if (path[0] == '\0') { 8870Sigor@sysoev.ru socklen--; 8880Sigor@sysoev.ru } 8890Sigor@sysoev.ru 8900Sigor@sysoev.ru #endif 8910Sigor@sysoev.ru 8920Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 8930Sigor@sysoev.ru 89465Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 8950Sigor@sysoev.ru 8960Sigor@sysoev.ru if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) { 89713Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length); 8980Sigor@sysoev.ru 8990Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 9000Sigor@sysoev.ru jbs->resolve.count = 1; 9010Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 9020Sigor@sysoev.ru 9030Sigor@sysoev.ru sa->u.sockaddr_un.sun_family = AF_UNIX; 90410Sigor@sysoev.ru nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length); 9050Sigor@sysoev.ru 9060Sigor@sysoev.ru return NXT_OK; 9070Sigor@sysoev.ru } 9080Sigor@sysoev.ru } 9090Sigor@sysoev.ru 9100Sigor@sysoev.ru return NXT_ERROR; 9110Sigor@sysoev.ru 9120Sigor@sysoev.ru #else /* !(NXT_HAVE_UNIX_DOMAIN) */ 9130Sigor@sysoev.ru 9140Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 9150Sigor@sysoev.ru "unix domain socket \"%V\" is not supported", 9160Sigor@sysoev.ru &jbs->addr); 9170Sigor@sysoev.ru return NXT_ERROR; 9180Sigor@sysoev.ru 9190Sigor@sysoev.ru #endif 9200Sigor@sysoev.ru } 9210Sigor@sysoev.ru 9220Sigor@sysoev.ru 9230Sigor@sysoev.ru static nxt_int_t 9240Sigor@sysoev.ru nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs) 9250Sigor@sysoev.ru { 9260Sigor@sysoev.ru #if (NXT_INET6) 9270Sigor@sysoev.ru u_char *p, *addr, *addr_end; 92810Sigor@sysoev.ru size_t length; 92965Sigor@sysoev.ru nxt_mp_t *mp; 9300Sigor@sysoev.ru nxt_int_t port; 9310Sigor@sysoev.ru nxt_sockaddr_t *sa; 9320Sigor@sysoev.ru struct in6_addr *in6_addr; 9330Sigor@sysoev.ru 93410Sigor@sysoev.ru length = jbs->addr.length - 1; 93510Sigor@sysoev.ru addr = jbs->addr.start + 1; 9360Sigor@sysoev.ru 93710Sigor@sysoev.ru addr_end = nxt_memchr(addr, ']', length); 9380Sigor@sysoev.ru 9390Sigor@sysoev.ru if (addr_end == NULL) { 9400Sigor@sysoev.ru goto invalid_address; 9410Sigor@sysoev.ru } 9420Sigor@sysoev.ru 9430Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 9440Sigor@sysoev.ru 94565Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 9460Sigor@sysoev.ru 9470Sigor@sysoev.ru if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 9480Sigor@sysoev.ru return NXT_ERROR; 9490Sigor@sysoev.ru } 9500Sigor@sysoev.ru 95199Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6), 95299Sigor@sysoev.ru NXT_INET6_ADDR_STR_LEN); 9530Sigor@sysoev.ru 9540Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 9550Sigor@sysoev.ru return NXT_ERROR; 9560Sigor@sysoev.ru } 9570Sigor@sysoev.ru 9580Sigor@sysoev.ru jbs->resolve.count = 1; 9590Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 9600Sigor@sysoev.ru 9610Sigor@sysoev.ru in6_addr = &sa->u.sockaddr_in6.sin6_addr; 9620Sigor@sysoev.ru 9630Sigor@sysoev.ru if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) { 9640Sigor@sysoev.ru goto invalid_address; 9650Sigor@sysoev.ru } 9660Sigor@sysoev.ru 9670Sigor@sysoev.ru p = addr_end + 1; 96810Sigor@sysoev.ru length = (addr + length) - p; 9690Sigor@sysoev.ru 97010Sigor@sysoev.ru if (length == 0) { 9710Sigor@sysoev.ru jbs->no_port = 1; 9720Sigor@sysoev.ru port = jbs->resolve.port; 9730Sigor@sysoev.ru goto found; 9740Sigor@sysoev.ru } 9750Sigor@sysoev.ru 9760Sigor@sysoev.ru if (*p == ':') { 97710Sigor@sysoev.ru port = nxt_int_parse(p + 1, length - 1); 9780Sigor@sysoev.ru 9790Sigor@sysoev.ru if (port >= 1 && port <= 65535) { 9800Sigor@sysoev.ru port = htons((in_port_t) port); 9810Sigor@sysoev.ru goto found; 9820Sigor@sysoev.ru } 9830Sigor@sysoev.ru } 9840Sigor@sysoev.ru 9850Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 9860Sigor@sysoev.ru "invalid port in \"%V\"", &jbs->addr); 9870Sigor@sysoev.ru 9880Sigor@sysoev.ru return NXT_ERROR; 9890Sigor@sysoev.ru 9900Sigor@sysoev.ru found: 9910Sigor@sysoev.ru 9920Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_family = AF_INET6; 9930Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_port = (in_port_t) port; 9940Sigor@sysoev.ru 9950Sigor@sysoev.ru if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) { 9960Sigor@sysoev.ru jbs->wildcard = 1; 9970Sigor@sysoev.ru } 9980Sigor@sysoev.ru 9990Sigor@sysoev.ru return NXT_OK; 10000Sigor@sysoev.ru 10010Sigor@sysoev.ru invalid_address: 10020Sigor@sysoev.ru 10030Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 10040Sigor@sysoev.ru "invalid IPv6 address in \"%V\"", &jbs->addr); 10050Sigor@sysoev.ru return NXT_ERROR; 10060Sigor@sysoev.ru 10070Sigor@sysoev.ru #else 10080Sigor@sysoev.ru 10090Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 10100Sigor@sysoev.ru "IPv6 socket \"%V\" is not supported", &jbs->addr); 10110Sigor@sysoev.ru return NXT_ERROR; 10120Sigor@sysoev.ru 10130Sigor@sysoev.ru #endif 10140Sigor@sysoev.ru } 10150Sigor@sysoev.ru 10160Sigor@sysoev.ru 10170Sigor@sysoev.ru static nxt_int_t 10180Sigor@sysoev.ru nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs) 10190Sigor@sysoev.ru { 10200Sigor@sysoev.ru u_char *p, *host; 102110Sigor@sysoev.ru size_t length; 102265Sigor@sysoev.ru nxt_mp_t *mp; 10230Sigor@sysoev.ru nxt_int_t port; 102465Sigor@sysoev.ru in_addr_t addr; 10250Sigor@sysoev.ru nxt_sockaddr_t *sa; 10260Sigor@sysoev.ru 10270Sigor@sysoev.ru addr = INADDR_ANY; 10280Sigor@sysoev.ru 102910Sigor@sysoev.ru length = jbs->addr.length; 103010Sigor@sysoev.ru host = jbs->addr.start; 10310Sigor@sysoev.ru 103210Sigor@sysoev.ru p = nxt_memchr(host, ':', length); 10330Sigor@sysoev.ru 10340Sigor@sysoev.ru if (p == NULL) { 10350Sigor@sysoev.ru 10360Sigor@sysoev.ru /* single value port, address, or host name */ 10370Sigor@sysoev.ru 103810Sigor@sysoev.ru port = nxt_int_parse(host, length); 10390Sigor@sysoev.ru 10400Sigor@sysoev.ru if (port > 0) { 10410Sigor@sysoev.ru if (port < 1 || port > 65535) { 10420Sigor@sysoev.ru goto invalid_port; 10430Sigor@sysoev.ru } 10440Sigor@sysoev.ru 10450Sigor@sysoev.ru /* "*:XX" */ 10460Sigor@sysoev.ru port = htons((in_port_t) port); 10470Sigor@sysoev.ru jbs->resolve.port = (in_port_t) port; 10480Sigor@sysoev.ru 10490Sigor@sysoev.ru } else { 10500Sigor@sysoev.ru jbs->no_port = 1; 10510Sigor@sysoev.ru 105210Sigor@sysoev.ru addr = nxt_inet_addr(host, length); 10530Sigor@sysoev.ru 10540Sigor@sysoev.ru if (addr == INADDR_NONE) { 105510Sigor@sysoev.ru jbs->resolve.name.length = length; 105610Sigor@sysoev.ru jbs->resolve.name.start = host; 10570Sigor@sysoev.ru 10580Sigor@sysoev.ru nxt_job_resolve(&jbs->resolve); 10590Sigor@sysoev.ru return NXT_AGAIN; 10600Sigor@sysoev.ru } 10610Sigor@sysoev.ru 10620Sigor@sysoev.ru /* "x.x.x.x" */ 10630Sigor@sysoev.ru port = jbs->resolve.port; 10640Sigor@sysoev.ru } 10650Sigor@sysoev.ru 10660Sigor@sysoev.ru } else { 10670Sigor@sysoev.ru 10680Sigor@sysoev.ru /* x.x.x.x:XX or host:XX */ 10690Sigor@sysoev.ru 10700Sigor@sysoev.ru p++; 107110Sigor@sysoev.ru length = (host + length) - p; 107210Sigor@sysoev.ru port = nxt_int_parse(p, length); 10730Sigor@sysoev.ru 10740Sigor@sysoev.ru if (port < 1 || port > 65535) { 10750Sigor@sysoev.ru goto invalid_port; 10760Sigor@sysoev.ru } 10770Sigor@sysoev.ru 10780Sigor@sysoev.ru port = htons((in_port_t) port); 10790Sigor@sysoev.ru 108010Sigor@sysoev.ru length = (p - 1) - host; 10810Sigor@sysoev.ru 108210Sigor@sysoev.ru if (length != 1 || host[0] != '*') { 108310Sigor@sysoev.ru addr = nxt_inet_addr(host, length); 10840Sigor@sysoev.ru 10850Sigor@sysoev.ru if (addr == INADDR_NONE) { 108610Sigor@sysoev.ru jbs->resolve.name.length = length; 108710Sigor@sysoev.ru jbs->resolve.name.start = host; 10880Sigor@sysoev.ru jbs->resolve.port = (in_port_t) port; 10890Sigor@sysoev.ru 10900Sigor@sysoev.ru nxt_job_resolve(&jbs->resolve); 10910Sigor@sysoev.ru return NXT_AGAIN; 10920Sigor@sysoev.ru } 10930Sigor@sysoev.ru 10940Sigor@sysoev.ru /* "x.x.x.x:XX" */ 10950Sigor@sysoev.ru } 10960Sigor@sysoev.ru } 10970Sigor@sysoev.ru 10980Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 10990Sigor@sysoev.ru 110065Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 11010Sigor@sysoev.ru if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 11020Sigor@sysoev.ru return NXT_ERROR; 11030Sigor@sysoev.ru } 11040Sigor@sysoev.ru 110513Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), 110613Sigor@sysoev.ru NXT_INET_ADDR_STR_LEN); 11070Sigor@sysoev.ru 11080Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 11090Sigor@sysoev.ru jbs->resolve.count = 1; 11100Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 11110Sigor@sysoev.ru 11120Sigor@sysoev.ru jbs->wildcard = (addr == INADDR_ANY); 11130Sigor@sysoev.ru 11140Sigor@sysoev.ru sa->u.sockaddr_in.sin_family = AF_INET; 11150Sigor@sysoev.ru sa->u.sockaddr_in.sin_port = (in_port_t) port; 11160Sigor@sysoev.ru sa->u.sockaddr_in.sin_addr.s_addr = addr; 11170Sigor@sysoev.ru 11180Sigor@sysoev.ru return NXT_OK; 11190Sigor@sysoev.ru } 11200Sigor@sysoev.ru 11210Sigor@sysoev.ru return NXT_ERROR; 11220Sigor@sysoev.ru 11230Sigor@sysoev.ru invalid_port: 11240Sigor@sysoev.ru 11250Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 11260Sigor@sysoev.ru "invalid port in \"%V\"", &jbs->addr); 11270Sigor@sysoev.ru 11280Sigor@sysoev.ru return NXT_ERROR; 11290Sigor@sysoev.ru } 11300Sigor@sysoev.ru 11310Sigor@sysoev.ru 11320Sigor@sysoev.ru in_addr_t 113310Sigor@sysoev.ru nxt_inet_addr(u_char *buf, size_t length) 11340Sigor@sysoev.ru { 11350Sigor@sysoev.ru u_char c, *end; 11360Sigor@sysoev.ru in_addr_t addr; 11370Sigor@sysoev.ru nxt_uint_t digit, octet, dots; 11380Sigor@sysoev.ru 11390Sigor@sysoev.ru addr = 0; 11400Sigor@sysoev.ru octet = 0; 11410Sigor@sysoev.ru dots = 0; 11420Sigor@sysoev.ru 114310Sigor@sysoev.ru end = buf + length; 11440Sigor@sysoev.ru 11450Sigor@sysoev.ru while (buf < end) { 11460Sigor@sysoev.ru 11470Sigor@sysoev.ru c = *buf++; 11480Sigor@sysoev.ru 11490Sigor@sysoev.ru digit = c - '0'; 11500Sigor@sysoev.ru /* values below '0' become large unsigned integers */ 11510Sigor@sysoev.ru 11520Sigor@sysoev.ru if (digit < 10) { 11530Sigor@sysoev.ru octet = octet * 10 + digit; 11540Sigor@sysoev.ru continue; 11550Sigor@sysoev.ru } 11560Sigor@sysoev.ru 11570Sigor@sysoev.ru if (c == '.' && octet < 256) { 11580Sigor@sysoev.ru addr = (addr << 8) + octet; 11590Sigor@sysoev.ru octet = 0; 11600Sigor@sysoev.ru dots++; 11610Sigor@sysoev.ru continue; 11620Sigor@sysoev.ru } 11630Sigor@sysoev.ru 11640Sigor@sysoev.ru return INADDR_NONE; 11650Sigor@sysoev.ru } 11660Sigor@sysoev.ru 11670Sigor@sysoev.ru if (dots == 3 && octet < 256) { 11680Sigor@sysoev.ru addr = (addr << 8) + octet; 11690Sigor@sysoev.ru return htonl(addr); 11700Sigor@sysoev.ru } 11710Sigor@sysoev.ru 11720Sigor@sysoev.ru return INADDR_NONE; 11730Sigor@sysoev.ru } 11740Sigor@sysoev.ru 11750Sigor@sysoev.ru 11760Sigor@sysoev.ru #if (NXT_INET6) 11770Sigor@sysoev.ru 11780Sigor@sysoev.ru nxt_int_t 117910Sigor@sysoev.ru nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length) 11800Sigor@sysoev.ru { 11810Sigor@sysoev.ru u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end; 11820Sigor@sysoev.ru nxt_uint_t digit, group, nibbles, groups_left; 11830Sigor@sysoev.ru 118410Sigor@sysoev.ru if (length == 0) { 11850Sigor@sysoev.ru return NXT_ERROR; 11860Sigor@sysoev.ru } 11870Sigor@sysoev.ru 118810Sigor@sysoev.ru end = buf + length; 11890Sigor@sysoev.ru 11900Sigor@sysoev.ru if (buf[0] == ':') { 11910Sigor@sysoev.ru buf++; 11920Sigor@sysoev.ru } 11930Sigor@sysoev.ru 11940Sigor@sysoev.ru addr = in6_addr->s6_addr; 11950Sigor@sysoev.ru zero_start = NULL; 11960Sigor@sysoev.ru groups_left = 8; 11970Sigor@sysoev.ru nibbles = 0; 11980Sigor@sysoev.ru group = 0; 11990Sigor@sysoev.ru ipv4 = NULL; 12000Sigor@sysoev.ru 12010Sigor@sysoev.ru while (buf < end) { 12020Sigor@sysoev.ru c = *buf++; 12030Sigor@sysoev.ru 12040Sigor@sysoev.ru if (c == ':') { 12050Sigor@sysoev.ru if (nibbles != 0) { 12060Sigor@sysoev.ru ipv4 = buf; 12070Sigor@sysoev.ru 12080Sigor@sysoev.ru *addr++ = (u_char) (group >> 8); 1209*611Svbart@nginx.com *addr++ = (u_char) (group & 0xFF); 12100Sigor@sysoev.ru groups_left--; 12110Sigor@sysoev.ru 12120Sigor@sysoev.ru if (groups_left != 0) { 12130Sigor@sysoev.ru nibbles = 0; 12140Sigor@sysoev.ru group = 0; 12150Sigor@sysoev.ru continue; 12160Sigor@sysoev.ru } 12170Sigor@sysoev.ru 12180Sigor@sysoev.ru } else { 12190Sigor@sysoev.ru if (zero_start == NULL) { 12200Sigor@sysoev.ru ipv4 = buf; 12210Sigor@sysoev.ru zero_start = addr; 12220Sigor@sysoev.ru continue; 12230Sigor@sysoev.ru } 12240Sigor@sysoev.ru } 12250Sigor@sysoev.ru 12260Sigor@sysoev.ru return NXT_ERROR; 12270Sigor@sysoev.ru } 12280Sigor@sysoev.ru 12290Sigor@sysoev.ru if (c == '.' && nibbles != 0) { 12300Sigor@sysoev.ru 12310Sigor@sysoev.ru if (groups_left < 2 || ipv4 == NULL) { 12320Sigor@sysoev.ru return NXT_ERROR; 12330Sigor@sysoev.ru } 12340Sigor@sysoev.ru 12350Sigor@sysoev.ru group = nxt_inet_addr(ipv4, end - ipv4); 12360Sigor@sysoev.ru if (group == INADDR_NONE) { 12370Sigor@sysoev.ru return NXT_ERROR; 12380Sigor@sysoev.ru } 12390Sigor@sysoev.ru 12400Sigor@sysoev.ru group = ntohl(group); 12410Sigor@sysoev.ru 1242*611Svbart@nginx.com *addr++ = (u_char) ((group >> 24) & 0xFF); 1243*611Svbart@nginx.com *addr++ = (u_char) ((group >> 16) & 0xFF); 12440Sigor@sysoev.ru groups_left--; 12450Sigor@sysoev.ru 12460Sigor@sysoev.ru /* the low 16-bit are copied below */ 12470Sigor@sysoev.ru break; 12480Sigor@sysoev.ru } 12490Sigor@sysoev.ru 12500Sigor@sysoev.ru nibbles++; 12510Sigor@sysoev.ru 12520Sigor@sysoev.ru if (nibbles > 4) { 12530Sigor@sysoev.ru return NXT_ERROR; 12540Sigor@sysoev.ru } 12550Sigor@sysoev.ru 12560Sigor@sysoev.ru group <<= 4; 12570Sigor@sysoev.ru 12580Sigor@sysoev.ru digit = c - '0'; 12590Sigor@sysoev.ru /* values below '0' become large unsigned integers */ 12600Sigor@sysoev.ru 12610Sigor@sysoev.ru if (digit < 10) { 12620Sigor@sysoev.ru group += digit; 12630Sigor@sysoev.ru continue; 12640Sigor@sysoev.ru } 12650Sigor@sysoev.ru 12660Sigor@sysoev.ru c |= 0x20; 12670Sigor@sysoev.ru digit = c - 'a'; 12680Sigor@sysoev.ru /* values below 'a' become large unsigned integers */ 12690Sigor@sysoev.ru 12700Sigor@sysoev.ru if (digit < 6) { 12710Sigor@sysoev.ru group += 10 + digit; 12720Sigor@sysoev.ru continue; 12730Sigor@sysoev.ru } 12740Sigor@sysoev.ru 12750Sigor@sysoev.ru return NXT_ERROR; 12760Sigor@sysoev.ru } 12770Sigor@sysoev.ru 12780Sigor@sysoev.ru if (nibbles == 0 && zero_start == NULL) { 12790Sigor@sysoev.ru return NXT_ERROR; 12800Sigor@sysoev.ru } 12810Sigor@sysoev.ru 12820Sigor@sysoev.ru *addr++ = (u_char) (group >> 8); 1283*611Svbart@nginx.com *addr++ = (u_char) (group & 0xFF); 12840Sigor@sysoev.ru groups_left--; 12850Sigor@sysoev.ru 12860Sigor@sysoev.ru if (groups_left != 0) { 12870Sigor@sysoev.ru 12880Sigor@sysoev.ru if (zero_start != NULL) { 12890Sigor@sysoev.ru 12900Sigor@sysoev.ru /* moving part before consecutive zero groups to the end */ 12910Sigor@sysoev.ru 12920Sigor@sysoev.ru groups_left *= 2; 12930Sigor@sysoev.ru src = addr - 1; 12940Sigor@sysoev.ru dst = src + groups_left; 12950Sigor@sysoev.ru 12960Sigor@sysoev.ru while (src >= zero_start) { 12970Sigor@sysoev.ru *dst-- = *src--; 12980Sigor@sysoev.ru } 12990Sigor@sysoev.ru 13000Sigor@sysoev.ru nxt_memzero(zero_start, groups_left); 13010Sigor@sysoev.ru 13020Sigor@sysoev.ru return NXT_OK; 13030Sigor@sysoev.ru } 13040Sigor@sysoev.ru 13050Sigor@sysoev.ru } else { 13060Sigor@sysoev.ru if (zero_start == NULL) { 13070Sigor@sysoev.ru return NXT_OK; 13080Sigor@sysoev.ru } 13090Sigor@sysoev.ru } 13100Sigor@sysoev.ru 13110Sigor@sysoev.ru return NXT_ERROR; 13120Sigor@sysoev.ru } 13130Sigor@sysoev.ru 13140Sigor@sysoev.ru #endif 1315