varnish-cache/vmod/vmod_debug_dyn.c
0
/*-
1
 * Copyright (c) 2015 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Dridi Boukelmoune <dridi@varnish-software.com>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <netdb.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <sys/socket.h>
36
#include <sys/stat.h>
37
#include <unistd.h>
38
39
#include "cache/cache.h"
40
41
#include "vsa.h"
42
#include "vss.h"
43
#include "vus.h"
44
#include "vcc_debug_if.h"
45
46
struct xyzzy_debug_dyn {
47
        unsigned                magic;
48
#define VMOD_DEBUG_DYN_MAGIC    0x9b77ccbd
49
        pthread_mutex_t         mtx;
50
        char                    *vcl_name;
51
        VCL_BACKEND             dir;
52
};
53
54
struct xyzzy_debug_dyn_uds {
55
        unsigned                magic;
56
#define VMOD_DEBUG_UDS_MAGIC    0x6c7370e6
57
        pthread_mutex_t         mtx;
58
        char                    *vcl_name;
59
        VCL_BACKEND             dir;
60
};
61
62
static void
63 450
dyn_dir_init(VRT_CTX, struct xyzzy_debug_dyn *dyn,
64
    VCL_STRING addr, VCL_STRING port, VCL_PROBE probe, VCL_BACKEND via)
65
{
66
        const struct suckaddr *sa;
67
        VCL_BACKEND dir, dir2;
68
        struct vrt_endpoint vep;
69
        struct vrt_backend vrt;
70
71 450
        CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
72 450
        XXXAN(addr);
73 450
        XXXAN(port);
74 450
        CHECK_OBJ_ORNULL(via, DIRECTOR_MAGIC);
75
76 450
        INIT_OBJ(&vep, VRT_ENDPOINT_MAGIC);
77 450
        INIT_OBJ(&vrt, VRT_BACKEND_MAGIC);
78 450
        vrt.endpoint = &vep;
79 450
        vrt.vcl_name = dyn->vcl_name;
80 450
        vrt.hosthdr = addr;
81 450
        vrt.authority = addr;
82 450
        vrt.probe = probe;
83
84 450
        sa = VSS_ResolveOne(NULL, addr, port, AF_UNSPEC, SOCK_STREAM, 0);
85 450
        AN(sa);
86 450
        if (VSA_Get_Proto(sa) == AF_INET)
87 450
                vep.ipv4 = sa;
88 0
        else if (VSA_Get_Proto(sa) == AF_INET6)
89 0
                vep.ipv6 = sa;
90
        else
91 0
                WRONG("Wrong proto family");
92
93 450
        dir = VRT_new_backend(ctx, &vrt, via);
94 450
        AN(dir);
95
96
        /*
97
         * NB: A real dynamic backend should not replace the previous
98
         * instance if the new one is identical.  We do it here because
99
         * the d* tests requires a replacement.
100
         */
101 450
        PTOK(pthread_mutex_lock(&dyn->mtx));
102 450
        dir2 = dyn->dir;
103 450
        dyn->dir = dir;
104 450
        PTOK(pthread_mutex_unlock(&dyn->mtx));
105
106 450
        if (dir2 != NULL)
107 225
                VRT_delete_backend(ctx, &dir2);
108
109 450
        VSA_free(&sa);
110 450
}
111
112
VCL_VOID
113 250
xyzzy_dyn__init(VRT_CTX, struct xyzzy_debug_dyn **dynp,
114
    const char *vcl_name, VCL_STRING addr, VCL_STRING port, VCL_PROBE probe,
115
    VCL_BACKEND via)
116
{
117
        struct xyzzy_debug_dyn *dyn;
118
119 250
        ASSERT_CLI();
120 250
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
121 250
        AN(dynp);
122 250
        AZ(*dynp);
123 250
        AN(vcl_name);
124
125 250
        if (*addr == '\0' || *port == '\0') {
126 25
                AZ(VRT_handled(ctx));
127 25
                VRT_fail(ctx, "Missing dynamic backend address or port");
128 25
                return;
129
        }
130
131 225
        ALLOC_OBJ(dyn, VMOD_DEBUG_DYN_MAGIC);
132 225
        AN(dyn);
133 225
        REPLACE(dyn->vcl_name, vcl_name);
134
135 225
        PTOK(pthread_mutex_init(&dyn->mtx, NULL));
136
137 225
        dyn_dir_init(ctx, dyn, addr, port, probe, via);
138 225
        XXXAN(dyn->dir);
139 225
        *dynp = dyn;
140 250
}
141
142
VCL_VOID v_matchproto_(td_xyzzy_debug_dyn__fini)
143 25
xyzzy_dyn__fini(struct xyzzy_debug_dyn **dynp)
144
{
145
        struct xyzzy_debug_dyn *dyn;
146
147 25
        TAKE_OBJ_NOTNULL(dyn, dynp, VMOD_DEBUG_DYN_MAGIC);
148
        /* at this point all backends will be deleted by the vcl */
149 25
        free(dyn->vcl_name);
150 25
        PTOK(pthread_mutex_destroy(&dyn->mtx));
151 25
        FREE_OBJ(dyn);
152 25
}
153
154
VCL_BACKEND v_matchproto_()
155 400
xyzzy_dyn_backend(VRT_CTX, struct xyzzy_debug_dyn *dyn)
156
{
157
        VCL_BACKEND retval;
158 400
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
159 400
        CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
160 400
        PTOK(pthread_mutex_lock(&dyn->mtx));
161 400
        retval = dyn->dir;
162 400
        PTOK(pthread_mutex_unlock(&dyn->mtx));
163 400
        AN(retval);
164 400
        return (retval);
165
}
166
167
VCL_VOID
168 225
xyzzy_dyn_refresh(VRT_CTX, struct xyzzy_debug_dyn *dyn,
169
    VCL_STRING addr, VCL_STRING port, VCL_PROBE probe, VCL_BACKEND via)
