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