varnish-cache/bin/varnishd/cache/cache_vrt_vmod.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
 * Runtime support for compiled VCL programs
31
 */
32
33
#include "config.h"
34
35
#include "cache_varnishd.h"
36
37
#include <dlfcn.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
41
#include "vcli_serve.h"
42
#include "vcc_interface.h"
43
#include "vmod_abi.h"
44
45
/*--------------------------------------------------------------------
46
 * Modules stuff
47
 */
48
49
struct vmod {
50
        unsigned                magic;
51
#define VMOD_MAGIC              0xb750219c
52
53
        VTAILQ_ENTRY(vmod)      list;
54
55
        int                     ref;
56
57
        char                    *nm;
58
        unsigned                nbr;
59
        char                    *path;
60
        char                    *backup;
61
        void                    *hdl;
62
        const void              *funcs;
63
        int                     funclen;
64
        const char              *abi;
65
        unsigned                vrt_major;
66
        unsigned                vrt_minor;
67
        const char              *vcs;
68
        const char              *version;
69
};
70
71
static VTAILQ_HEAD(,vmod)       vmods = VTAILQ_HEAD_INITIALIZER(vmods);
72
73
static unsigned
74 1800
vmod_abi_mismatch(const struct vmod_data *d)
75
{
76
77 1800
        if (d->vrt_major == 0 && d->vrt_minor == 0)
78 1440
                return (d->abi == NULL || strcmp(d->abi, VMOD_ABI_Version));
79
80 360
        return (d->vrt_major != VRT_MAJOR_VERSION ||
81 360
            d->vrt_minor > VRT_MINOR_VERSION);
82 1800
}
83
84
int
85 2485
VPI_Vmod_Init(VRT_CTX, struct vmod **hdl, unsigned nbr, void *ptr, int len,
86
    const char *nm, const char *path, const char *file_id, const char *backup)
