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