xref: /unit/src/nxt_listen_socket.c (revision 2646:b003301015ea)
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