nxt_listen_socket.c (493:745222d540a2) nxt_listen_socket.c (494:7c83ddcc1c42)
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8
9
10static u_char *nxt_listen_socket_log_handler(void *ctx, u_char *pos,
11 u_char *last);
12
13
14nxt_int_t
15nxt_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
30nxt_int_t
31nxt_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
131fail:
132
133 nxt_socket_close(task, s);
134
135socket_fail:
136
137 thr->log = old;
138
139 return NXT_ERROR;
140}
141
142
143nxt_int_t
144nxt_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
171fail:
172
173 thr->log = old;
174
175 return NXT_ERROR;
176}
177
178
179void
180nxt_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
220size_t
221nxt_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
300static u_char *
301nxt_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",
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8
9
10static u_char *nxt_listen_socket_log_handler(void *ctx, u_char *pos,
11 u_char *last);
12
13
14nxt_int_t
15nxt_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
30nxt_int_t
31nxt_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
131fail:
132
133 nxt_socket_close(task, s);
134
135socket_fail:
136
137 thr->log = old;
138
139 return NXT_ERROR;
140}
141
142
143nxt_int_t
144nxt_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
171fail:
172
173 thr->log = old;
174
175 return NXT_ERROR;
176}
177
178
179void
180nxt_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
220size_t
221nxt_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
300static u_char *
301nxt_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);
308 (size_t) sa->length, nxt_sockaddr_start(sa));
309}
309}