vinyl-cache/bin/vinyld/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
#include <signal.h>
41
42
#include "cache/cache_int.h"
43
#include "acceptor/cache_acceptor.h"
44
#include "acceptor/acceptor_priv.h"
45
46
#include "cache/cache_transport.h"
47
#include "cache/cache_pool.h"
48
#include "common/heritage.h"
49
50
#include "vcli_serve.h"
51
#include "vtim.h"
52
53
unsigned pool_accepting;
54
55
static pthread_t        VCA_thread;
56
static vtim_dur vca_pace = 0.0;
57
static struct lock pace_mtx;
58
static struct lock shut_mtx;
59
60
/*--------------------------------------------------------------------
61
 * lacking a better place, we put some generic periodic updates
62
 * into the vca_acct() loop which we are running anyway
63
 */
64
static void
65 61487
vca_periodic(vtim_real t0)
66
{
67
        vtim_real now;
68
69 61487
        now = VTIM_real();
70 61487
        VSC_C_main->uptime = (uint64_t)(now - t0);
71
72 61487
        VTIM_postel = FEATURE(FEATURE_HTTP_DATE_POSTEL);
73 61487
}
74
75
/*--------------------------------------------------------------------
76
 * If accept(2)'ing fails, we pace ourselves to relive any resource
77
 * shortage if possible.
78
 */
79
80
void
81 90704
vca_pace_check(void)
82
{
83
        vtim_dur p;
84
85 90704
        if (vca_pace == 0.0)
86 90704
                return;
87 0
        Lck_Lock(&pace_mtx);
88 0
        p = vca_pace;
89 0
        Lck_Unlock(&pace_mtx);
90 0
        if (p > 0.0)
91 0
                VTIM_sleep(p);
92 90704
}
93
94
void
95 0
vca_pace_bad(void)
96
{
97
98 0
        Lck_Lock(&pace_mtx);
99 0
        vca_pace += cache_param->acceptor_sleep_incr;
100 0
        if (vca_pace > cache_param->acceptor_sleep_max)
101 0
                vca_pace = cache_param->acceptor_sleep_max;
102 0
        Lck_Unlock(&pace_mtx);
103 0
}
104
105
void
106 49191
vca_pace_good(void)
107
{
108
109 49191
        if (vca_pace == 0.0)
110 49191
                return;
111 0
        Lck_Lock(&pace_mtx);
112 0
        vca_pace *= cache_param->acceptor_sleep_decay;
113 0
        if (vca_pace < cache_param->acceptor_sleep_incr)
114 0
                vca_pace = 0.0;
115 0
        Lck_Unlock(&pace_mtx);
116 49191
}
117
118
/*--------------------------------------------------------------------
119
 * Called when a worker and attached thread pool is created, to
120
 * allocate the tasks which will listen to sockets for that pool.
121
 */
122
123
void
124 41481
VCA_NewPool(struct pool *pp)
125
{
126
        struct acceptor *vca;
127
128 124443
        VCA_Foreach(vca) {
129 82962
                CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC);
130 82962
                vca->accept(pp);
131
        }
132 41481
}
133
134
void
135 40950
VCA_DestroyPool(struct pool *pp)
136
{
137
        struct poolsock *ps;
138
139 105742
        while (1) {
140 105742
                Lck_Lock(&pp->mtx);
141 170793
                VTAILQ_FOREACH(ps, &pp->poolsocks, list) {
142 65051
                        pthread_t thr = ps->thread;
143
                        // We use cli_thread as a "not accepting" marker
144 65051
                        if (pthread_equal(thr, cli_thread))
145 19979
                                continue;
146 45072
                        (void)pthread_kill(thr, SIGUSR1);
147 45072
                }
148 105742
                Lck_Unlock(&pp->mtx);
149 105742
                if (VTAILQ_EMPTY(&pp->poolsocks))
150 40950
                        break;
151 64792
                usleep (100);
152
        }
153 40950
}
154
155
/*--------------------------------------------------------------------*/
156
157
static void * v_matchproto_()
158 0
vca_acct(void *arg)
159
{
160
        struct acceptor *vca;
161
        vtim_real t0;
162
163
        // XXX Actually a misnomer now because the accept happens in a pool
164
        // thread. Rename to accept-nanny or so?
165 0
        THR_SetName("cache-acceptor");
166 0
        THR_Init();
167 0
        (void)arg;
168
169 0
        t0 = VTIM_real();
170 0
        vca_periodic(t0);
171
172 0
        pool_accepting = 1;
173
174 40697
        while (1) {
175 40697
                (void)sleep(1);
176
177 122091
                VCA_Foreach(vca) {
178 81394
                        CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC);
179 81394
                        vca->update(&shut_mtx);
180
                }
181
182 40697
                vca_periodic(t0);
183
        }
184
185
        NEEDLESS(return (NULL));
