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