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