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