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 * 2465Sigor@sysoev.ru nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length) 250Sigor@sysoev.ru { 2613Sigor@sysoev.ru size_t size; 270Sigor@sysoev.ru nxt_sockaddr_t *sa; 280Sigor@sysoev.ru 2913Sigor@sysoev.ru size = offsetof(nxt_sockaddr_t, u) + socklen + address_length; 3013Sigor@sysoev.ru 310Sigor@sysoev.ru /* 320Sigor@sysoev.ru * The current struct sockaddr's define 32-bit fields at maximum 330Sigor@sysoev.ru * and may define 64-bit AF_INET6 fields in the future. Alignment 3465Sigor@sysoev.ru * of memory allocated by nxt_mp_zalloc() is enough for these fields. 350Sigor@sysoev.ru * If 128-bit alignment will be required then nxt_mem_malloc() and 360Sigor@sysoev.ru * nxt_memzero() should be used instead. 370Sigor@sysoev.ru */ 3813Sigor@sysoev.ru 3965Sigor@sysoev.ru sa = nxt_mp_zalloc(mp, size); 400Sigor@sysoev.ru 410Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 4213Sigor@sysoev.ru sa->socklen = socklen; 4313Sigor@sysoev.ru sa->length = address_length; 4413Sigor@sysoev.ru sa->sockaddr_size = size; 450Sigor@sysoev.ru } 460Sigor@sysoev.ru 470Sigor@sysoev.ru return sa; 480Sigor@sysoev.ru } 490Sigor@sysoev.ru 500Sigor@sysoev.ru 510Sigor@sysoev.ru nxt_sockaddr_t * 5265Sigor@sysoev.ru nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length, 5365Sigor@sysoev.ru size_t address_length) 540Sigor@sysoev.ru { 550Sigor@sysoev.ru size_t size, copy; 560Sigor@sysoev.ru nxt_sockaddr_t *sa; 570Sigor@sysoev.ru 5810Sigor@sysoev.ru size = length; 5910Sigor@sysoev.ru copy = length; 600Sigor@sysoev.ru 610Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 620Sigor@sysoev.ru 630Sigor@sysoev.ru /* 640Sigor@sysoev.ru * Unspecified Unix domain sockaddr_un form and length are very 650Sigor@sysoev.ru * platform depended (see comment in unix/socket.h). Here they are 660Sigor@sysoev.ru * normalized to the sockaddr_un with single zero byte sun_path[]. 670Sigor@sysoev.ru */ 680Sigor@sysoev.ru 690Sigor@sysoev.ru if (size <= offsetof(struct sockaddr_un, sun_path)) { 700Sigor@sysoev.ru /* 710Sigor@sysoev.ru * Small socket length means a short unspecified Unix domain 720Sigor@sysoev.ru * socket address: 730Sigor@sysoev.ru * 740Sigor@sysoev.ru * getsockname() and getpeername() on OpenBSD prior to 5.3 750Sigor@sysoev.ru * return zero length and does not update a passed sockaddr 760Sigor@sysoev.ru * buffer at all. 770Sigor@sysoev.ru * 780Sigor@sysoev.ru * Linux returns length equal to 2, i.e. sockaddr_un without 790Sigor@sysoev.ru * sun_path[], unix(7): 800Sigor@sysoev.ru * 810Sigor@sysoev.ru * unnamed: A stream socket that has not been bound 820Sigor@sysoev.ru * to a pathname using bind(2) has no name. Likewise, 830Sigor@sysoev.ru * the two sockets created by socketpair(2) are unnamed. 840Sigor@sysoev.ru * When the address of an unnamed socket is returned by 850Sigor@sysoev.ru * getsockname(2), getpeername(2), and accept(2), its 860Sigor@sysoev.ru * length is sizeof(sa_family_t), and sun_path should 870Sigor@sysoev.ru * not be inspected. 880Sigor@sysoev.ru */ 890Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1; 900Sigor@sysoev.ru 910Sigor@sysoev.ru #if !(NXT_LINUX) 920Sigor@sysoev.ru 930Sigor@sysoev.ru } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') { 940Sigor@sysoev.ru /* 950Sigor@sysoev.ru * Omit nonsignificant zeros of the unspecified Unix domain socket 960Sigor@sysoev.ru * address. This test is disabled for Linux since Linux abstract 970Sigor@sysoev.ru * socket address also starts with zero. However Linux unspecified 980Sigor@sysoev.ru * Unix domain socket address is short and is handled above. 990Sigor@sysoev.ru */ 1000Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1; 1010Sigor@sysoev.ru copy = size; 1020Sigor@sysoev.ru 1030Sigor@sysoev.ru #endif 1040Sigor@sysoev.ru } 1050Sigor@sysoev.ru 1060Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 1070Sigor@sysoev.ru 10813Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, size, address_length); 1090Sigor@sysoev.ru 1100Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 1110Sigor@sysoev.ru nxt_memcpy(&sa->u.sockaddr, sockaddr, copy); 1120Sigor@sysoev.ru 1130Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD) 1140Sigor@sysoev.ru 11510Sigor@sysoev.ru if (length == 0) { 1160Sigor@sysoev.ru sa->u.sockaddr.sa_family = AF_UNIX; 1170Sigor@sysoev.ru } 1180Sigor@sysoev.ru 1190Sigor@sysoev.ru #endif 1200Sigor@sysoev.ru } 1210Sigor@sysoev.ru 1220Sigor@sysoev.ru return sa; 1230Sigor@sysoev.ru } 1240Sigor@sysoev.ru 1250Sigor@sysoev.ru 1260Sigor@sysoev.ru nxt_sockaddr_t * 12765Sigor@sysoev.ru nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src) 1280Sigor@sysoev.ru { 12910Sigor@sysoev.ru size_t length; 1300Sigor@sysoev.ru nxt_sockaddr_t *dst; 1310Sigor@sysoev.ru 13213Sigor@sysoev.ru length = offsetof(nxt_sockaddr_t, u) + src->socklen; 1330Sigor@sysoev.ru 13465Sigor@sysoev.ru dst = nxt_mp_alloc(mp, length); 1350Sigor@sysoev.ru 1360Sigor@sysoev.ru if (nxt_fast_path(dst != NULL)) { 13710Sigor@sysoev.ru nxt_memcpy(dst, src, length); 1380Sigor@sysoev.ru } 1390Sigor@sysoev.ru 1400Sigor@sysoev.ru return dst; 1410Sigor@sysoev.ru } 1420Sigor@sysoev.ru 1430Sigor@sysoev.ru 1440Sigor@sysoev.ru nxt_sockaddr_t * 14565Sigor@sysoev.ru nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s) 1460Sigor@sysoev.ru { 1470Sigor@sysoev.ru int ret; 14813Sigor@sysoev.ru size_t length; 1490Sigor@sysoev.ru socklen_t socklen; 1500Sigor@sysoev.ru nxt_sockaddr_buf_t sockaddr; 1510Sigor@sysoev.ru 1520Sigor@sysoev.ru socklen = NXT_SOCKADDR_LEN; 1530Sigor@sysoev.ru 1540Sigor@sysoev.ru ret = getsockname(s, &sockaddr.buf, &socklen); 1550Sigor@sysoev.ru 1560Sigor@sysoev.ru if (nxt_fast_path(ret == 0)) { 15713Sigor@sysoev.ru 15813Sigor@sysoev.ru switch (sockaddr.buf.sa_family) { 15913Sigor@sysoev.ru #if (NXT_INET6) 16013Sigor@sysoev.ru case AF_INET6: 16113Sigor@sysoev.ru length = NXT_INET6_ADDR_STR_LEN; 16213Sigor@sysoev.ru break; 16313Sigor@sysoev.ru #endif 16413Sigor@sysoev.ru 16513Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 16613Sigor@sysoev.ru case AF_UNIX: 16713Sigor@sysoev.ru length = sizeof("unix:") - 1 + socklen; 16813Sigor@sysoev.ru #endif 16913Sigor@sysoev.ru break; 17013Sigor@sysoev.ru 17113Sigor@sysoev.ru case AF_INET: 17213Sigor@sysoev.ru length = NXT_INET_ADDR_STR_LEN; 17313Sigor@sysoev.ru break; 17413Sigor@sysoev.ru 17513Sigor@sysoev.ru default: 17613Sigor@sysoev.ru length = 0; 17713Sigor@sysoev.ru break; 17813Sigor@sysoev.ru } 17913Sigor@sysoev.ru 18013Sigor@sysoev.ru return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length); 1810Sigor@sysoev.ru } 1820Sigor@sysoev.ru 18313Sigor@sysoev.ru nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno); 1840Sigor@sysoev.ru 1850Sigor@sysoev.ru return NULL; 1860Sigor@sysoev.ru } 1870Sigor@sysoev.ru 1880Sigor@sysoev.ru 18913Sigor@sysoev.ru void 19013Sigor@sysoev.ru nxt_sockaddr_text(nxt_sockaddr_t *sa) 1910Sigor@sysoev.ru { 19213Sigor@sysoev.ru size_t offset; 19313Sigor@sysoev.ru u_char *p, *start, *end, *octet; 19413Sigor@sysoev.ru uint32_t port; 19513Sigor@sysoev.ru 19698Svbart@nginx.com end = nxt_pointer_to(sa, sa->sockaddr_size); 19713Sigor@sysoev.ru 19813Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 19913Sigor@sysoev.ru 20013Sigor@sysoev.ru case AF_INET: 20113Sigor@sysoev.ru offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in); 20213Sigor@sysoev.ru 20313Sigor@sysoev.ru sa->start = offset; 20413Sigor@sysoev.ru sa->address_start = offset; 20513Sigor@sysoev.ru 20698Svbart@nginx.com start = nxt_pointer_to(sa, offset); 20713Sigor@sysoev.ru octet = (u_char *) &sa->u.sockaddr_in.sin_addr; 20813Sigor@sysoev.ru 20913Sigor@sysoev.ru p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud", 21013Sigor@sysoev.ru octet[0], octet[1], octet[2], octet[3]); 21113Sigor@sysoev.ru 21213Sigor@sysoev.ru sa->address_length = p - start; 21313Sigor@sysoev.ru sa->port_start = sa->address_length + 1; 2140Sigor@sysoev.ru 21513Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port; 21613Sigor@sysoev.ru 21713Sigor@sysoev.ru break; 21813Sigor@sysoev.ru 21913Sigor@sysoev.ru #if (NXT_INET6) 22013Sigor@sysoev.ru 22113Sigor@sysoev.ru case AF_INET6: 22213Sigor@sysoev.ru offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6); 22313Sigor@sysoev.ru 22413Sigor@sysoev.ru sa->start = offset; 225*101Sigor@sysoev.ru sa->address_start = offset + 1; 22613Sigor@sysoev.ru 22798Svbart@nginx.com start = nxt_pointer_to(sa, offset); 22813Sigor@sysoev.ru p = start; 22913Sigor@sysoev.ru 23013Sigor@sysoev.ru *p++ = '['; 23113Sigor@sysoev.ru 23213Sigor@sysoev.ru p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 23313Sigor@sysoev.ru 23413Sigor@sysoev.ru sa->address_length = p - (start + 1); 23513Sigor@sysoev.ru sa->port_start = sa->address_length + 2; 23620Sigor@sysoev.ru 23713Sigor@sysoev.ru *p++ = ']'; 2380Sigor@sysoev.ru 23913Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port; 24013Sigor@sysoev.ru 24113Sigor@sysoev.ru break; 24213Sigor@sysoev.ru 24313Sigor@sysoev.ru #endif 24413Sigor@sysoev.ru 24513Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 24613Sigor@sysoev.ru 24713Sigor@sysoev.ru case AF_UNIX: 248100Sigor@sysoev.ru offset = offsetof(nxt_sockaddr_t, u) + sa->socklen; 2490Sigor@sysoev.ru 25013Sigor@sysoev.ru sa->start = offset; 25113Sigor@sysoev.ru sa->address_start = offset; 25213Sigor@sysoev.ru 25398Svbart@nginx.com start = nxt_pointer_to(sa, offset); 254100Sigor@sysoev.ru p = (u_char *) sa->u.sockaddr_un.sun_path; 2550Sigor@sysoev.ru 25613Sigor@sysoev.ru #if (NXT_LINUX) 25713Sigor@sysoev.ru 25813Sigor@sysoev.ru if (p[0] == '\0') { 25913Sigor@sysoev.ru int length; 2600Sigor@sysoev.ru 26113Sigor@sysoev.ru /* Linux abstract socket address has no trailing zero. */ 26213Sigor@sysoev.ru length = sa->socklen - offsetof(struct sockaddr_un, sun_path); 26313Sigor@sysoev.ru 26413Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1); 26513Sigor@sysoev.ru 26613Sigor@sysoev.ru } else { 26713Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:%s", p); 26813Sigor@sysoev.ru } 26913Sigor@sysoev.ru 27013Sigor@sysoev.ru #else /* !(NXT_LINUX) */ 27113Sigor@sysoev.ru 27213Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:%s", p); 2730Sigor@sysoev.ru 27413Sigor@sysoev.ru #endif 27513Sigor@sysoev.ru 27613Sigor@sysoev.ru sa->address_length = p - start; 27713Sigor@sysoev.ru sa->port_start = sa->address_length; 27813Sigor@sysoev.ru sa->length = p - start; 27913Sigor@sysoev.ru 28013Sigor@sysoev.ru return; 28113Sigor@sysoev.ru 28213Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 28313Sigor@sysoev.ru 28413Sigor@sysoev.ru default: 28513Sigor@sysoev.ru return; 2860Sigor@sysoev.ru } 2870Sigor@sysoev.ru 28813Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%d", ntohs(port)); 28913Sigor@sysoev.ru 29013Sigor@sysoev.ru sa->length = p - start; 2910Sigor@sysoev.ru } 2920Sigor@sysoev.ru 2930Sigor@sysoev.ru 2940Sigor@sysoev.ru uint32_t 29513Sigor@sysoev.ru nxt_sockaddr_port_number(nxt_sockaddr_t *sa) 2960Sigor@sysoev.ru { 2970Sigor@sysoev.ru uint32_t port; 2980Sigor@sysoev.ru 2990Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 3000Sigor@sysoev.ru 3010Sigor@sysoev.ru #if (NXT_INET6) 3020Sigor@sysoev.ru 3030Sigor@sysoev.ru case AF_INET6: 3040Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port; 3050Sigor@sysoev.ru break; 3060Sigor@sysoev.ru 3070Sigor@sysoev.ru #endif 3080Sigor@sysoev.ru 3090Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 3100Sigor@sysoev.ru 3110Sigor@sysoev.ru case AF_UNIX: 3120Sigor@sysoev.ru return 0; 3130Sigor@sysoev.ru 3140Sigor@sysoev.ru #endif 3150Sigor@sysoev.ru 3160Sigor@sysoev.ru default: 3170Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port; 3180Sigor@sysoev.ru break; 3190Sigor@sysoev.ru } 3200Sigor@sysoev.ru 3210Sigor@sysoev.ru return ntohs((uint16_t) port); 3220Sigor@sysoev.ru } 3230Sigor@sysoev.ru 3240Sigor@sysoev.ru 3250Sigor@sysoev.ru nxt_bool_t 3260Sigor@sysoev.ru nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) 3270Sigor@sysoev.ru { 32813Sigor@sysoev.ru if (sa1->socklen != sa2->socklen) { 3290Sigor@sysoev.ru return 0; 3300Sigor@sysoev.ru } 3310Sigor@sysoev.ru 3320Sigor@sysoev.ru if (sa1->type != sa2->type) { 3330Sigor@sysoev.ru return 0; 3340Sigor@sysoev.ru } 3350Sigor@sysoev.ru 3360Sigor@sysoev.ru if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) { 3370Sigor@sysoev.ru return 0; 3380Sigor@sysoev.ru } 3390Sigor@sysoev.ru 3400Sigor@sysoev.ru /* 3410Sigor@sysoev.ru * sockaddr struct's cannot be compared in whole since kernel 3420Sigor@sysoev.ru * may fill some fields in inherited sockaddr struct's. 3430Sigor@sysoev.ru */ 3440Sigor@sysoev.ru 3450Sigor@sysoev.ru switch (sa1->u.sockaddr.sa_family) { 3460Sigor@sysoev.ru 3470Sigor@sysoev.ru #if (NXT_INET6) 3480Sigor@sysoev.ru 3490Sigor@sysoev.ru case AF_INET6: 3500Sigor@sysoev.ru if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) { 3510Sigor@sysoev.ru return 0; 3520Sigor@sysoev.ru } 3530Sigor@sysoev.ru 3540Sigor@sysoev.ru if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr, 3550Sigor@sysoev.ru &sa2->u.sockaddr_in6.sin6_addr, 16) 3560Sigor@sysoev.ru != 0) 3570Sigor@sysoev.ru { 3580Sigor@sysoev.ru return 0; 3590Sigor@sysoev.ru } 3600Sigor@sysoev.ru 3610Sigor@sysoev.ru return 1; 3620Sigor@sysoev.ru 3630Sigor@sysoev.ru #endif 3640Sigor@sysoev.ru 3650Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 3660Sigor@sysoev.ru 3670Sigor@sysoev.ru case AF_UNIX: 3680Sigor@sysoev.ru { 36910Sigor@sysoev.ru size_t length; 3700Sigor@sysoev.ru 37113Sigor@sysoev.ru length = sa1->socklen - offsetof(struct sockaddr_un, sun_path); 3720Sigor@sysoev.ru 3730Sigor@sysoev.ru if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path, 37410Sigor@sysoev.ru &sa2->u.sockaddr_un.sun_path, length) 3750Sigor@sysoev.ru != 0) 3760Sigor@sysoev.ru { 3770Sigor@sysoev.ru return 0; 3780Sigor@sysoev.ru } 3790Sigor@sysoev.ru 3800Sigor@sysoev.ru return 1; 3810Sigor@sysoev.ru } 3820Sigor@sysoev.ru 3830Sigor@sysoev.ru #endif 3840Sigor@sysoev.ru 3850Sigor@sysoev.ru default: /* AF_INET */ 3860Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) { 3870Sigor@sysoev.ru return 0; 3880Sigor@sysoev.ru } 3890Sigor@sysoev.ru 3900Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_addr.s_addr 3910Sigor@sysoev.ru != sa2->u.sockaddr_in.sin_addr.s_addr) 3920Sigor@sysoev.ru { 3930Sigor@sysoev.ru return 0; 3940Sigor@sysoev.ru } 3950Sigor@sysoev.ru 3960Sigor@sysoev.ru return 1; 3970Sigor@sysoev.ru } 3980Sigor@sysoev.ru } 3990Sigor@sysoev.ru 4000Sigor@sysoev.ru 4010Sigor@sysoev.ru size_t 4020Sigor@sysoev.ru nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port) 4030Sigor@sysoev.ru { 4040Sigor@sysoev.ru u_char *p; 4050Sigor@sysoev.ru 4060Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 4070Sigor@sysoev.ru 4080Sigor@sysoev.ru case AF_INET: 4090Sigor@sysoev.ru p = (u_char *) &sa->u.sockaddr_in.sin_addr; 4100Sigor@sysoev.ru 4110Sigor@sysoev.ru if (port) { 4120Sigor@sysoev.ru p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d", 4130Sigor@sysoev.ru p[0], p[1], p[2], p[3], 4140Sigor@sysoev.ru ntohs(sa->u.sockaddr_in.sin_port)); 4150Sigor@sysoev.ru } else { 4160Sigor@sysoev.ru p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud", 4170Sigor@sysoev.ru p[0], p[1], p[2], p[3]); 4180Sigor@sysoev.ru } 4190Sigor@sysoev.ru 4200Sigor@sysoev.ru return p - buf; 4210Sigor@sysoev.ru 4220Sigor@sysoev.ru #if (NXT_INET6) 4230Sigor@sysoev.ru 4240Sigor@sysoev.ru case AF_INET6: 4250Sigor@sysoev.ru p = buf; 4260Sigor@sysoev.ru 4270Sigor@sysoev.ru if (port) { 4280Sigor@sysoev.ru *p++ = '['; 4290Sigor@sysoev.ru } 4300Sigor@sysoev.ru 4310Sigor@sysoev.ru p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 4320Sigor@sysoev.ru 4330Sigor@sysoev.ru if (port) { 4340Sigor@sysoev.ru p = nxt_sprintf(p, end, "]:%d", 4350Sigor@sysoev.ru ntohs(sa->u.sockaddr_in6.sin6_port)); 4360Sigor@sysoev.ru } 4370Sigor@sysoev.ru 4380Sigor@sysoev.ru return p - buf; 4390Sigor@sysoev.ru #endif 4400Sigor@sysoev.ru 4410Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 4420Sigor@sysoev.ru 4430Sigor@sysoev.ru case AF_UNIX: 4440Sigor@sysoev.ru 4450Sigor@sysoev.ru #if (NXT_LINUX) 4460Sigor@sysoev.ru 4470Sigor@sysoev.ru p = (u_char *) sa->u.sockaddr_un.sun_path; 4480Sigor@sysoev.ru 4490Sigor@sysoev.ru if (p[0] == '\0') { 45010Sigor@sysoev.ru int length; 4510Sigor@sysoev.ru 4520Sigor@sysoev.ru /* Linux abstract socket address has no trailing zero. */ 4530Sigor@sysoev.ru 45413Sigor@sysoev.ru length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1; 45510Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1); 4560Sigor@sysoev.ru 4570Sigor@sysoev.ru } else { 4580Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:%s", p); 4590Sigor@sysoev.ru } 4600Sigor@sysoev.ru 4610Sigor@sysoev.ru #else /* !(NXT_LINUX) */ 4620Sigor@sysoev.ru 4630Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path); 4640Sigor@sysoev.ru 4650Sigor@sysoev.ru #endif 4660Sigor@sysoev.ru 4670Sigor@sysoev.ru return p - buf; 4680Sigor@sysoev.ru 4690Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 4700Sigor@sysoev.ru 4710Sigor@sysoev.ru default: 4720Sigor@sysoev.ru return 0; 4730Sigor@sysoev.ru } 4740Sigor@sysoev.ru } 4750Sigor@sysoev.ru 4760Sigor@sysoev.ru 4770Sigor@sysoev.ru #if (NXT_INET6) 4780Sigor@sysoev.ru 4790Sigor@sysoev.ru static u_char * 4800Sigor@sysoev.ru nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end) 4810Sigor@sysoev.ru { 482*101Sigor@sysoev.ru u_char *p; 483*101Sigor@sysoev.ru size_t zero_groups, last_zero_groups, ipv6_bytes; 484*101Sigor@sysoev.ru nxt_uint_t i, zero_start, last_zero_start; 4850Sigor@sysoev.ru 486*101Sigor@sysoev.ru const size_t max_inet6_length = 487*101Sigor@sysoev.ru sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") - 1; 488*101Sigor@sysoev.ru 489*101Sigor@sysoev.ru if (buf + max_inet6_length > end) { 4900Sigor@sysoev.ru return buf; 4910Sigor@sysoev.ru } 4920Sigor@sysoev.ru 4930Sigor@sysoev.ru zero_start = 8; 4940Sigor@sysoev.ru zero_groups = 0; 4950Sigor@sysoev.ru last_zero_start = 8; 4960Sigor@sysoev.ru last_zero_groups = 0; 4970Sigor@sysoev.ru 4980Sigor@sysoev.ru for (i = 0; i < 16; i += 2) { 4990Sigor@sysoev.ru 5000Sigor@sysoev.ru if (addr[i] == 0 && addr[i + 1] == 0) { 5010Sigor@sysoev.ru 5020Sigor@sysoev.ru if (last_zero_groups == 0) { 5030Sigor@sysoev.ru last_zero_start = i; 5040Sigor@sysoev.ru } 5050Sigor@sysoev.ru 5060Sigor@sysoev.ru last_zero_groups++; 5070Sigor@sysoev.ru 5080Sigor@sysoev.ru } else { 5090Sigor@sysoev.ru if (zero_groups < last_zero_groups) { 5100Sigor@sysoev.ru zero_groups = last_zero_groups; 5110Sigor@sysoev.ru zero_start = last_zero_start; 5120Sigor@sysoev.ru } 5130Sigor@sysoev.ru 5140Sigor@sysoev.ru last_zero_groups = 0; 5150Sigor@sysoev.ru } 5160Sigor@sysoev.ru } 5170Sigor@sysoev.ru 5180Sigor@sysoev.ru if (zero_groups < last_zero_groups) { 5190Sigor@sysoev.ru zero_groups = last_zero_groups; 5200Sigor@sysoev.ru zero_start = last_zero_start; 5210Sigor@sysoev.ru } 5220Sigor@sysoev.ru 5230Sigor@sysoev.ru ipv6_bytes = 16; 5240Sigor@sysoev.ru p = buf; 5250Sigor@sysoev.ru 5260Sigor@sysoev.ru if (zero_start == 0) { 5270Sigor@sysoev.ru 5280Sigor@sysoev.ru /* IPv4-mapped address */ 5290Sigor@sysoev.ru if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff) 5300Sigor@sysoev.ru /* IPv4-compatible address */ 5310Sigor@sysoev.ru || (zero_groups == 6) 5320Sigor@sysoev.ru /* not IPv6 loopback address */ 5330Sigor@sysoev.ru || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1)) 5340Sigor@sysoev.ru { 5350Sigor@sysoev.ru ipv6_bytes = 12; 5360Sigor@sysoev.ru } 5370Sigor@sysoev.ru 5380Sigor@sysoev.ru *p++ = ':'; 5390Sigor@sysoev.ru } 5400Sigor@sysoev.ru 5410Sigor@sysoev.ru for (i = 0; i < ipv6_bytes; i += 2) { 5420Sigor@sysoev.ru 5430Sigor@sysoev.ru if (i == zero_start) { 5440Sigor@sysoev.ru /* Output maximum number of consecutive zero groups as "::". */ 5450Sigor@sysoev.ru i += (zero_groups - 1) * 2; 5460Sigor@sysoev.ru *p++ = ':'; 5470Sigor@sysoev.ru continue; 5480Sigor@sysoev.ru } 5490Sigor@sysoev.ru 5500Sigor@sysoev.ru p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]); 5510Sigor@sysoev.ru 5520Sigor@sysoev.ru if (i < 14) { 5530Sigor@sysoev.ru *p++ = ':'; 5540Sigor@sysoev.ru } 5550Sigor@sysoev.ru } 5560Sigor@sysoev.ru 5570Sigor@sysoev.ru if (ipv6_bytes == 12) { 5580Sigor@sysoev.ru p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud", 5590Sigor@sysoev.ru addr[12], addr[13], addr[14], addr[15]); 5600Sigor@sysoev.ru } 5610Sigor@sysoev.ru 5620Sigor@sysoev.ru return p; 5630Sigor@sysoev.ru } 5640Sigor@sysoev.ru 5650Sigor@sysoev.ru #endif 5660Sigor@sysoev.ru 5670Sigor@sysoev.ru 56899Sigor@sysoev.ru nxt_sockaddr_t * 56999Sigor@sysoev.ru nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr) 57099Sigor@sysoev.ru { 57199Sigor@sysoev.ru nxt_sockaddr_t *sa; 57299Sigor@sysoev.ru 57399Sigor@sysoev.ru if (addr->length > 6 && nxt_memcmp(addr->start, "unix:", 5) == 0) { 57499Sigor@sysoev.ru sa = nxt_sockaddr_unix_parse(mp, addr); 57599Sigor@sysoev.ru 57699Sigor@sysoev.ru } else if (addr->length != 0 && addr->start[0] == '[') { 57799Sigor@sysoev.ru sa = nxt_sockaddr_inet6_parse(mp, addr); 57899Sigor@sysoev.ru 57999Sigor@sysoev.ru } else { 58099Sigor@sysoev.ru sa = nxt_sockaddr_inet_parse(mp, addr); 58199Sigor@sysoev.ru } 58299Sigor@sysoev.ru 58399Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 58499Sigor@sysoev.ru nxt_sockaddr_text(sa); 58599Sigor@sysoev.ru } 58699Sigor@sysoev.ru 58799Sigor@sysoev.ru return sa; 58899Sigor@sysoev.ru } 58999Sigor@sysoev.ru 59099Sigor@sysoev.ru 59199Sigor@sysoev.ru static nxt_sockaddr_t * 59299Sigor@sysoev.ru nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr) 59399Sigor@sysoev.ru { 59499Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 59599Sigor@sysoev.ru size_t length, socklen; 59699Sigor@sysoev.ru u_char *path; 59799Sigor@sysoev.ru nxt_sockaddr_t *sa; 59899Sigor@sysoev.ru 59999Sigor@sysoev.ru /* 60099Sigor@sysoev.ru * Actual sockaddr_un length can be lesser or even larger than defined 60199Sigor@sysoev.ru * struct sockaddr_un length (see comment in unix/nxt_socket.h). So 60299Sigor@sysoev.ru * limit maximum Unix domain socket address length by defined sun_path[] 60399Sigor@sysoev.ru * length because some OSes accept addresses twice larger than defined 60499Sigor@sysoev.ru * struct sockaddr_un. Also reserve space for a trailing zero to avoid 60599Sigor@sysoev.ru * ambiguity, since many OSes accept Unix domain socket addresses 60699Sigor@sysoev.ru * without a trailing zero. 60799Sigor@sysoev.ru */ 60899Sigor@sysoev.ru const size_t max_len = sizeof(struct sockaddr_un) 60999Sigor@sysoev.ru - offsetof(struct sockaddr_un, sun_path) - 1; 61099Sigor@sysoev.ru 61199Sigor@sysoev.ru /* Cutting "unix:". */ 61299Sigor@sysoev.ru length = addr->length - 5; 61399Sigor@sysoev.ru path = addr->start + 5; 61499Sigor@sysoev.ru 61599Sigor@sysoev.ru if (length > max_len) { 61699Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, 61799Sigor@sysoev.ru "unix domain socket \"%V\" name is too long", 61899Sigor@sysoev.ru addr); 61999Sigor@sysoev.ru return NULL; 62099Sigor@sysoev.ru } 62199Sigor@sysoev.ru 62299Sigor@sysoev.ru socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; 62399Sigor@sysoev.ru 62499Sigor@sysoev.ru #if (NXT_LINUX) 62599Sigor@sysoev.ru 62699Sigor@sysoev.ru /* 62799Sigor@sysoev.ru * Linux unix(7): 62899Sigor@sysoev.ru * 62999Sigor@sysoev.ru * abstract: an abstract socket address is distinguished by the fact 63099Sigor@sysoev.ru * that sun_path[0] is a null byte ('\0'). The socket's address in 63199Sigor@sysoev.ru * this namespace is given by the additional bytes in sun_path that 63299Sigor@sysoev.ru * are covered by the specified length of the address structure. 63399Sigor@sysoev.ru * (Null bytes in the name have no special significance.) 63499Sigor@sysoev.ru */ 63599Sigor@sysoev.ru if (path[0] == '@') { 63699Sigor@sysoev.ru path[0] = '\0'; 63799Sigor@sysoev.ru socklen--; 63899Sigor@sysoev.ru } 63999Sigor@sysoev.ru 64099Sigor@sysoev.ru #endif 64199Sigor@sysoev.ru 64299Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, socklen, addr->length); 64399Sigor@sysoev.ru 64499Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 64599Sigor@sysoev.ru sa->u.sockaddr_un.sun_family = AF_UNIX; 64699Sigor@sysoev.ru nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length); 64799Sigor@sysoev.ru } 64899Sigor@sysoev.ru 64999Sigor@sysoev.ru return sa; 65099Sigor@sysoev.ru 65199Sigor@sysoev.ru #else /* !(NXT_HAVE_UNIX_DOMAIN) */ 65299Sigor@sysoev.ru 65399Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, 65499Sigor@sysoev.ru "unix domain socket \"%V\" is not supported", addr); 65599Sigor@sysoev.ru 65699Sigor@sysoev.ru return NULL; 65799Sigor@sysoev.ru 65899Sigor@sysoev.ru #endif 65999Sigor@sysoev.ru } 66099Sigor@sysoev.ru 66199Sigor@sysoev.ru 66299Sigor@sysoev.ru static nxt_sockaddr_t * 66399Sigor@sysoev.ru nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr) 66499Sigor@sysoev.ru { 66599Sigor@sysoev.ru #if (NXT_INET6) 66699Sigor@sysoev.ru u_char *p, *start, *end; 66799Sigor@sysoev.ru size_t length; 66899Sigor@sysoev.ru nxt_int_t ret, port; 66999Sigor@sysoev.ru nxt_sockaddr_t *sa; 67099Sigor@sysoev.ru 67199Sigor@sysoev.ru length = addr->length - 1; 67299Sigor@sysoev.ru start = addr->start + 1; 67399Sigor@sysoev.ru 67499Sigor@sysoev.ru end = nxt_memchr(start, ']', length); 67599Sigor@sysoev.ru 67699Sigor@sysoev.ru if (end != NULL) { 67799Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6), 67899Sigor@sysoev.ru NXT_INET6_ADDR_STR_LEN); 67999Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 68099Sigor@sysoev.ru return NULL; 68199Sigor@sysoev.ru } 68299Sigor@sysoev.ru 68399Sigor@sysoev.ru ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start); 68499Sigor@sysoev.ru 68599Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 68699Sigor@sysoev.ru p = end + 1; 68799Sigor@sysoev.ru length = (start + length) - p; 68899Sigor@sysoev.ru 68999Sigor@sysoev.ru if (length > 2 && *p == ':') { 69099Sigor@sysoev.ru port = nxt_int_parse(p + 1, length - 1); 69199Sigor@sysoev.ru 69299Sigor@sysoev.ru if (port > 0 && port < 65536) { 69399Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port); 69499Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_family = AF_INET6; 69599Sigor@sysoev.ru 69699Sigor@sysoev.ru return sa; 69799Sigor@sysoev.ru } 69899Sigor@sysoev.ru } 69999Sigor@sysoev.ru 70099Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr); 70199Sigor@sysoev.ru 70299Sigor@sysoev.ru return NULL; 70399Sigor@sysoev.ru } 70499Sigor@sysoev.ru } 70599Sigor@sysoev.ru 70699Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"", addr); 70799Sigor@sysoev.ru 70899Sigor@sysoev.ru return NULL; 70999Sigor@sysoev.ru 71099Sigor@sysoev.ru #else /* !(NXT_INET6) */ 71199Sigor@sysoev.ru 71299Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "IPv6 socket \"%V\" is not supported", 71399Sigor@sysoev.ru addr); 71499Sigor@sysoev.ru return NULL; 71599Sigor@sysoev.ru 71699Sigor@sysoev.ru #endif 71799Sigor@sysoev.ru } 71899Sigor@sysoev.ru 71999Sigor@sysoev.ru 72099Sigor@sysoev.ru static nxt_sockaddr_t * 72199Sigor@sysoev.ru nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr) 72299Sigor@sysoev.ru { 72399Sigor@sysoev.ru u_char *p; 72499Sigor@sysoev.ru size_t length; 72599Sigor@sysoev.ru nxt_int_t port; 72699Sigor@sysoev.ru in_addr_t inaddr; 72799Sigor@sysoev.ru nxt_sockaddr_t *sa; 72899Sigor@sysoev.ru 72999Sigor@sysoev.ru p = nxt_memchr(addr->start, ':', addr->length); 73099Sigor@sysoev.ru 73199Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 73299Sigor@sysoev.ru inaddr = INADDR_ANY; 73399Sigor@sysoev.ru length = p - addr->start; 73499Sigor@sysoev.ru 73599Sigor@sysoev.ru if (length != 1 || addr->start[0] != '*') { 73699Sigor@sysoev.ru inaddr = nxt_inet_addr(addr->start, length); 73799Sigor@sysoev.ru 73899Sigor@sysoev.ru if (nxt_slow_path(inaddr == INADDR_NONE)) { 73999Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"", 74099Sigor@sysoev.ru addr); 74199Sigor@sysoev.ru return NULL; 74299Sigor@sysoev.ru } 74399Sigor@sysoev.ru } 74499Sigor@sysoev.ru 74599Sigor@sysoev.ru p++; 74699Sigor@sysoev.ru length = (addr->start + addr->length) - p; 74799Sigor@sysoev.ru port = nxt_int_parse(p, length); 74899Sigor@sysoev.ru 74999Sigor@sysoev.ru if (port > 0 && port < 65536) { 75099Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), 75199Sigor@sysoev.ru NXT_INET_ADDR_STR_LEN); 75299Sigor@sysoev.ru 75399Sigor@sysoev.ru if (nxt_slow_path(sa != NULL)) { 75499Sigor@sysoev.ru sa->u.sockaddr_in.sin_family = AF_INET; 75599Sigor@sysoev.ru sa->u.sockaddr_in.sin_port = htons((in_port_t) port); 75699Sigor@sysoev.ru sa->u.sockaddr_in.sin_addr.s_addr = inaddr; 75799Sigor@sysoev.ru } 75899Sigor@sysoev.ru 75999Sigor@sysoev.ru return sa; 76099Sigor@sysoev.ru } 76199Sigor@sysoev.ru } 76299Sigor@sysoev.ru 76399Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr); 76499Sigor@sysoev.ru 76599Sigor@sysoev.ru return NULL; 76699Sigor@sysoev.ru } 76799Sigor@sysoev.ru 76899Sigor@sysoev.ru 7690Sigor@sysoev.ru void 7700Sigor@sysoev.ru nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs) 7710Sigor@sysoev.ru { 7720Sigor@sysoev.ru u_char *p; 77310Sigor@sysoev.ru size_t length; 7740Sigor@sysoev.ru nxt_int_t ret; 7750Sigor@sysoev.ru nxt_work_handler_t handler; 7760Sigor@sysoev.ru 7770Sigor@sysoev.ru nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse"); 7780Sigor@sysoev.ru 77910Sigor@sysoev.ru length = jbs->addr.length; 78010Sigor@sysoev.ru p = jbs->addr.start; 7810Sigor@sysoev.ru 78271Svbart@nginx.com if (length > 6 && nxt_memcmp(p, "unix:", 5) == 0) { 7830Sigor@sysoev.ru ret = nxt_job_sockaddr_unix_parse(jbs); 7840Sigor@sysoev.ru 78510Sigor@sysoev.ru } else if (length != 0 && *p == '[') { 7860Sigor@sysoev.ru ret = nxt_job_sockaddr_inet6_parse(jbs); 7870Sigor@sysoev.ru 7880Sigor@sysoev.ru } else { 7890Sigor@sysoev.ru ret = nxt_job_sockaddr_inet_parse(jbs); 7900Sigor@sysoev.ru } 7910Sigor@sysoev.ru 7920Sigor@sysoev.ru switch (ret) { 7930Sigor@sysoev.ru 7940Sigor@sysoev.ru case NXT_OK: 7950Sigor@sysoev.ru handler = jbs->resolve.ready_handler; 7960Sigor@sysoev.ru break; 7970Sigor@sysoev.ru 7980Sigor@sysoev.ru case NXT_ERROR: 7990Sigor@sysoev.ru handler = jbs->resolve.error_handler; 8000Sigor@sysoev.ru break; 8010Sigor@sysoev.ru 8020Sigor@sysoev.ru default: /* NXT_AGAIN */ 8030Sigor@sysoev.ru return; 8040Sigor@sysoev.ru } 8050Sigor@sysoev.ru 8064Sigor@sysoev.ru nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler); 8070Sigor@sysoev.ru } 8080Sigor@sysoev.ru 8090Sigor@sysoev.ru 8100Sigor@sysoev.ru static nxt_int_t 8110Sigor@sysoev.ru nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs) 8120Sigor@sysoev.ru { 8130Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 81410Sigor@sysoev.ru size_t length, socklen; 8150Sigor@sysoev.ru u_char *path; 81665Sigor@sysoev.ru nxt_mp_t *mp; 8170Sigor@sysoev.ru nxt_sockaddr_t *sa; 8180Sigor@sysoev.ru 8190Sigor@sysoev.ru /* 8200Sigor@sysoev.ru * Actual sockaddr_un length can be lesser or even larger than defined 8210Sigor@sysoev.ru * struct sockaddr_un length (see comment in unix/nxt_socket.h). So 8220Sigor@sysoev.ru * limit maximum Unix domain socket address length by defined sun_path[] 8230Sigor@sysoev.ru * length because some OSes accept addresses twice larger than defined 8240Sigor@sysoev.ru * struct sockaddr_un. Also reserve space for a trailing zero to avoid 8250Sigor@sysoev.ru * ambiguity, since many OSes accept Unix domain socket addresses 8260Sigor@sysoev.ru * without a trailing zero. 8270Sigor@sysoev.ru */ 8280Sigor@sysoev.ru const size_t max_len = sizeof(struct sockaddr_un) 8290Sigor@sysoev.ru - offsetof(struct sockaddr_un, sun_path) - 1; 8300Sigor@sysoev.ru 8310Sigor@sysoev.ru /* cutting "unix:" */ 83210Sigor@sysoev.ru length = jbs->addr.length - 5; 83310Sigor@sysoev.ru path = jbs->addr.start + 5; 8340Sigor@sysoev.ru 83510Sigor@sysoev.ru if (length > max_len) { 8360Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 8370Sigor@sysoev.ru "unix domain socket \"%V\" name is too long", 8380Sigor@sysoev.ru &jbs->addr); 8390Sigor@sysoev.ru return NXT_ERROR; 8400Sigor@sysoev.ru } 8410Sigor@sysoev.ru 84210Sigor@sysoev.ru socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; 8430Sigor@sysoev.ru 8440Sigor@sysoev.ru #if (NXT_LINUX) 8450Sigor@sysoev.ru 8460Sigor@sysoev.ru /* 8470Sigor@sysoev.ru * Linux unix(7): 8480Sigor@sysoev.ru * 8490Sigor@sysoev.ru * abstract: an abstract socket address is distinguished by the fact 8500Sigor@sysoev.ru * that sun_path[0] is a null byte ('\0'). The socket's address in 8510Sigor@sysoev.ru * this namespace is given by the additional bytes in sun_path that 8520Sigor@sysoev.ru * are covered by the specified length of the address structure. 8530Sigor@sysoev.ru * (Null bytes in the name have no special significance.) 8540Sigor@sysoev.ru */ 8550Sigor@sysoev.ru if (path[0] == '\0') { 8560Sigor@sysoev.ru socklen--; 8570Sigor@sysoev.ru } 8580Sigor@sysoev.ru 8590Sigor@sysoev.ru #endif 8600Sigor@sysoev.ru 8610Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 8620Sigor@sysoev.ru 86365Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 8640Sigor@sysoev.ru 8650Sigor@sysoev.ru if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) { 86613Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length); 8670Sigor@sysoev.ru 8680Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 8690Sigor@sysoev.ru jbs->resolve.count = 1; 8700Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 8710Sigor@sysoev.ru 8720Sigor@sysoev.ru sa->u.sockaddr_un.sun_family = AF_UNIX; 87310Sigor@sysoev.ru nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length); 8740Sigor@sysoev.ru 8750Sigor@sysoev.ru return NXT_OK; 8760Sigor@sysoev.ru } 8770Sigor@sysoev.ru } 8780Sigor@sysoev.ru 8790Sigor@sysoev.ru return NXT_ERROR; 8800Sigor@sysoev.ru 8810Sigor@sysoev.ru #else /* !(NXT_HAVE_UNIX_DOMAIN) */ 8820Sigor@sysoev.ru 8830Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 8840Sigor@sysoev.ru "unix domain socket \"%V\" is not supported", 8850Sigor@sysoev.ru &jbs->addr); 8860Sigor@sysoev.ru return NXT_ERROR; 8870Sigor@sysoev.ru 8880Sigor@sysoev.ru #endif 8890Sigor@sysoev.ru } 8900Sigor@sysoev.ru 8910Sigor@sysoev.ru 8920Sigor@sysoev.ru static nxt_int_t 8930Sigor@sysoev.ru nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs) 8940Sigor@sysoev.ru { 8950Sigor@sysoev.ru #if (NXT_INET6) 8960Sigor@sysoev.ru u_char *p, *addr, *addr_end; 89710Sigor@sysoev.ru size_t length; 89865Sigor@sysoev.ru nxt_mp_t *mp; 8990Sigor@sysoev.ru nxt_int_t port; 9000Sigor@sysoev.ru nxt_sockaddr_t *sa; 9010Sigor@sysoev.ru struct in6_addr *in6_addr; 9020Sigor@sysoev.ru 90310Sigor@sysoev.ru length = jbs->addr.length - 1; 90410Sigor@sysoev.ru addr = jbs->addr.start + 1; 9050Sigor@sysoev.ru 90610Sigor@sysoev.ru addr_end = nxt_memchr(addr, ']', length); 9070Sigor@sysoev.ru 9080Sigor@sysoev.ru if (addr_end == NULL) { 9090Sigor@sysoev.ru goto invalid_address; 9100Sigor@sysoev.ru } 9110Sigor@sysoev.ru 9120Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 9130Sigor@sysoev.ru 91465Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 9150Sigor@sysoev.ru 9160Sigor@sysoev.ru if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 9170Sigor@sysoev.ru return NXT_ERROR; 9180Sigor@sysoev.ru } 9190Sigor@sysoev.ru 92099Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6), 92199Sigor@sysoev.ru NXT_INET6_ADDR_STR_LEN); 9220Sigor@sysoev.ru 9230Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 9240Sigor@sysoev.ru return NXT_ERROR; 9250Sigor@sysoev.ru } 9260Sigor@sysoev.ru 9270Sigor@sysoev.ru jbs->resolve.count = 1; 9280Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 9290Sigor@sysoev.ru 9300Sigor@sysoev.ru in6_addr = &sa->u.sockaddr_in6.sin6_addr; 9310Sigor@sysoev.ru 9320Sigor@sysoev.ru if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) { 9330Sigor@sysoev.ru goto invalid_address; 9340Sigor@sysoev.ru } 9350Sigor@sysoev.ru 9360Sigor@sysoev.ru p = addr_end + 1; 93710Sigor@sysoev.ru length = (addr + length) - p; 9380Sigor@sysoev.ru 93910Sigor@sysoev.ru if (length == 0) { 9400Sigor@sysoev.ru jbs->no_port = 1; 9410Sigor@sysoev.ru port = jbs->resolve.port; 9420Sigor@sysoev.ru goto found; 9430Sigor@sysoev.ru } 9440Sigor@sysoev.ru 9450Sigor@sysoev.ru if (*p == ':') { 94610Sigor@sysoev.ru port = nxt_int_parse(p + 1, length - 1); 9470Sigor@sysoev.ru 9480Sigor@sysoev.ru if (port >= 1 && port <= 65535) { 9490Sigor@sysoev.ru port = htons((in_port_t) port); 9500Sigor@sysoev.ru goto found; 9510Sigor@sysoev.ru } 9520Sigor@sysoev.ru } 9530Sigor@sysoev.ru 9540Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 9550Sigor@sysoev.ru "invalid port in \"%V\"", &jbs->addr); 9560Sigor@sysoev.ru 9570Sigor@sysoev.ru return NXT_ERROR; 9580Sigor@sysoev.ru 9590Sigor@sysoev.ru found: 9600Sigor@sysoev.ru 9610Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_family = AF_INET6; 9620Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_port = (in_port_t) port; 9630Sigor@sysoev.ru 9640Sigor@sysoev.ru if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) { 9650Sigor@sysoev.ru jbs->wildcard = 1; 9660Sigor@sysoev.ru } 9670Sigor@sysoev.ru 9680Sigor@sysoev.ru return NXT_OK; 9690Sigor@sysoev.ru 9700Sigor@sysoev.ru invalid_address: 9710Sigor@sysoev.ru 9720Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 9730Sigor@sysoev.ru "invalid IPv6 address in \"%V\"", &jbs->addr); 9740Sigor@sysoev.ru return NXT_ERROR; 9750Sigor@sysoev.ru 9760Sigor@sysoev.ru #else 9770Sigor@sysoev.ru 9780Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 9790Sigor@sysoev.ru "IPv6 socket \"%V\" is not supported", &jbs->addr); 9800Sigor@sysoev.ru return NXT_ERROR; 9810Sigor@sysoev.ru 9820Sigor@sysoev.ru #endif 9830Sigor@sysoev.ru } 9840Sigor@sysoev.ru 9850Sigor@sysoev.ru 9860Sigor@sysoev.ru static nxt_int_t 9870Sigor@sysoev.ru nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs) 9880Sigor@sysoev.ru { 9890Sigor@sysoev.ru u_char *p, *host; 99010Sigor@sysoev.ru size_t length; 99165Sigor@sysoev.ru nxt_mp_t *mp; 9920Sigor@sysoev.ru nxt_int_t port; 99365Sigor@sysoev.ru in_addr_t addr; 9940Sigor@sysoev.ru nxt_sockaddr_t *sa; 9950Sigor@sysoev.ru 9960Sigor@sysoev.ru addr = INADDR_ANY; 9970Sigor@sysoev.ru 99810Sigor@sysoev.ru length = jbs->addr.length; 99910Sigor@sysoev.ru host = jbs->addr.start; 10000Sigor@sysoev.ru 100110Sigor@sysoev.ru p = nxt_memchr(host, ':', length); 10020Sigor@sysoev.ru 10030Sigor@sysoev.ru if (p == NULL) { 10040Sigor@sysoev.ru 10050Sigor@sysoev.ru /* single value port, address, or host name */ 10060Sigor@sysoev.ru 100710Sigor@sysoev.ru port = nxt_int_parse(host, length); 10080Sigor@sysoev.ru 10090Sigor@sysoev.ru if (port > 0) { 10100Sigor@sysoev.ru if (port < 1 || port > 65535) { 10110Sigor@sysoev.ru goto invalid_port; 10120Sigor@sysoev.ru } 10130Sigor@sysoev.ru 10140Sigor@sysoev.ru /* "*:XX" */ 10150Sigor@sysoev.ru port = htons((in_port_t) port); 10160Sigor@sysoev.ru jbs->resolve.port = (in_port_t) port; 10170Sigor@sysoev.ru 10180Sigor@sysoev.ru } else { 10190Sigor@sysoev.ru jbs->no_port = 1; 10200Sigor@sysoev.ru 102110Sigor@sysoev.ru addr = nxt_inet_addr(host, length); 10220Sigor@sysoev.ru 10230Sigor@sysoev.ru if (addr == INADDR_NONE) { 102410Sigor@sysoev.ru jbs->resolve.name.length = length; 102510Sigor@sysoev.ru jbs->resolve.name.start = host; 10260Sigor@sysoev.ru 10270Sigor@sysoev.ru nxt_job_resolve(&jbs->resolve); 10280Sigor@sysoev.ru return NXT_AGAIN; 10290Sigor@sysoev.ru } 10300Sigor@sysoev.ru 10310Sigor@sysoev.ru /* "x.x.x.x" */ 10320Sigor@sysoev.ru port = jbs->resolve.port; 10330Sigor@sysoev.ru } 10340Sigor@sysoev.ru 10350Sigor@sysoev.ru } else { 10360Sigor@sysoev.ru 10370Sigor@sysoev.ru /* x.x.x.x:XX or host:XX */ 10380Sigor@sysoev.ru 10390Sigor@sysoev.ru p++; 104010Sigor@sysoev.ru length = (host + length) - p; 104110Sigor@sysoev.ru port = nxt_int_parse(p, length); 10420Sigor@sysoev.ru 10430Sigor@sysoev.ru if (port < 1 || port > 65535) { 10440Sigor@sysoev.ru goto invalid_port; 10450Sigor@sysoev.ru } 10460Sigor@sysoev.ru 10470Sigor@sysoev.ru port = htons((in_port_t) port); 10480Sigor@sysoev.ru 104910Sigor@sysoev.ru length = (p - 1) - host; 10500Sigor@sysoev.ru 105110Sigor@sysoev.ru if (length != 1 || host[0] != '*') { 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 jbs->resolve.port = (in_port_t) port; 10580Sigor@sysoev.ru 10590Sigor@sysoev.ru nxt_job_resolve(&jbs->resolve); 10600Sigor@sysoev.ru return NXT_AGAIN; 10610Sigor@sysoev.ru } 10620Sigor@sysoev.ru 10630Sigor@sysoev.ru /* "x.x.x.x:XX" */ 10640Sigor@sysoev.ru } 10650Sigor@sysoev.ru } 10660Sigor@sysoev.ru 10670Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 10680Sigor@sysoev.ru 106965Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 10700Sigor@sysoev.ru if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 10710Sigor@sysoev.ru return NXT_ERROR; 10720Sigor@sysoev.ru } 10730Sigor@sysoev.ru 107413Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), 107513Sigor@sysoev.ru NXT_INET_ADDR_STR_LEN); 10760Sigor@sysoev.ru 10770Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 10780Sigor@sysoev.ru jbs->resolve.count = 1; 10790Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 10800Sigor@sysoev.ru 10810Sigor@sysoev.ru jbs->wildcard = (addr == INADDR_ANY); 10820Sigor@sysoev.ru 10830Sigor@sysoev.ru sa->u.sockaddr_in.sin_family = AF_INET; 10840Sigor@sysoev.ru sa->u.sockaddr_in.sin_port = (in_port_t) port; 10850Sigor@sysoev.ru sa->u.sockaddr_in.sin_addr.s_addr = addr; 10860Sigor@sysoev.ru 10870Sigor@sysoev.ru return NXT_OK; 10880Sigor@sysoev.ru } 10890Sigor@sysoev.ru 10900Sigor@sysoev.ru return NXT_ERROR; 10910Sigor@sysoev.ru 10920Sigor@sysoev.ru invalid_port: 10930Sigor@sysoev.ru 10940Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 10950Sigor@sysoev.ru "invalid port in \"%V\"", &jbs->addr); 10960Sigor@sysoev.ru 10970Sigor@sysoev.ru return NXT_ERROR; 10980Sigor@sysoev.ru } 10990Sigor@sysoev.ru 11000Sigor@sysoev.ru 11010Sigor@sysoev.ru in_addr_t 110210Sigor@sysoev.ru nxt_inet_addr(u_char *buf, size_t length) 11030Sigor@sysoev.ru { 11040Sigor@sysoev.ru u_char c, *end; 11050Sigor@sysoev.ru in_addr_t addr; 11060Sigor@sysoev.ru nxt_uint_t digit, octet, dots; 11070Sigor@sysoev.ru 11080Sigor@sysoev.ru addr = 0; 11090Sigor@sysoev.ru octet = 0; 11100Sigor@sysoev.ru dots = 0; 11110Sigor@sysoev.ru 111210Sigor@sysoev.ru end = buf + length; 11130Sigor@sysoev.ru 11140Sigor@sysoev.ru while (buf < end) { 11150Sigor@sysoev.ru 11160Sigor@sysoev.ru c = *buf++; 11170Sigor@sysoev.ru 11180Sigor@sysoev.ru digit = c - '0'; 11190Sigor@sysoev.ru /* values below '0' become large unsigned integers */ 11200Sigor@sysoev.ru 11210Sigor@sysoev.ru if (digit < 10) { 11220Sigor@sysoev.ru octet = octet * 10 + digit; 11230Sigor@sysoev.ru continue; 11240Sigor@sysoev.ru } 11250Sigor@sysoev.ru 11260Sigor@sysoev.ru if (c == '.' && octet < 256) { 11270Sigor@sysoev.ru addr = (addr << 8) + octet; 11280Sigor@sysoev.ru octet = 0; 11290Sigor@sysoev.ru dots++; 11300Sigor@sysoev.ru continue; 11310Sigor@sysoev.ru } 11320Sigor@sysoev.ru 11330Sigor@sysoev.ru return INADDR_NONE; 11340Sigor@sysoev.ru } 11350Sigor@sysoev.ru 11360Sigor@sysoev.ru if (dots == 3 && octet < 256) { 11370Sigor@sysoev.ru addr = (addr << 8) + octet; 11380Sigor@sysoev.ru return htonl(addr); 11390Sigor@sysoev.ru } 11400Sigor@sysoev.ru 11410Sigor@sysoev.ru return INADDR_NONE; 11420Sigor@sysoev.ru } 11430Sigor@sysoev.ru 11440Sigor@sysoev.ru 11450Sigor@sysoev.ru #if (NXT_INET6) 11460Sigor@sysoev.ru 11470Sigor@sysoev.ru nxt_int_t 114810Sigor@sysoev.ru nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length) 11490Sigor@sysoev.ru { 11500Sigor@sysoev.ru u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end; 11510Sigor@sysoev.ru nxt_uint_t digit, group, nibbles, groups_left; 11520Sigor@sysoev.ru 115310Sigor@sysoev.ru if (length == 0) { 11540Sigor@sysoev.ru return NXT_ERROR; 11550Sigor@sysoev.ru } 11560Sigor@sysoev.ru 115710Sigor@sysoev.ru end = buf + length; 11580Sigor@sysoev.ru 11590Sigor@sysoev.ru if (buf[0] == ':') { 11600Sigor@sysoev.ru buf++; 11610Sigor@sysoev.ru } 11620Sigor@sysoev.ru 11630Sigor@sysoev.ru addr = in6_addr->s6_addr; 11640Sigor@sysoev.ru zero_start = NULL; 11650Sigor@sysoev.ru groups_left = 8; 11660Sigor@sysoev.ru nibbles = 0; 11670Sigor@sysoev.ru group = 0; 11680Sigor@sysoev.ru ipv4 = NULL; 11690Sigor@sysoev.ru 11700Sigor@sysoev.ru while (buf < end) { 11710Sigor@sysoev.ru c = *buf++; 11720Sigor@sysoev.ru 11730Sigor@sysoev.ru if (c == ':') { 11740Sigor@sysoev.ru if (nibbles != 0) { 11750Sigor@sysoev.ru ipv4 = buf; 11760Sigor@sysoev.ru 11770Sigor@sysoev.ru *addr++ = (u_char) (group >> 8); 11780Sigor@sysoev.ru *addr++ = (u_char) (group & 0xff); 11790Sigor@sysoev.ru groups_left--; 11800Sigor@sysoev.ru 11810Sigor@sysoev.ru if (groups_left != 0) { 11820Sigor@sysoev.ru nibbles = 0; 11830Sigor@sysoev.ru group = 0; 11840Sigor@sysoev.ru continue; 11850Sigor@sysoev.ru } 11860Sigor@sysoev.ru 11870Sigor@sysoev.ru } else { 11880Sigor@sysoev.ru if (zero_start == NULL) { 11890Sigor@sysoev.ru ipv4 = buf; 11900Sigor@sysoev.ru zero_start = addr; 11910Sigor@sysoev.ru continue; 11920Sigor@sysoev.ru } 11930Sigor@sysoev.ru } 11940Sigor@sysoev.ru 11950Sigor@sysoev.ru return NXT_ERROR; 11960Sigor@sysoev.ru } 11970Sigor@sysoev.ru 11980Sigor@sysoev.ru if (c == '.' && nibbles != 0) { 11990Sigor@sysoev.ru 12000Sigor@sysoev.ru if (groups_left < 2 || ipv4 == NULL) { 12010Sigor@sysoev.ru return NXT_ERROR; 12020Sigor@sysoev.ru } 12030Sigor@sysoev.ru 12040Sigor@sysoev.ru group = nxt_inet_addr(ipv4, end - ipv4); 12050Sigor@sysoev.ru if (group == INADDR_NONE) { 12060Sigor@sysoev.ru return NXT_ERROR; 12070Sigor@sysoev.ru } 12080Sigor@sysoev.ru 12090Sigor@sysoev.ru group = ntohl(group); 12100Sigor@sysoev.ru 12110Sigor@sysoev.ru *addr++ = (u_char) ((group >> 24) & 0xff); 12120Sigor@sysoev.ru *addr++ = (u_char) ((group >> 16) & 0xff); 12130Sigor@sysoev.ru groups_left--; 12140Sigor@sysoev.ru 12150Sigor@sysoev.ru /* the low 16-bit are copied below */ 12160Sigor@sysoev.ru break; 12170Sigor@sysoev.ru } 12180Sigor@sysoev.ru 12190Sigor@sysoev.ru nibbles++; 12200Sigor@sysoev.ru 12210Sigor@sysoev.ru if (nibbles > 4) { 12220Sigor@sysoev.ru return NXT_ERROR; 12230Sigor@sysoev.ru } 12240Sigor@sysoev.ru 12250Sigor@sysoev.ru group <<= 4; 12260Sigor@sysoev.ru 12270Sigor@sysoev.ru digit = c - '0'; 12280Sigor@sysoev.ru /* values below '0' become large unsigned integers */ 12290Sigor@sysoev.ru 12300Sigor@sysoev.ru if (digit < 10) { 12310Sigor@sysoev.ru group += digit; 12320Sigor@sysoev.ru continue; 12330Sigor@sysoev.ru } 12340Sigor@sysoev.ru 12350Sigor@sysoev.ru c |= 0x20; 12360Sigor@sysoev.ru digit = c - 'a'; 12370Sigor@sysoev.ru /* values below 'a' become large unsigned integers */ 12380Sigor@sysoev.ru 12390Sigor@sysoev.ru if (digit < 6) { 12400Sigor@sysoev.ru group += 10 + digit; 12410Sigor@sysoev.ru continue; 12420Sigor@sysoev.ru } 12430Sigor@sysoev.ru 12440Sigor@sysoev.ru return NXT_ERROR; 12450Sigor@sysoev.ru } 12460Sigor@sysoev.ru 12470Sigor@sysoev.ru if (nibbles == 0 && zero_start == NULL) { 12480Sigor@sysoev.ru return NXT_ERROR; 12490Sigor@sysoev.ru } 12500Sigor@sysoev.ru 12510Sigor@sysoev.ru *addr++ = (u_char) (group >> 8); 12520Sigor@sysoev.ru *addr++ = (u_char) (group & 0xff); 12530Sigor@sysoev.ru groups_left--; 12540Sigor@sysoev.ru 12550Sigor@sysoev.ru if (groups_left != 0) { 12560Sigor@sysoev.ru 12570Sigor@sysoev.ru if (zero_start != NULL) { 12580Sigor@sysoev.ru 12590Sigor@sysoev.ru /* moving part before consecutive zero groups to the end */ 12600Sigor@sysoev.ru 12610Sigor@sysoev.ru groups_left *= 2; 12620Sigor@sysoev.ru src = addr - 1; 12630Sigor@sysoev.ru dst = src + groups_left; 12640Sigor@sysoev.ru 12650Sigor@sysoev.ru while (src >= zero_start) { 12660Sigor@sysoev.ru *dst-- = *src--; 12670Sigor@sysoev.ru } 12680Sigor@sysoev.ru 12690Sigor@sysoev.ru nxt_memzero(zero_start, groups_left); 12700Sigor@sysoev.ru 12710Sigor@sysoev.ru return NXT_OK; 12720Sigor@sysoev.ru } 12730Sigor@sysoev.ru 12740Sigor@sysoev.ru } else { 12750Sigor@sysoev.ru if (zero_start == NULL) { 12760Sigor@sysoev.ru return NXT_OK; 12770Sigor@sysoev.ru } 12780Sigor@sysoev.ru } 12790Sigor@sysoev.ru 12800Sigor@sysoev.ru return NXT_ERROR; 12810Sigor@sysoev.ru } 12820Sigor@sysoev.ru 12830Sigor@sysoev.ru #endif 1284