| | varnish-cache/bin/varnishd/acceptor/cache_acceptor.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
6 |
|
* |
7 |
|
* SPDX-License-Identifier: BSD-2-Clause |
8 |
|
* |
9 |
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
* modification, are permitted provided that the following conditions |
11 |
|
* are met: |
12 |
|
* 1. Redistributions of source code must retain the above copyright |
13 |
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
* documentation and/or other materials provided with the distribution. |
17 |
|
* |
18 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
19 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
22 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
26 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 |
|
* SUCH DAMAGE. |
29 |
|
* |
30 |
|
* This source file has the various trickery surrounding the accept/listen |
31 |
|
* sockets. |
32 |
|
* |
33 |
|
*/ |
34 |
|
|
35 |
|
#include "config.h" |
36 |
|
|
37 |
|
#include <stdlib.h> |
38 |
|
#include <netinet/in.h> |
39 |
|
#include <netinet/tcp.h> |
40 |
|
|
41 |
|
#include "cache/cache_varnishd.h" |
42 |
|
#include "acceptor/cache_acceptor.h" |
43 |
|
#include "acceptor/acceptor_priv.h" |
44 |
|
|
45 |
|
#include "cache/cache_transport.h" |
46 |
|
#include "cache/cache_pool.h" |
47 |
|
#include "common/heritage.h" |
48 |
|
|
49 |
|
#include "vcli_serve.h" |
50 |
|
#include "vtim.h" |
51 |
|
|
52 |
|
unsigned pool_accepting; |
53 |
|
|
54 |
|
static pthread_t VCA_thread; |
55 |
|
static vtim_dur vca_pace = 0.0; |
56 |
|
static struct lock pace_mtx; |
57 |
|
static pthread_mutex_t shut_mtx = PTHREAD_MUTEX_INITIALIZER; |
58 |
|
|
59 |
|
/*-------------------------------------------------------------------- |
60 |
|
* lacking a better place, we put some generic periodic updates |
61 |
|
* into the vca_acct() loop which we are running anyway |
62 |
|
*/ |
63 |
|
static void |
64 |
70134 |
vca_periodic(vtim_real t0) |
65 |
|
{ |
66 |
|
vtim_real now; |
67 |
|
|
68 |
70134 |
now = VTIM_real(); |
69 |
70134 |
VSC_C_main->uptime = (uint64_t)(now - t0); |
70 |
|
|
71 |
70134 |
VTIM_postel = FEATURE(FEATURE_HTTP_DATE_POSTEL); |
72 |
70134 |
} |
73 |
|
|
74 |
|
/*-------------------------------------------------------------------- |
75 |
|
* If accept(2)'ing fails, we pace ourselves to relive any resource |
76 |
|
* shortage if possible. |
77 |
|
*/ |
78 |
|
|
79 |
|
void |
80 |
157094 |
vca_pace_check(void) |
81 |
|
{ |
82 |
|
vtim_dur p; |
83 |
|
|
84 |
157094 |
if (vca_pace == 0.0) |
85 |
157094 |
return; |
86 |
0 |
Lck_Lock(&pace_mtx); |
87 |
0 |
p = vca_pace; |
88 |
0 |
Lck_Unlock(&pace_mtx); |
89 |
0 |
if (p > 0.0) |
90 |
0 |
VTIM_sleep(p); |
91 |
157094 |
} |
92 |
|
|
93 |
|
void |
94 |
0 |
vca_pace_bad(void) |
95 |
|
{ |
96 |
|
|
97 |
0 |
Lck_Lock(&pace_mtx); |
98 |
0 |
vca_pace += cache_param->acceptor_sleep_incr; |
99 |
0 |
if (vca_pace > cache_param->acceptor_sleep_max) |
100 |
0 |
vca_pace = cache_param->acceptor_sleep_max; |
101 |
0 |
Lck_Unlock(&pace_mtx); |
102 |
0 |
} |
103 |
|
|
104 |
|
void |
105 |
84583 |
vca_pace_good(void) |
106 |
|
{ |
107 |
|
|
108 |
84583 |
if (vca_pace == 0.0) |
109 |
84583 |
return; |
110 |
0 |
Lck_Lock(&pace_mtx); |
111 |
0 |
vca_pace *= cache_param->acceptor_sleep_decay; |
112 |
0 |
if (vca_pace < cache_param->acceptor_sleep_incr) |
113 |
0 |
vca_pace = 0.0; |
114 |
0 |
Lck_Unlock(&pace_mtx); |
115 |
84583 |
} |
116 |
|
|
117 |
|
/*-------------------------------------------------------------------- |
118 |
|
* Called when a worker and attached thread pool is created, to |
119 |
|
* allocate the tasks which will listen to sockets for that pool. |
120 |
|
*/ |
121 |
|
|
122 |
|
void |
123 |
72551 |
VCA_NewPool(struct pool *pp) |
124 |
|
{ |
125 |
|
struct acceptor *vca; |
126 |
|
|
127 |
217653 |
VCA_Foreach(vca) { |
128 |
145102 |
CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC); |
129 |
145102 |
vca->accept(pp); |
130 |
|
} |
131 |
72551 |
} |
132 |
|
|
133 |
|
void |
134 |
80 |
VCA_DestroyPool(struct pool *pp) |
135 |
|
{ |
136 |
|
struct poolsock *ps; |
137 |
|
|
138 |
160 |
while (!VTAILQ_EMPTY(&pp->poolsocks)) { |
139 |
80 |
ps = VTAILQ_FIRST(&pp->poolsocks); |
140 |
80 |
VTAILQ_REMOVE(&pp->poolsocks, ps, list); |
141 |
|
} |
142 |
80 |
} |
143 |
|
|
144 |
|
/*--------------------------------------------------------------------*/ |
145 |
|
|
146 |
|
static void * v_matchproto_() |
147 |
0 |
vca_acct(void *arg) |
148 |
|
{ |
149 |
|
struct acceptor *vca; |
150 |
|
vtim_real t0; |
151 |
|
|
152 |
|
// XXX Actually a misnomer now because the accept happens in a pool |
153 |
|
// thread. Rename to accept-nanny or so? |
154 |
0 |
THR_SetName("cache-acceptor"); |
155 |
0 |
THR_Init(); |
156 |
0 |
(void)arg; |
157 |
|
|
158 |
0 |
t0 = VTIM_real(); |
159 |
0 |
vca_periodic(t0); |
160 |
|
|
161 |
0 |
pool_accepting = 1; |
162 |
|
|
163 |
33654 |
while (1) { |
164 |
33654 |
(void)sleep(1); |
165 |
|
|
166 |
100962 |
VCA_Foreach(vca) { |
167 |
67308 |
CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC); |
168 |
67308 |
vca->update(&shut_mtx); |
169 |
|
} |
170 |
|
|
171 |
33654 |
vca_periodic(t0); |
172 |
|
} |
173 |
|
|
174 |
|
NEEDLESS(return (NULL)); |
175 |
|
} |
176 |
|
|
177 |
|
/*--------------------------------------------------------------------*/ |
178 |
|
|
179 |
|
void |
180 |
36480 |
VCA_Start(struct cli *cli) |
181 |
|
{ |
182 |
|
struct acceptor *vca; |
183 |
|
|
184 |
36480 |
ASSERT_CLI(); |
185 |
|
|
186 |
109440 |
VCA_Foreach(vca) { |
187 |
72960 |
CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC); |
188 |
72960 |
vca->start(cli); |
189 |
|
} |
190 |
|
|
191 |
36480 |
PTOK(pthread_create(&VCA_thread, NULL, vca_acct, NULL)); |
192 |
36480 |
} |
193 |
|
|
194 |
|
/*--------------------------------------------------------------------*/ |
195 |
|
|
196 |
|
static void v_matchproto_(cli_func_t) |
197 |
72440 |
ccf_listen_address(struct cli *cli, const char * const *av, void *priv) |
198 |
|
{ |
199 |
|
struct listen_sock *ls; |
200 |
|
|
201 |
72440 |
(void)av; |
202 |
72440 |
(void)priv; |
203 |
|
|
204 |
|
/* |
205 |
|
* This CLI command is primarily used by varnishtest. Don't |
206 |
|
* respond until listen(2) has been called, in order to avoid |
207 |
|
* a race where varnishtest::client would attempt to connect(2) |
208 |
|
* before listen(2) has been called. |
209 |
|
*/ |
210 |
72440 |
while (!pool_accepting) |
211 |
0 |
VTIM_sleep(.1); |
212 |
|
|
213 |
72440 |
PTOK(pthread_mutex_lock(&shut_mtx)); |
214 |
|
|
215 |
|
/* |
216 |
|
* Varnishtest expects the list of listen sockets to come out in the |
217 |
|
* same order as it is specified on the command line. |
218 |
|
*/ |
219 |
145360 |
VTAILQ_FOREACH(ls, &heritage.socks, list) { |
220 |
72920 |
CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC); |
221 |
72920 |
CHECK_OBJ_NOTNULL(ls->vca, ACCEPTOR_MAGIC); |
222 |
72920 |
ls->vca->event(cli, ls, VCA_EVENT_LADDR); |
223 |
72920 |
} |
224 |
|
|
225 |
72440 |
PTOK(pthread_mutex_unlock(&shut_mtx)); |
226 |
72440 |
} |
227 |
|
|
228 |
|
/*--------------------------------------------------------------------*/ |
229 |
|
|
230 |
|
static struct cli_proto vca_cmds[] = { |
231 |
|
{ CLICMD_DEBUG_LISTEN_ADDRESS, "d", ccf_listen_address }, |
232 |
|
{ NULL } |
233 |
|
}; |
234 |
|
|
235 |
|
void |
236 |
36670 |
VCA_Init(void) |
237 |
|
{ |
238 |
|
struct acceptor *vca; |
239 |
|
|
240 |
36670 |
CLI_AddFuncs(vca_cmds); |
241 |
36670 |
Lck_New(&pace_mtx, lck_vcapace); |
242 |
|
|
243 |
110010 |
VCA_Foreach(vca) { |
244 |
73340 |
CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC); |
245 |
73340 |
vca->init(); |
246 |
|
} |
247 |
36670 |
} |
248 |
|
|
249 |
|
void |
250 |
36160 |
VCA_Shutdown(void) |
251 |
|
{ |
252 |
|
struct acceptor *vca; |
253 |
|
|
254 |
36160 |
PTOK(pthread_mutex_lock(&shut_mtx)); |
255 |
|
|
256 |
108480 |
VCA_Foreach(vca) { |
257 |
72320 |
CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC); |
258 |
72320 |
vca->shutdown(); |
259 |
|
} |
260 |
|
|
261 |
36160 |
PTOK(pthread_mutex_unlock(&shut_mtx)); |
262 |
36160 |
} |
263 |
|
|
264 |
|
/*-------------------------------------------------------------------- |
265 |
|
* Transport protocol registration |
266 |
|
* |
267 |
|
*/ |
268 |
|
|
269 |
|
static VTAILQ_HEAD(,transport) transports = |
270 |
|
VTAILQ_HEAD_INITIALIZER(transports); |
271 |
|
|
272 |
|
static uint16_t next_xport; |
273 |
|
|
274 |
|
void |
275 |
119520 |
XPORT_Register(struct transport *xp) |
276 |
|
{ |
277 |
|
|
278 |
119520 |
CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC); |
279 |
119520 |
AZ(xp->number); |
280 |
|
|
281 |
119520 |
xp->number = ++next_xport; |
282 |
119520 |
VTAILQ_INSERT_TAIL(&transports, xp, list); |
283 |
119520 |
} |
284 |
|
|
285 |
|
void |
286 |
39840 |
XPORT_Init(void) |
287 |
|
{ |
288 |
|
|
289 |
39840 |
ASSERT_MGT(); |
290 |
|
|
291 |
|
#define TRANSPORT_MACRO(name) XPORT_Register(&name##_transport); |
292 |
39840 |
TRANSPORTS |
293 |
|
#undef TRANSPORT_MACRO |
294 |
39840 |
} |
295 |
|
|
296 |
|
const struct transport * |
297 |
38800 |
XPORT_Find(const char *name) |
298 |
|
{ |
299 |
|
const struct transport *xp; |
300 |
|
|
301 |
38800 |
ASSERT_MGT(); |
302 |
|
|
303 |
77040 |
VTAILQ_FOREACH(xp, &transports, list) |
304 |
76960 |
if (xp->proto_ident != NULL && |
305 |
76960 |
!strcasecmp(xp->proto_ident, name)) |
306 |
38720 |
return (xp); |
307 |
80 |
return (NULL); |
308 |
38800 |
} |
309 |
|
|
310 |
|
const struct transport * |
311 |
91968 |
XPORT_ByNumber(uint16_t no) |
312 |
|
{ |
313 |
|
const struct transport *xp; |
314 |
|
|
315 |
183977 |
VTAILQ_FOREACH(xp, &transports, list) |
316 |
183977 |
if (xp->number == no) |
317 |
91968 |
return (xp); |
318 |
0 |
return (NULL); |
319 |
91968 |
} |