170
{
171 225
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
172 225
        CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
173 225
        dyn_dir_init(ctx, dyn, addr, port, probe, via);
174 225
}
175
176
static int
177 425
dyn_uds_init(VRT_CTX, struct xyzzy_debug_dyn_uds *uds, VCL_STRING path)
178
{
179
        VCL_BACKEND dir, dir2;
180
        struct vrt_endpoint vep;
181
        struct vrt_backend vrt;
182
        struct stat st;
183
184 425
        if (path == NULL) {
185 0
                VRT_fail(ctx, "path is NULL");
186 0
                return (-1);
187
        }
188 425
        if (! VUS_is(path)) {
189 50
                VRT_fail(ctx, "path must be an absolute path: %s", path);
190 50
                return (-1);
191
        }
192
193
        /* XXX: now that we accept that sockets may come after vcl.load
194
         * and change during the life of a VCL, do we still need to check
195
         * this? It looks like both if blocks can be retired.
196
         */
197 375
        errno = 0;
198 375
        if (stat(path, &st) != 0) {
199 25
                VRT_fail(ctx, "Cannot stat path %s: %s", path, strerror(errno));
200 25
                return (-1);
201
        }
202 350
        if (!S_ISSOCK(st.st_mode)) {
203 25
                VRT_fail(ctx, "%s is not a socket", path);
204 25
                return (-1);
205
        }
206
207 325
        INIT_OBJ(&vep, VRT_ENDPOINT_MAGIC);
208 325
        INIT_OBJ(&vrt, VRT_BACKEND_MAGIC);
209 325
        vrt.endpoint = &vep;
210 325
        vep.uds_path = path;
211 325
        vrt.vcl_name = uds->vcl_name;
212 325
        vrt.hosthdr = "localhost";
213 325
        vep.ipv4 = NULL;
214 325
        vep.ipv6 = NULL;
215
216
        // we support via: uds -> ip, but not via: ip -> uds
217 325
        if ((dir = VRT_new_backend(ctx, &vrt, NULL)) == NULL)
218 0
                return (-1);
219
220 325
        PTOK(pthread_mutex_lock(&uds->mtx));
221 325
        dir2 = uds->dir;
222 325
        uds->dir = dir;
223 325
        PTOK(pthread_mutex_unlock(&uds->mtx));
224
225 325
        if (dir2 != NULL)
226 125
                VRT_delete_backend(ctx, &dir2);
227 325
        return (0);
228 425
}
229
230
VCL_VOID v_matchproto_(td_xyzzy_debug_dyn_uds__init)
231 300
xyzzy_dyn_uds__init(VRT_CTX, struct xyzzy_debug_dyn_uds **udsp,
232
    const char *vcl_name, VCL_STRING path)
233
{
234
        struct xyzzy_debug_dyn_uds *uds;
235
236 300
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
237 300
        AN(udsp);
238 300
        AZ(*udsp);
239 300
        AN(vcl_name);
240
241 300
        ALLOC_OBJ(uds, VMOD_DEBUG_UDS_MAGIC);
242 300
        AN(uds);
243 300
        REPLACE(uds->vcl_name, vcl_name);
244 300
        PTOK(pthread_mutex_init(&uds->mtx, NULL));
245
246 300
        if (dyn_uds_init(ctx, uds, path) != 0) {
247 100
                free(uds->vcl_name);
248 100
                PTOK(pthread_mutex_destroy(&uds->mtx));
249 100
                FREE_OBJ(uds);
250 100
                return;
251
        }
252
253 200
        *udsp = uds;
254 300
}
255
256
VCL_VOID v_matchproto_(td_debug_dyn_uds__fini)
257 25
xyzzy_dyn_uds__fini(struct xyzzy_debug_dyn_uds **udsp)
258
{
259
        struct xyzzy_debug_dyn_uds *uds;
260
261 25
        TAKE_OBJ_NOTNULL(uds, udsp, VMOD_DEBUG_UDS_MAGIC);
262 25
        free(uds->vcl_name);
263 25
        PTOK(pthread_mutex_destroy(&uds->mtx));
264 25
        FREE_OBJ(uds);
265 25
}
266
267
VCL_BACKEND v_matchproto_(td_debug_dyn_uds_backend)
268 325
xyzzy_dyn_uds_backend(VRT_CTX, struct xyzzy_debug_dyn_uds *uds)
269
{
270 325
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
271 325
        CHECK_OBJ_NOTNULL(uds, VMOD_DEBUG_UDS_MAGIC);
272 325
        AN(uds->dir);
273 325
        return (uds->dir);
274
}
275
276
VCL_VOID v_matchproto_(td_debug_dyn_uds_refresh)
277 125
xyzzy_dyn_uds_refresh(VRT_CTX, struct xyzzy_debug_dyn_uds *uds, VCL_STRING path)
278
{
279 125
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
280 125
        CHECK_OBJ_NOTNULL(uds, VMOD_DEBUG_UDS_MAGIC);
281 125
        (void) dyn_uds_init(ctx, uds, path);
282 125
}