| | 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 |
|
}; |
68 |
|
|
69 |
|
static VTAILQ_HEAD(,vmod) vmods = VTAILQ_HEAD_INITIALIZER(vmods); |
70 |
|
|
71 |
|
static unsigned |
72 |
14400 |
vmod_abi_mismatch(const struct vmod_data *d) |
73 |
|
{ |
74 |
|
|
75 |
14400 |
if (d->vrt_major == 0 && d->vrt_minor == 0) |
76 |
11520 |
return (d->abi == NULL || strcmp(d->abi, VMOD_ABI_Version)); |
77 |
|
|
78 |
2880 |
return (d->vrt_major != VRT_MAJOR_VERSION || |
79 |
2880 |
d->vrt_minor > VRT_MINOR_VERSION); |
80 |
14400 |
} |
81 |
|
|
82 |
|
int |
83 |
19880 |
VPI_Vmod_Init(VRT_CTX, struct vmod **hdl, unsigned nbr, void *ptr, int len, |
84 |
|
const char *nm, const char *path, const char *file_id, const char *backup) |
85 |
|
{ |
86 |
|
struct vmod *v; |
87 |
|
const struct vmod_data *d; |
88 |
|
char buf[256]; |
89 |
|
void *dlhdl; |
90 |
|
|
91 |
19880 |
ASSERT_CLI(); |
92 |
19880 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
93 |
19880 |
AN(ctx->msg); |
94 |
19880 |
AN(hdl); |
95 |
19880 |
AZ(*hdl); |
96 |
|
|
97 |
19880 |
dlhdl = dlopen(backup, RTLD_NOW | RTLD_LOCAL); |
98 |
19880 |
if (dlhdl == NULL) { |
99 |
0 |
VSB_printf(ctx->msg, "Loading vmod %s from %s (%s):\n", |
100 |
0 |
nm, backup, path); |
101 |
0 |
VSB_printf(ctx->msg, "dlopen() failed: %s\n", dlerror()); |
102 |
0 |
return (1); |
103 |
|
} |
104 |
|
|
105 |
25840 |
VTAILQ_FOREACH(v, &vmods, list) |
106 |
11440 |
if (v->hdl == dlhdl) |
107 |
5480 |
break; |
108 |
19880 |
if (v == NULL) { |
109 |
14400 |
ALLOC_OBJ(v, VMOD_MAGIC); |
110 |
14400 |
AN(v); |
111 |
|
|
112 |
14400 |
v->hdl = dlhdl; |
113 |
|
|
114 |
14400 |
bprintf(buf, "Vmod_%s_Data", nm); |
115 |
14400 |
d = dlsym(v->hdl, buf); |
116 |
28800 |
if (d == NULL || |
117 |
14400 |
d->file_id == NULL || |
118 |
14400 |
strcmp(d->file_id, file_id)) { |
119 |
0 |
VSB_printf(ctx->msg, "Loading vmod %s from %s (%s):\n", |
120 |
0 |
nm, backup, path); |
121 |
0 |
VSB_cat(ctx->msg, |
122 |
|
"This is no longer the same file seen by" |
123 |
|
" the VCL-compiler.\n"); |
124 |
0 |
(void)dlclose(v->hdl); |
125 |
0 |
FREE_OBJ(v); |
126 |
0 |
return (1); |
127 |
|
} |
128 |
28800 |
if (vmod_abi_mismatch(d) || |
129 |
14400 |
d->name == NULL || |
130 |
14400 |
strcmp(d->name, nm) || |
131 |
14400 |
d->func == NULL || |
132 |
14400 |
d->func_len <= 0 || |
133 |
14400 |
d->proto != NULL || |
134 |
14400 |
d->json == NULL) { |
135 |
0 |
VSB_printf(ctx->msg, "Loading vmod %s from %s (%s):\n", |
136 |
0 |
nm, backup, path); |
137 |
0 |
VSB_cat(ctx->msg, "VMOD data is mangled.\n"); |
138 |
0 |
(void)dlclose(v->hdl); |
139 |
0 |
FREE_OBJ(v); |
140 |
0 |
return (1); |
141 |
|
} |
142 |
|
|
143 |
14400 |
v->nbr = nbr; |
144 |
14400 |
v->funclen = d->func_len; |
145 |
14400 |
v->funcs = d->func; |
146 |
14400 |
v->abi = d->abi; |
147 |
14400 |
v->vrt_major = d->vrt_major; |
148 |
14400 |
v->vrt_minor = d->vrt_minor; |
149 |
|
|
150 |
14400 |
REPLACE(v->nm, nm); |
151 |
14400 |
REPLACE(v->path, path); |
152 |
14400 |
REPLACE(v->backup, backup); |
153 |
|
|
154 |
14400 |
VSC_C_main->vmods++; |
155 |
14400 |
VTAILQ_INSERT_TAIL(&vmods, v, list); |
156 |
14400 |
} |
157 |
|
|
158 |
19880 |
assert(len == v->funclen); |
159 |
19880 |
memcpy(ptr, v->funcs, v->funclen); |
160 |
19880 |
v->ref++; |
161 |
|
|
162 |
19880 |
*hdl = v; |
163 |
19880 |
return (0); |
164 |
19880 |
} |
165 |
|
|
166 |
|
void |
167 |
3155 |
VPI_Vmod_Unload(VRT_CTX, struct vmod **hdl) |
168 |
|
{ |
169 |
|
struct vmod *v; |
170 |
|
|
171 |
3155 |
ASSERT_CLI(); |
172 |
|
|
173 |
3155 |
TAKE_OBJ_NOTNULL(v, hdl, VMOD_MAGIC); |
174 |
|
|
175 |
3155 |
VCL_TaskLeave(ctx, cli_task_privs); |
176 |
3155 |
VCL_TaskEnter(cli_task_privs); |
177 |
|
|
178 |
|
#ifndef DONT_DLCLOSE_VMODS |
179 |
|
/* |
180 |
|
* atexit(3) handlers are not called during dlclose(3). We don't |
181 |
|
* normally use them, but we do when running GCOV. This option |
182 |
|
* enables us to do that. |
183 |
|
*/ |
184 |
|
AZ(dlclose(v->hdl)); |
185 |
|
#endif |
186 |
3155 |
if (--v->ref != 0) |
187 |
2240 |
return; |
188 |
915 |
free(v->nm); |
189 |
915 |
free(v->path); |
190 |
915 |
free(v->backup); |
191 |
915 |
VTAILQ_REMOVE(&vmods, v, list); |
192 |
915 |
VSC_C_main->vmods--; |
193 |
915 |
FREE_OBJ(v); |
194 |
3155 |
} |
195 |
|
|
196 |
|
void |
197 |
516 |
VMOD_Panic(struct vsb *vsb) |
198 |
|
{ |
199 |
|
struct vmod *v; |
200 |
|
|
201 |
516 |
VSB_cat(vsb, "vmods = {\n"); |
202 |
516 |
VSB_indent(vsb, 2); |
203 |
916 |
VTAILQ_FOREACH(v, &vmods, list) |
204 |
800 |
VSB_printf(vsb, "%s = {%p, %s, %u.%u},\n", |
205 |
400 |
v->nm, v, v->abi, v->vrt_major, v->vrt_minor); |
206 |
516 |
VSB_indent(vsb, -2); |
207 |
516 |
VSB_cat(vsb, "},\n"); |
208 |
516 |
} |
209 |
|
|
210 |
|
/*---------------------------------------------------------------------*/ |
211 |
|
|
212 |
|
static void v_matchproto_(cli_func_t) |
213 |
160 |
ccf_debug_vmod(struct cli *cli, const char * const *av, void *priv) |
214 |
|
{ |
215 |
|
struct vmod *v; |
216 |
|
|
217 |
160 |
(void)av; |
218 |
160 |
(void)priv; |
219 |
160 |
ASSERT_CLI(); |
220 |
320 |
VTAILQ_FOREACH(v, &vmods, list) |
221 |
160 |
VCLI_Out(cli, "%5d %s (%s)\n", v->ref, v->nm, v->path); |
222 |
160 |
} |
223 |
|
|
224 |
|
static struct cli_proto vcl_cmds[] = { |
225 |
|
{ CLICMD_DEBUG_VMOD, "d", ccf_debug_vmod }, |
226 |
|
{ NULL } |
227 |
|
}; |
228 |
|
|
229 |
|
void |
230 |
36590 |
VMOD_Init(void) |
231 |
|
{ |
232 |
|
|
233 |
36590 |
CLI_AddFuncs(vcl_cmds); |
234 |
36590 |
} |