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