varnish-cache/vmod/vmod_debug_dyn.c
1
/*-
2
 * Copyright (c) 2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Dridi Boukelmoune <dridi@varnish-software.com>
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
31
#include "config.h"
32
33
#include <netdb.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <sys/socket.h>
37
#include <sys/stat.h>
38
#include <unistd.h>
39
40
#include "cache/cache.h"
41
42
#include "vsa.h"
43
#include "vss.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 280
dyn_dir_init(VRT_CTX, struct xyzzy_debug_dyn *dyn,
64
     VCL_STRING addr, VCL_STRING port, VCL_PROBE probe)
65
{
66
        struct suckaddr *sa;
67
        VCL_BACKEND dir, dir2;
68
        struct vrt_endpoint vep;
69
        struct vrt_backend vrt;
70
71 280
        CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
72 280
        XXXAN(addr);
73 280
        XXXAN(port);
74
75 280
        INIT_OBJ(&vep, VRT_ENDPOINT_MAGIC);
76 280
        INIT_OBJ(&vrt, VRT_BACKEND_MAGIC);
77 280
        vrt.endpoint = &vep;
78 280
        vrt.vcl_name = dyn->vcl_name;
79 280
        vrt.hosthdr = addr;
80 280
        vrt.probe = probe;
81
82 280
        sa = VSS_ResolveOne(NULL, addr, port, AF_UNSPEC, SOCK_STREAM, 0);
83 280
        AN(sa);
84 280
        if (VSA_Get_Proto(sa) == AF_INET)
85 280
                vep.ipv4 = sa;
86 0
        else if (VSA_Get_Proto(sa) == AF_INET6)
87 0
                vep.ipv6 = sa;
88
        else
89 0
                WRONG("Wrong proto family");
90
91 280
        dir = VRT_new_backend(ctx, &vrt);
92 280
        AN(dir);
93
94
        /*
95
         * NB: A real dynamic backend should not replace the previous
96
         * instance if the new one is identical.  We do it here because
97
         * the d* tests requires a replacement.
98
         */
99 280
        AZ(pthread_mutex_lock(&dyn->mtx));
100 280
        dir2 = dyn->dir;
101 280
        dyn->dir = dir;
102 280
        AZ(pthread_mutex_unlock(&dyn->mtx));
103
104 280
        if (dir2 != NULL)
105 120
                VRT_delete_backend(ctx, &dir2);
106
107 280
        free(sa);
108 280
}
109
110
VCL_VOID
111 180
xyzzy_dyn__init(VRT_CTX, struct xyzzy_debug_dyn **dynp,
112
    const char *vcl_name, VCL_STRING addr, VCL_STRING port, VCL_PROBE probe)
113
{
114
        struct xyzzy_debug_dyn *dyn;
115
116 180
        ASSERT_CLI();
117 180
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
118 180
        AN(dynp);
119 180
        AZ(*dynp);
120 180
        AN(vcl_name);
121
122 180
        if (*addr == '\0' || *port == '\0') {
123 20
                AN(ctx->handling);
124 20
                AZ(*ctx->handling);
125 20
                VRT_fail(ctx, "Missing dynamic backend address or port");
126 20
                return;
127
        }
128
129 160
        ALLOC_OBJ(dyn, VMOD_DEBUG_DYN_MAGIC);
130 160
        AN(dyn);
131 160
        REPLACE(dyn->vcl_name, vcl_name);
132
133 160
        AZ(pthread_mutex_init(&dyn->mtx, NULL));
134
135 160
        dyn_dir_init(ctx, dyn, addr, port, probe);
136 160
        XXXAN(dyn->dir);
137 160
        *dynp = dyn;
138 180
}
139
140
VCL_VOID v_matchproto_(td_xyzzy_debug_dyn__fini)
141 20
xyzzy_dyn__fini(struct xyzzy_debug_dyn **dynp)
142
{
143
        struct xyzzy_debug_dyn *dyn;
144
145 20
        TAKE_OBJ_NOTNULL(dyn, dynp, VMOD_DEBUG_DYN_MAGIC);
146
        /* at this point all backends will be deleted by the vcl */
147 20
        free(dyn->vcl_name);
148 20
        AZ(pthread_mutex_destroy(&dyn->mtx));
149 20
        FREE_OBJ(dyn);
150 20
}
151
152
VCL_BACKEND v_matchproto_()
153 260
xyzzy_dyn_backend(VRT_CTX, struct xyzzy_debug_dyn *dyn)
154
{
155 260
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
156 260
        CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
157 260
        AN(dyn->dir);
158 260
        return (dyn->dir);
159
}
160
161
VCL_VOID
162 120
xyzzy_dyn_refresh(VRT_CTX, struct xyzzy_debug_dyn *dyn,
163
    VCL_STRING addr, VCL_STRING port, VCL_PROBE probe)
