nxt_listen_socket.c (13:3a52b2c3d3f1) nxt_listen_socket.c (62:5e1efcc7b740)
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8
9
10static u_char *nxt_listen_socket_log_handler(void *ctx, u_char *pos,
11 u_char *last);
12
13
14nxt_int_t
15nxt_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
121fail:
122
123 nxt_socket_close(task, s);
124
125socket_fail:
126
127 thr->log = old;
128
129 return NXT_ERROR;
130}
131
132
133nxt_int_t
134nxt_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
161fail:
162
163 thr->log = old;
164
165 return NXT_ERROR;
166}
167
168
169size_t
170nxt_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)
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8
9
10static u_char *nxt_listen_socket_log_handler(void *ctx, u_char *pos,
11 u_char *last);
12
13
14nxt_int_t
15nxt_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
121fail:
122
123 nxt_socket_close(task, s);
124
125socket_fail:
126
127 thr->log = old;
128
129 return NXT_ERROR;
130}
131
132
133nxt_int_t
134nxt_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
161fail:
162
163 thr->log = old;
164
165 return NXT_ERROR;
166}
167
168
169size_t
170nxt_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)
244 + sizeof(nxt_conn_t)
245 + sizeof(nxt_log_t);
246}
247
248
249static u_char *
250nxt_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}
245 + sizeof(nxt_log_t);
246}
247
248
249static u_char *
250nxt_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}