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