164
{
165 120
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
166 120
        CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
167 120
        dyn_dir_init(ctx, dyn, addr, port, probe);
168 120
}
169
170
static int
171 340
dyn_uds_init(VRT_CTX, struct xyzzy_debug_dyn_uds *uds, VCL_STRING path)
172
{
173
        VCL_BACKEND dir, dir2;
174
        struct vrt_endpoint vep;
175
        struct vrt_backend vrt;
176
        struct stat st;
177
178 340
        if (path == NULL) {
179 0
                VRT_fail(ctx, "path is NULL");
180 0
                return (-1);
181
        }
182 340
        if (*path != '/') {
183 40
                VRT_fail(ctx, "path must be an absolute path: %s", path);
184 40
                return (-1);
185
        }
186
187
        /* XXX: now that we accept that sockets may come after vcl.load
188
         * and change during the life of a VCL, do we still need to check
189
         * this? It looks like both if blocks can be retired.
190
         */
191 300
        errno = 0;
192 300
        if (stat(path, &st) != 0) {
193 20
                VRT_fail(ctx, "Cannot stat path %s: %s", path, strerror(errno));
194 20
                return (-1);
195
        }
196 280
        if (!S_ISSOCK(st.st_mode)) {
197 20
                VRT_fail(ctx, "%s is not a socket", path);
198 20
                return (-1);
199
        }
200
201 260
        INIT_OBJ(&vep, VRT_ENDPOINT_MAGIC);
202 260
        INIT_OBJ(&vrt, VRT_BACKEND_MAGIC);
203 260
        vrt.endpoint = &vep;
204 260
        vep.uds_path = path;
205 260
        vrt.vcl_name = uds->vcl_name;
206 260
        vrt.hosthdr = "localhost";
207 260
        vep.ipv4 = NULL;
208 260
        vep.ipv6 = NULL;
209
210 260
        if ((dir = VRT_new_backend(ctx, &vrt)) == NULL)
211 0
                return (-1);
212
213 260
        AZ(pthread_mutex_lock(&uds->mtx));
214 260
        dir2 = uds->dir;
215 260
        uds->dir = dir;
216 260
        AZ(pthread_mutex_unlock(&uds->mtx));
217
218 260
        if (dir2 != NULL)
219 100
                VRT_delete_backend(ctx, &dir2);
220 260
        return (0);
221 340
}
222
223
VCL_VOID v_matchproto_(td_xyzzy_debug_dyn_uds__init)
224 240
xyzzy_dyn_uds__init(VRT_CTX, struct xyzzy_debug_dyn_uds **udsp,
225
    const char *vcl_name, VCL_STRING path)
226
{
227
        struct xyzzy_debug_dyn_uds *uds;
228
229 240
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
230 240
        AN(udsp);
231 240
        AZ(*udsp);
232 240
        AN(vcl_name);
233
234 240
        ALLOC_OBJ(uds, VMOD_DEBUG_UDS_MAGIC);
235 240
        AN(uds);
236 240
        REPLACE(uds->vcl_name, vcl_name);
237 240
        AZ(pthread_mutex_init(&uds->mtx, NULL));
238
239 240
        if (dyn_uds_init(ctx, uds, path) != 0) {
240 80
                free(uds->vcl_name);
241 80
                AZ(pthread_mutex_destroy(&uds->mtx));
242 80
                FREE_OBJ(uds);
243 80
                return;
244
        }
245
246 160
        *udsp = uds;
247 240
}
248
249
VCL_VOID v_matchproto_(td_debug_dyn_uds__fini)
250 20
xyzzy_dyn_uds__fini(struct xyzzy_debug_dyn_uds **udsp)
251
{
252
        struct xyzzy_debug_dyn_uds *uds;
253
254 20
        TAKE_OBJ_NOTNULL(uds, udsp, VMOD_DEBUG_UDS_MAGIC);
255 20
        free(uds->vcl_name);
256 20
        AZ(pthread_mutex_destroy(&uds->mtx));
257 20
        FREE_OBJ(uds);
258 20
}
259
260
VCL_BACKEND v_matchproto_(td_debug_dyn_uds_backend)
261 260
xyzzy_dyn_uds_backend(VRT_CTX, struct xyzzy_debug_dyn_uds *uds)
262
{
263 260
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
264 260
        CHECK_OBJ_NOTNULL(uds, VMOD_DEBUG_UDS_MAGIC);
265 260
        AN(uds->dir);
266 260
        return (uds->dir);
267
}
268
269
VCL_VOID v_matchproto_(td_debug_dyn_uds_refresh)
270 100
xyzzy_dyn_uds_refresh(VRT_CTX, struct xyzzy_debug_dyn_uds *uds, VCL_STRING path)
271
{
272 100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
273 100
        CHECK_OBJ_NOTNULL(uds, VMOD_DEBUG_UDS_MAGIC);
274 100
        (void) dyn_uds_init(ctx, uds, path);
275 100
}