186
}
187
188
/*--------------------------------------------------------------------*/
189
190
void
191 20790
VCA_Start(struct cli *cli)
192
{
193
        struct acceptor *vca;
194
195 20790
        ASSERT_CLI();
196
197 62370
        VCA_Foreach(vca) {
198 41580
                CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC);
199 41580
                vca->start(cli);
200
        }
201
202 20790
        PTOK(pthread_create(&VCA_thread, NULL, vca_acct, NULL));
203 20790
}
204
205
/*--------------------------------------------------------------------*/
206
207
static void v_matchproto_(cli_func_t)
208 41223
ccf_listen_address(struct cli *cli, const char * const *av, void *priv)
209
{
210
        struct listen_sock *ls;
211
212 41223
        (void)av;
213 41223
        (void)priv;
214
215
        /*
216
         * This CLI command is primarily used by vinyltest.  Don't
217
         * respond until listen(2) has been called, in order to avoid
218
         * a race where vinyltest::client would attempt to connect(2)
219
         * before listen(2) has been called.
220
         */
221 41223
        while (!pool_accepting)
222 0
                VTIM_sleep(.1);
223
224 41223
        Lck_Lock(&shut_mtx);
225
226
        /*
227
         * Vinyltest expects the list of listen sockets to come out in the
228
         * same order as it is specified on the command line.
229
         */
230 82698
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
231 41475
                CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
232 41475
                CHECK_OBJ_NOTNULL(ls->vca, ACCEPTOR_MAGIC);
233 41475
                ls->vca->event(cli, ls, VCA_EVENT_LADDR);
234 41475
        }
235
236 41223
        Lck_Unlock(&shut_mtx);
237 41223
}
238
239
/*--------------------------------------------------------------------*/
240
241
static struct cli_proto vca_cmds[] = {
242
        { CLICMD_DEBUG_LISTEN_ADDRESS,  "d", ccf_listen_address },
243
        { NULL }
244
};
245
246
static sigset_t set_sigusr1;
247
248
void
249 20885
VCA_Init(void)
250
{
251
        struct acceptor *vca;
252
253 20885
        CLI_AddFuncs(vca_cmds);
254 20885
        Lck_New(&pace_mtx, lck_vcapace);
255 20885
        Lck_New(&shut_mtx, lck_vcashut);
256
257 62655
        VCA_Foreach(vca) {
258 41770
                CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC);
259 41770
                vca->init();
260
        }
261
262 20885
        AZ(sigemptyset(&set_sigusr1));
263 20885
        AZ(sigaddset(&set_sigusr1, SIGUSR1));
264 20885
}
265
266
void
267 20622
VCA_Shutdown(void)
268
{
269
        struct acceptor *vca;
270
271 20622
        Lck_Lock(&shut_mtx);
272
273 61866
        VCA_Foreach(vca) {
274 41244
                CHECK_OBJ_NOTNULL(vca, ACCEPTOR_MAGIC);
275 41244
                vca->shutdown();
276
        }
277
278 20622
        Lck_Unlock(&shut_mtx);
279 20622
}
280
281
void
282 41611
VCA_USR1_Unblock(void)
283
{
284 41611
        AZ(pthread_sigmask(SIG_UNBLOCK, &set_sigusr1, NULL));
285 41611
}
286
287
void
288 41235
VCA_USR1_Block(void)
289
{
290 41235
        AZ(pthread_sigmask(SIG_BLOCK, &set_sigusr1, NULL));
291 41235
}
292
293
/*--------------------------------------------------------------------
294
 * Transport protocol registration
295
 *
296
 */
297
298
static VTAILQ_HEAD(,transport)  transports =
299
    VTAILQ_HEAD_INITIALIZER(transports);
300
301
static uint16_t next_xport;
302
303
void
304 68478
XPORT_Register(struct transport *xp)
305
{
306
307 68478
        CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC);
308 68478
        AZ(xp->number);
309
310 68478
        xp->number = ++next_xport;
311 68478
        VTAILQ_INSERT_TAIL(&transports, xp, list);
312 68478
}
313
314
void
315 22826
XPORT_Init(void)
316
{
317
318 22826
        ASSERT_MGT();
319
320
#define TRANSPORT_MACRO(name) XPORT_Register(&name##_transport);
321 22826
        TRANSPORTS
322
#undef TRANSPORT_MACRO
323 22826
}
324
325
const struct transport *
326 22133
XPORT_Find(const char *name)
327
{
328
        const struct transport *xp;
329
330 22133
        ASSERT_MGT();
331
332 43930
        VTAILQ_FOREACH(xp, &transports, list)
333 43888
                if (xp->proto_ident != NULL &&
334 43888
                    !strcasecmp(xp->proto_ident, name))
335 22091
                        return (xp);
336 42
        return (NULL);
337 22133
}
338
339
const struct transport *
340 55275
XPORT_ByNumber(uint16_t no)
341
{
342
        const struct transport *xp;
343
344 110568
        VTAILQ_FOREACH(xp, &transports, list)
345 110568
                if (xp->number == no)
346 55275
                        return (xp);
347 0
        return (NULL);
348 55275
}