| | 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 |
} |