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