87
{
88
        struct vmod *v;
89
        const struct vmod_data *d;
90
        char buf[256];
91
        void *dlhdl;
92
93 2485
        ASSERT_CLI();
94 2485
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
95 2485
        AN(ctx->msg);
96 2485
        AN(hdl);
97 2485
        AZ(*hdl);
98
99 2485
        dlhdl = dlopen(backup, RTLD_NOW | RTLD_LOCAL);
100 2485
        if (dlhdl == NULL) {
101 0
                VSB_printf(ctx->msg, "Loading vmod %s from %s (%s):\n",
102 0
                    nm, backup, path);
103 0
                VSB_printf(ctx->msg, "dlopen() failed: %s\n", dlerror());
104 0
                return (1);
105
        }
106
107 3230
        VTAILQ_FOREACH(v, &vmods, list)
108 1430
                if (v->hdl == dlhdl)
109 685
                        break;
110 2485
        if (v == NULL) {
111 1800
                ALLOC_OBJ(v, VMOD_MAGIC);
112 1800
                AN(v);
113
114 1800
                v->hdl = dlhdl;
115
116 1800
                bprintf(buf, "Vmod_%s_Data", nm);
117 1800
                d = dlsym(v->hdl, buf);
118 3600
                if (d == NULL ||
119 1800
                    d->file_id == NULL ||
120 1800
                    strcmp(d->file_id, file_id)) {
121 0
                        VSB_printf(ctx->msg, "Loading vmod %s from %s (%s):\n",
122 0
                            nm, backup, path);
123 0
                        VSB_cat(ctx->msg,
124
                            "This is no longer the same file seen by"
125
                            " the VCL-compiler.\n");
126 0
                        (void)dlclose(v->hdl);
127 0
                        FREE_OBJ(v);
128 0
                        return (1);
129
                }
130 3600
                if (vmod_abi_mismatch(d) ||
131 1800
                    d->name == NULL ||
132 1800
                    strcmp(d->name, nm) ||
133 1800
                    d->func == NULL ||
134 1800
                    d->func_len <= 0 ||
135 1800
                    d->proto != NULL ||
136 1800
                    d->json == NULL) {
137 0
                        VSB_printf(ctx->msg, "Loading vmod %s from %s (%s):\n",
138 0
                            nm, backup, path);
139 0
                        VSB_cat(ctx->msg, "VMOD data is mangled.\n");
140 0
                        (void)dlclose(v->hdl);
141 0
                        FREE_OBJ(v);
142 0
                        return (1);
143
                }
144
145 1800
                v->nbr = nbr;
146 1800
                v->funclen = d->func_len;
147 1800
                v->funcs = d->func;
148 1800
                v->abi = d->abi;
149 1800
                v->vrt_major = d->vrt_major;
150 1800
                v->vrt_minor = d->vrt_minor;
151 1800
                v->vcs = d->vcs;
152 1800
                v->version = d->version;
153
154 1800
                REPLACE(v->nm, nm);
155 1800
                REPLACE(v->path, path);
156 1800
                REPLACE(v->backup, backup);
157
158 1800
                VSC_C_main->vmods++;
159 1800
                VTAILQ_INSERT_TAIL(&vmods, v, list);
160 1800
        }
161
162 2485
        assert(len == v->funclen);
163 2485
        memcpy(ptr, v->funcs, v->funclen);
164 2485
        v->ref++;
165
166 2485
        *hdl = v;
167 2485
        return (0);
168 2485
}
169
170
void
171 392
VPI_Vmod_Unload(VRT_CTX, struct vmod **hdl)
172
{
173
        struct vmod *v;
174
175 392
        ASSERT_CLI();
176
177 392
        TAKE_OBJ_NOTNULL(v, hdl, VMOD_MAGIC);
178
179 392
        VCL_TaskLeave(ctx, cli_task_privs);
180 392
        VCL_TaskEnter(cli_task_privs);
181
182
#ifndef DONT_DLCLOSE_VMODS
183
        /*
184
         * atexit(3) handlers are not called during dlclose(3).  We don't
185
         * normally use them, but we do when running GCOV.  This option
186
         * enables us to do that.
187
         */
188
        AZ(dlclose(v->hdl));
189
#endif
190 392
        if (--v->ref != 0)
191 280
                return;
192 112
        free(v->nm);
193 112
        free(v->path);
194 112
        free(v->backup);
195 112
        VTAILQ_REMOVE(&vmods, v, list);
196 112
        VSC_C_main->vmods--;
197 112
        FREE_OBJ(v);
198 392
}
199
200
void
201 63
VMOD_Panic(struct vsb *vsb)
202
{
203
        struct vmod *v;
204
205 63
        VSB_cat(vsb, "vmods = {\n");
206 63
        VSB_indent(vsb, 2);
207 113
        VTAILQ_FOREACH(v, &vmods, list) {
208 50
                VSB_printf(vsb, "%s = {", v->nm);
209 50
                VSB_indent(vsb, 2);
210 100
                VSB_printf(vsb, "p=%p, abi=\"%s\", vrt=%u.%u,\n",
211 50
                           v, v->abi, v->vrt_major, v->vrt_minor);
212 50
                VSB_bcat(vsb, "vcs=", 4);
213 50
                VSB_quote(vsb, v->vcs, -1, VSB_QUOTE_CSTR);
214 50
                VSB_bcat(vsb, ", version=", 10);
215 50
                VSB_quote(vsb, v->version, -1, VSB_QUOTE_CSTR);
216 50
                VSB_indent(vsb, -2);
217 50
                VSB_bcat(vsb, "},\n", 3);
218 50
        }
219
220 63
        VSB_indent(vsb, -2);
221 63
        VSB_cat(vsb, "},\n");
222 63
}
223
224
/*---------------------------------------------------------------------*/
225
226
static void v_matchproto_(cli_func_t)
227 20
ccf_debug_vmod(struct cli *cli, const char * const *av, void *priv)
228
{
229
        struct vmod *v;
230
231 20
        (void)av;
232 20
        (void)priv;
233 20
        ASSERT_CLI();
234 40
        VTAILQ_FOREACH(v, &vmods, list) {
235 40
                VCLI_Out(cli, "%5d %s (path=\"%s\", version=\"%s\","
236 20
                    " vcs=\"%s\")\n", v->ref, v->nm, v->path, v->version,
237 20
                    v->vcs);
238 20
        }
239 20
}
240
241
static struct cli_proto vcl_cmds[] = {
242
        { CLICMD_DEBUG_VMOD,                    "d", ccf_debug_vmod },
243
        { NULL }
244
};
245
246
void
247 4601
VMOD_Init(void)
248
{
249
250 4601
        CLI_AddFuncs(vcl_cmds);
251 4601
}