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
nxt_listen_socket(nxt_task_t * task,nxt_socket_t s,int backlog)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_alert(task, "listen(%d, %d) failed %E", s, backlog, nxt_socket_errno);
24
25 return NXT_ERROR;
26 }
27
28
29 nxt_int_t
nxt_listen_socket_create(nxt_task_t * task,nxt_mp_t * mp,nxt_listen_socket_t * ls)30 nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp,
31 nxt_listen_socket_t *ls)
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 #if (NXT_HAVE_UNIX_DOMAIN)
39 int ret;
40 u_char *p;
41 nxt_err_t err;
42 nxt_socket_t ts;
43 nxt_sockaddr_t *orig_sa;
44 nxt_file_name_t *name, *tmp;
45 nxt_file_access_t access;
46 #endif
47
48 sa = ls->sockaddr;
49
50 thr = nxt_thread();
51 old = thr->log;
52 log = *thr->log;
53 log.ctx_handler = nxt_listen_socket_log_handler;
54 log.ctx = sa;
55 thr->log = &log;
56
57 family = sa->u.sockaddr.sa_family;
58
59 s = nxt_socket_create(task, family, sa->type, 0, ls->flags);
60 if (s == -1) {
61 goto fail;
62 }
63
64 if (nxt_socket_setsockopt(task, s, SOL_SOCKET, SO_REUSEADDR, 1) != NXT_OK) {
65 goto fail;
66 }
67
68 #if (NXT_INET6 && defined IPV6_V6ONLY)
69
70 if (family == AF_INET6 && ls->ipv6only) {
71 int ipv6only;
72
73 ipv6only = (ls->ipv6only == 1);
74
75 /* Ignore possible error. TODO: why? */
76 (void) nxt_socket_setsockopt(task, s, IPPROTO_IPV6, IPV6_V6ONLY,
77 ipv6only);
78 }
79
80 #endif
81
82 #if 0
83
84 /* Ignore possible error. TODO: why? */
85 (void) nxt_socket_setsockopt(task, s, SOL_SOCKET, SO_SNDBUF, 8192);
86
87 #endif
88
89 if (ls->read_after_accept) {
90 nxt_socket_defer_accept(task, s, sa);
91 }
92
93 #if (NXT_HAVE_UNIX_DOMAIN)
94
95 if (family == AF_UNIX
96 && sa->type == SOCK_STREAM
97 && sa->u.sockaddr_un.sun_path[0] != '\0')
98 {
99 orig_sa = sa;
100
101 sa = nxt_sockaddr_alloc(mp, sa->socklen + 4, sa->length + 4);
102 if (sa == NULL) {
103 goto fail;
104 }
105
106 sa->type = SOCK_STREAM;
107 sa->u.sockaddr_un.sun_family = AF_UNIX;
108
109 p = nxt_cpystr((u_char *) sa->u.sockaddr_un.sun_path,
110 (u_char *) orig_sa->u.sockaddr_un.sun_path);
111 nxt_memcpy(p, ".tmp", 4);
112
113 nxt_sockaddr_text(sa);
114
115 (void) unlink(sa->u.sockaddr_un.sun_path);
116
117 } else {
118 orig_sa = NULL;
119 }
120
121 #endif
122
123 if (nxt_socket_bind(task, s, sa) != NXT_OK) {
124 goto fail;
125 }
126
127 #if (NXT_HAVE_UNIX_DOMAIN)
128
129 if (family == AF_UNIX) {
130 const char *user;
131 const char *group;
132 nxt_runtime_t *rt = thr->runtime;
133
134 name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path;
135 access = rt->control_mode > 0 ? rt->control_mode : S_IRUSR | S_IWUSR;
136
137 if (nxt_file_set_access(name, access) != NXT_OK) {
138 goto listen_fail;
139 }
140
141 user = rt->control_user;
142 group = rt->control_group;
143
144 if (nxt_file_chown(name, user, group) != NXT_OK) {
145 goto listen_fail;
146 }
147 }
148
149 #endif
150
151 nxt_debug(task, "listen(%d, %d)", s, ls->backlog);
152
153 if (listen(s, ls->backlog) != 0) {
154 nxt_alert(task, "listen(%d, %d) failed %E",
155 s, ls->backlog, nxt_socket_errno);
156 goto listen_fail;
157 }
158
159 #if (NXT_HAVE_UNIX_DOMAIN)
160
161 if (orig_sa != NULL) {
162 ts = nxt_socket_create(task, AF_UNIX, SOCK_STREAM, 0, 0);
163 if (ts == -1) {
164 goto listen_fail;
165 }
166
167 ret = connect(ts, &orig_sa->u.sockaddr, orig_sa->socklen);
168
169 err = nxt_socket_errno;
170
171 nxt_socket_close(task, ts);
172
173 if (ret == 0) {
174 nxt_alert(task, "connect(%d, %*s) socket already in use",
175 ts, (size_t) orig_sa->length,
176 nxt_sockaddr_start(orig_sa));
177
178 goto listen_fail;
179 }
180
181 if (err != NXT_ENOENT && err != NXT_ECONNREFUSED) {
182 nxt_alert(task, "connect(%d, %*s) failed %E",
183 ts, (size_t) orig_sa->length,
184 nxt_sockaddr_start(orig_sa), err);
185
186 goto listen_fail;
187 }
188
189 tmp = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path;
190 name = (nxt_file_name_t *) orig_sa->u.sockaddr_un.sun_path;
191
192 if (nxt_file_rename(tmp, name) != NXT_OK) {
193 goto listen_fail;
194 }
195 }
196
197 #endif
198
199 ls->socket = s;
200 thr->log = old;
201
202 return NXT_OK;
203
204 listen_fail:
205
206 #if (NXT_HAVE_UNIX_DOMAIN)
207
208 if (family == AF_UNIX) {
209 name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path;
210
211 (void) nxt_file_delete(name);
212 }
213
214 #endif
215
216 fail:
217
218 if (s != -1) {
219 nxt_socket_close(task, s);
220 }
221
222 thr->log = old;
223
224 return NXT_ERROR;
225 }
226
227
228 nxt_int_t
nxt_listen_socket_update(nxt_task_t * task,nxt_listen_socket_t * ls,nxt_listen_socket_t * prev)229 nxt_listen_socket_update(nxt_task_t *task, nxt_listen_socket_t *ls,
230 nxt_listen_socket_t *prev)
231 {
232 nxt_log_t log, *old;
233 nxt_thread_t *thr;
234
235 ls->socket = prev->socket;
236
237 thr = nxt_thread();
238 old = thr->log;
239 log = *thr->log;
240 log.ctx_handler = nxt_listen_socket_log_handler;
241 log.ctx = ls->sockaddr;
242 thr->log = &log;
243
244 nxt_debug(task, "listen(%d, %d)", ls->socket, ls->backlog);
245
246 if (listen(ls->socket, ls->backlog) != 0) {
247 nxt_alert(task, "listen(%d, %d) failed %E",
248 ls->socket, ls->backlog, nxt_socket_errno);
249 goto fail;
250 }
251
252 thr->log = old;
253
254 return NXT_OK;
255
256 fail:
257
258 thr->log = old;
259
260 return NXT_ERROR;
261 }
262
263
264 void
nxt_listen_socket_remote_size(nxt_listen_socket_t * ls)265 nxt_listen_socket_remote_size(nxt_listen_socket_t *ls)
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 break;
276
277 #endif
278
279 #if (NXT_HAVE_UNIX_DOMAIN)
280
281 case AF_UNIX:
282 /*
283 * A remote socket is usually unbound and thus has unspecified Unix
284 * domain sockaddr_un which can be shortcut to 3 bytes. To handle
285 * a bound remote socket correctly ls->socklen should be larger, see
286 * comment in nxt_socket.h.
287 */
288 ls->socklen = offsetof(struct sockaddr_un, sun_path) + 1;
289 ls->address_length = nxt_length("unix:");
290
291 break;
292
293 #endif
294
295 default:
296 case AF_INET:
297 ls->socklen = sizeof(struct sockaddr_in);
298 ls->address_length = NXT_INET_ADDR_STR_LEN;
299
300 break;
301 }
302 }
303
304
305 size_t
nxt_listen_socket_pool_min_size(nxt_listen_socket_t * ls)306 nxt_listen_socket_pool_min_size(nxt_listen_socket_t *ls)
307 {
308 size_t size;
309
310 /*
311 * The first nxt_sockaddr_t is intended for mandatory remote sockaddr
312 * and textual representaion with port. The second nxt_sockaddr_t
313 * is intended for local sockaddr without textual representaion which
314 * may be required to get specific address of connection received on
315 * wildcard AF_INET and AF_INET6 addresses. For AF_UNIX addresses
316 * the local sockaddr is not required.
317 */
318
319 switch (ls->sockaddr->u.sockaddr.sa_family) {
320
321 #if (NXT_INET6)
322
323 case AF_INET6:
324 ls->socklen = sizeof(struct sockaddr_in6);
325 ls->address_length = NXT_INET6_ADDR_STR_LEN;
326
327 size = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6)
328 + NXT_INET6_ADDR_STR_LEN + nxt_length(":65535");
329
330 if (IN6_IS_ADDR_UNSPECIFIED(&ls->sockaddr->u.sockaddr_in6.sin6_addr)) {
331 size += offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6);
332 }
333
334 break;
335
336 #endif
337
338 #if (NXT_HAVE_UNIX_DOMAIN)
339
340 case AF_UNIX:
341 /*
342 * A remote socket is usually unbound and thus has unspecified Unix
343 * domain sockaddr_un which can be shortcut to 3 bytes. To handle
344 * a bound remote socket correctly ls->socklen should be at least
345 * sizeof(struct sockaddr_un), see comment in nxt_socket.h.
346 */
347 ls->socklen = 3;
348 size = ls->socklen + nxt_length("unix:");
349 ls->address_length = nxt_length("unix:");
350
351 break;
352
353 #endif
354
355 default:
356 ls->socklen = sizeof(struct sockaddr_in);
357 ls->address_length = NXT_INET_ADDR_STR_LEN;
358
359 size = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in)
360 + NXT_INET_ADDR_STR_LEN + nxt_length(":65535");
361
362 if (ls->sockaddr->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) {
363 size += offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in);
364 }
365
366 break;
367 }
368
369 #if (NXT_TLS)
370
371 if (ls->tls) {
372 size += 4 * sizeof(void *) /* SSL/TLS connection */
373 + sizeof(nxt_buf_mem_t)
374 + sizeof(nxt_work_t); /* nxt_mp_cleanup */
375 }
376
377 #endif
378
379 return size // + sizeof(nxt_mem_pool_t)
380 + sizeof(nxt_conn_t)
381 + sizeof(nxt_log_t);
382 }
383
384
385 static u_char *
nxt_listen_socket_log_handler(void * ctx,u_char * pos,u_char * end)386 nxt_listen_socket_log_handler(void *ctx, u_char *pos, u_char *end)
387 {
388 nxt_sockaddr_t *sa;
389
390 sa = ctx;
391
392 return nxt_sprintf(pos, end, " while creating listening socket on %*s",
393 (size_t) sa->length, nxt_sockaddr_start(sa));
394 }
395