xref: /unit/src/nxt_listen_socket.c (revision 771:f349b2d68e75)
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
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
30 nxt_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 
130 fail:
131 
132     nxt_socket_close(task, s);
133 
134 socket_fail:
135 
136     thr->log = old;
137 
138     return NXT_ERROR;
139 }
140 
141 
142 nxt_int_t
143 nxt_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 
170 fail:
171 
172     thr->log = old;
173 
174     return NXT_ERROR;
175 }
176 
177 
178 void
179 nxt_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 = 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 
219 size_t
220 nxt_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 + 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;
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)
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_TLS)
284 
285     if (ls->tls) {
286         size += 4 * sizeof(void *)       /* SSL/TLS connection */
287                 + sizeof(nxt_buf_mem_t)
288                 + sizeof(nxt_work_t);    /* nxt_mp_cleanup */
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 
299 static u_char *
300 nxt_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 }
309