1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 10 static u_char *nxt_listen_socket_log_handler(void *ctx, u_char *pos, 11 u_char *last); 12 13 14 nxt_int_t 15 nxt_listen_socket(nxt_task_t *task, nxt_socket_t s, int backlog) 16 { 17 nxt_debug(task, "listen(%d, %d)", s, backlog); 18 19 if (nxt_fast_path(listen(s, backlog) == 0)) { 20 return NXT_OK; 21 } 22 23 nxt_log(task, NXT_LOG_CRIT, "listen(%d, %d) failed %E", 24 s, backlog, nxt_socket_errno); 25 26 return NXT_ERROR; 27 } 28 29 30 nxt_int_t 31 nxt_listen_socket_create(nxt_task_t *task, nxt_listen_socket_t *ls, 32 nxt_bool_t bind_test) 33 { 34 nxt_log_t log, *old; 35 nxt_uint_t family; 36 nxt_socket_t s; 37 nxt_thread_t *thr; 38 nxt_sockaddr_t *sa; 39 40 sa = ls->sockaddr; 41 42 thr = nxt_thread(); 43 old = thr->log; 44 log = *thr->log; 45 log.ctx_handler = nxt_listen_socket_log_handler; 46 log.ctx = sa; 47 thr->log = &log; 48 49 family = sa->u.sockaddr.sa_family; 50 51 s = nxt_socket_create(task, family, sa->type, 0, ls->flags); 52 if (s == -1) { 53 goto socket_fail; 54 } 55 56 if (nxt_socket_setsockopt(task, s, SOL_SOCKET, SO_REUSEADDR, 1) != NXT_OK) { 57 goto fail; 58 } 59 60 #if (NXT_INET6 && defined IPV6_V6ONLY) 61 62 if (family == AF_INET6 && ls->ipv6only) { 63 int ipv6only; 64 65 ipv6only = (ls->ipv6only == 1); 66 67 /* Ignore possible error. TODO: why? */ 68 (void) nxt_socket_setsockopt(task, s, IPPROTO_IPV6, IPV6_V6ONLY, 69 ipv6only); 70 } 71 72 #endif 73 74 #if 0 75 76 /* Ignore possible error. TODO: why? */ 77 (void) nxt_socket_setsockopt(task, s, SOL_SOCKET, SO_SNDBUF, 8192); 78 79 #endif 80 81 if (ls->read_after_accept) { 82 nxt_socket_defer_accept(task, s, sa); 83 } 84 85 switch (nxt_socket_bind(task, s, sa, bind_test)) { 86 87 case NXT_OK: 88 break; 89 90 case NXT_ERROR: 91 goto fail; 92 93 default: /* NXT_DECLINED: EADDRINUSE on bind() test */ 94 return NXT_OK; 95 } 96 97 #if (NXT_HAVE_UNIX_DOMAIN) 98 99 if (family == AF_UNIX) { 100 nxt_file_name_t *name; 101 nxt_file_access_t access; 102 103 name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; 104 105 access = (S_IRUSR | S_IWUSR); 106 107 if (nxt_file_set_access(name, access) != NXT_OK) { 108 goto fail; 109 } 110 111 if (bind_test && nxt_file_delete(name) != NXT_OK) { 112 goto fail; 113 } 114 } 115 116 #endif 117 118 nxt_debug(task, "listen(%d, %d)", s, ls->backlog); 119 120 if (listen(s, ls->backlog) != 0) { 121 nxt_log(task, NXT_LOG_CRIT, "listen(%d, %d) failed %E", 122 s, ls->backlog, nxt_socket_errno); 123 goto fail; 124 } 125 126 ls->socket = s; 127 thr->log = old; 128 129 return NXT_OK; 130 131 fail: 132 133 nxt_socket_close(task, s); 134 135 socket_fail: 136 137 thr->log = old; 138 139 return NXT_ERROR; 140 } 141 142 143 nxt_int_t 144 nxt_listen_socket_update(nxt_task_t *task, nxt_listen_socket_t *ls, 145 nxt_listen_socket_t *prev) 146 { 147 nxt_log_t log, *old; 148 nxt_thread_t *thr; 149 150 ls->socket = prev->socket; 151 152 thr = nxt_thread(); 153 old = thr->log; 154 log = *thr->log; 155 log.ctx_handler = nxt_listen_socket_log_handler; 156 log.ctx = ls->sockaddr; 157 thr->log = &log; 158 159 nxt_debug(task, "listen(%d, %d)", ls->socket, ls->backlog); 160 161 if (listen(ls->socket, ls->backlog) != 0) { 162 nxt_log(task, NXT_LOG_CRIT, "listen(%d, %d) failed %E", 163 ls->socket, ls->backlog, nxt_socket_errno); 164 goto fail; 165 } 166 167 thr->log = old; 168 169 return NXT_OK; 170 171 fail: 172 173 thr->log = old; 174 175 return NXT_ERROR; 176 } 177 178 179 void 180 nxt_listen_socket_remote_size(nxt_listen_socket_t *ls) 181 { 182 switch (ls->sockaddr->u.sockaddr.sa_family) { 183 184 #if (NXT_INET6) 185 186 case AF_INET6: 187 ls->socklen = sizeof(struct sockaddr_in6); 188 ls->address_length = NXT_INET6_ADDR_STR_LEN; 189 190 break; 191 192 #endif 193 194 #if (NXT_HAVE_UNIX_DOMAIN) 195 196 case AF_UNIX: 197 /* 198 * A remote socket is usually unbound and thus has unspecified Unix 199 * domain sockaddr_un which can be shortcut to 3 bytes. To handle 200 * a bound remote socket correctly ls->socklen should be larger, see 201 * comment in nxt_socket.h. 202 */ 203 ls->socklen = offsetof(struct sockaddr_un, sun_path) + 1; 204 ls->address_length = sizeof("unix:") - 1; 205 206 break; 207 208 #endif 209 210 default: 211 case AF_INET: 212 ls->socklen = sizeof(struct sockaddr_in); 213 ls->address_length = NXT_INET_ADDR_STR_LEN; 214 215 break; 216 } 217 } 218 219 220 size_t 221 nxt_listen_socket_pool_min_size(nxt_listen_socket_t *ls) 222 { 223 size_t size; 224 225 /* 226 * The first nxt_sockaddr_t is intended for mandatory remote sockaddr 227 * and textual representaion with port. The second nxt_sockaddr_t 228 * is intended for local sockaddr without textual representaion which 229 * may be required to get specific address of connection received on 230 * wildcard AF_INET and AF_INET6 addresses. For AF_UNIX addresses 231 * the local sockaddr is not required. 232 */ 233 234 switch (ls->sockaddr->u.sockaddr.sa_family) { 235 236 #if (NXT_INET6) 237 238 case AF_INET6: 239 ls->socklen = sizeof(struct sockaddr_in6); 240 ls->address_length = NXT_INET6_ADDR_STR_LEN; 241 242 size = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6) 243 + NXT_INET6_ADDR_STR_LEN + (sizeof(":65535") - 1); 244 245 if (IN6_IS_ADDR_UNSPECIFIED(&ls->sockaddr->u.sockaddr_in6.sin6_addr)) { 246 size += offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6); 247 } 248 249 break; 250 251 #endif 252 253 #if (NXT_HAVE_UNIX_DOMAIN) 254 255 case AF_UNIX: 256 /* 257 * A remote socket is usually unbound and thus has unspecified Unix 258 * domain sockaddr_un which can be shortcut to 3 bytes. To handle 259 * a bound remote socket correctly ls->socklen should be at least 260 * sizeof(struct sockaddr_un), see comment in nxt_socket.h. 261 */ 262 ls->socklen = 3; 263 size = ls->socklen + sizeof("unix:") - 1; 264 ls->address_length = sizeof("unix:") - 1; 265 266 break; 267 268 #endif 269 270 default: 271 ls->socklen = sizeof(struct sockaddr_in); 272 ls->address_length = NXT_INET_ADDR_STR_LEN; 273 274 size = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in) 275 + NXT_INET_ADDR_STR_LEN + (sizeof(":65535") - 1); 276 277 if (ls->sockaddr->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) { 278 size += offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in); 279 } 280 281 break; 282 } 283 284 #if (NXT_SSLTLS) 285 286 if (ls->ssltls) { 287 size += 4 * sizeof(void *) /* SSL/TLS connection */ 288 + sizeof(nxt_buf_mem_t) 289 + sizeof(nxt_mem_pool_cleanup_t); 290 } 291 292 #endif 293 294 return size // + sizeof(nxt_mem_pool_t) 295 + sizeof(nxt_conn_t) 296 + sizeof(nxt_log_t); 297 } 298 299 300 static u_char * 301 nxt_listen_socket_log_handler(void *ctx, u_char *pos, u_char *end) 302 { 303 nxt_sockaddr_t *sa; 304 305 sa = ctx; 306 307 return nxt_sprintf(pos, end, " while creating listening socket on %*s", 308 (size_t) sa->length, sa->start); 309 } 310