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