varnish-cache/bin/varnishtest/vtc_client.c
1
/*-
2
 * Copyright (c) 2008-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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 <sys/socket.h>
32
33
#include <errno.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
38
#include "vtc.h"
39
40
#include "vsa.h"
41
#include "vss.h"
42
#include "vtcp.h"
43
44
struct client {
45
        unsigned                magic;
46
#define CLIENT_MAGIC            0x6242397c
47
        char                    *name;
48
        struct vtclog           *vl;
49
        VTAILQ_ENTRY(client)    list;
50
51
        char                    *spec;
52
53
        char                    connect[256];
54
55
        char                    *proxy_spec;
56
        int                     proxy_version;
57
58
        unsigned                repeat;
59
60
        unsigned                running;
61
        pthread_t               tp;
62
};
63
64
static VTAILQ_HEAD(, client)    clients =
65
    VTAILQ_HEAD_INITIALIZER(clients);
66
67
/**********************************************************************
68
 * Send the proxy header
69
 */
70
71
static int v_matchproto_(vss_resolved_f)
72 18
proxy_cb(void *priv, const struct suckaddr *sa)
73
{
74 18
        struct suckaddr **addr = priv;
75 18
        *addr = VSA_Clone(sa);
76 18
        return (1);
77
}
78
79
static void
80 9
client_proxy(struct vtclog *vl, int fd, int version, const char *spec)
81
{
82
        struct suckaddr *sac, *sas;
83
        const char *err;
84
        char *p, *p2;
85
        int error;
86
87 9
        p = strdup(spec);
88 9
        AN(p);
89 9
        p2 = strchr(p, ' ');
90 9
        AN(p2);
91 9
        *p2++ = '\0';
92
93 9
        error = VSS_resolver(p, NULL, proxy_cb, &sac, &err);
94 9
        if (err != NULL)
95 0
                vtc_fatal(vl, "Could not resolve client address: %s", err);
96 9
        assert(error == 1);
97 9
        error = VSS_resolver(p2, NULL, proxy_cb, &sas, &err);
98 9
        if (err != NULL)
99 0
                vtc_fatal(vl, "Could not resolve server address: %s", err);
100 9
        assert(error == 1);
101 9
        if (vtc_send_proxy(fd, version, sac, sas))
102 0
                vtc_fatal(vl, "Write failed: %s", strerror(errno));
103 9
        free(p);
104 9
        free(sac);
105 9
        free(sas);
106 9
}
107
108
/**********************************************************************
109
 * Client thread
110
 */
111
112
static void *
113 1063
client_thread(void *priv)
114
{
115
        struct client *c;
116
        struct vtclog *vl;
117
        int fd;
118
        unsigned u;
119
        struct vsb *vsb;
120
        char *p;
121
        char mabuf[32], mpbuf[32];
122
        const char *err;
123
124 1063
        CAST_OBJ_NOTNULL(c, priv, CLIENT_MAGIC);
125 1063
        AN(*c->connect);
126
127 1063
        vl = vtc_logopen(c->name);
128
129 1063
        p = strdup(c->connect);
130 1063
        AN(p);
131 1063
        vsb = macro_expand(vl, p);
132 1063
        AN(vsb);
133
134 1063
        if (c->repeat == 0)
135 662
                c->repeat = 1;
136 1063
        if (c->repeat != 1)
137 5
                vtc_log(vl, 2, "Started (%u iterations)", c->repeat);
138 2201
        for (u = 0; u < c->repeat; u++) {
139 1138
                vtc_log(vl, 3, "Connect to %s", VSB_data(vsb));
140 1138
                fd = VTCP_open(VSB_data(vsb), NULL, 10., &err);
141 1138
                if (fd < 0)
142 0
                        vtc_fatal(c->vl, "Failed to open %s: %s",
143
                            VSB_data(vsb), err);
144 1138
                assert(fd >= 0);
145
                /* VTCP_blocking does its own checks, trust it */
146 1138
                (void)VTCP_blocking(fd);
147 1138
                VTCP_myname(fd, mabuf, sizeof mabuf, mpbuf, sizeof mpbuf);
148 1138
                vtc_log(vl, 3, "connected fd %d from %s %s to %s",
149
                    fd, mabuf, mpbuf, VSB_data(vsb));
150 1138
                if (c->proxy_spec != NULL)
151 9
                        client_proxy(vl, fd, c->proxy_version, c->proxy_spec);
152 1138
                fd = http_process(vl, c->spec, fd, NULL);
153 1138
                vtc_log(vl, 3, "closing fd %d", fd);
154 1138
                VTCP_close(&fd);
155
        }
156 1063
        vtc_log(vl, 2, "Ending");
157 1063
        VSB_destroy(&vsb);
158 1063
        free(p);
159 1063
        return (NULL);
160
}
161
162
/**********************************************************************
163
 * Allocate and initialize a client
164
 */
165
166
static struct client *
167 665
client_new(const char *name)
168
{
169
        struct client *c;
170
171 665
        ALLOC_OBJ(c, CLIENT_MAGIC);
172 665
        AN(c);
173 665
        REPLACE(c->name, name);
174 665
        c->vl = vtc_logopen(name);
175 665
        AN(c->vl);
176
177 665
        bprintf(c->connect, "%s", "${v1_sock}");
178 665
        VTAILQ_INSERT_TAIL(&clients, c, list);
179 665
        return (c);
180
}
181
182
/**********************************************************************
183
 * Clean up client
184
 */
185
186
static void
187 665
client_delete(struct client *c)
188
{
189
190 665
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
191 665
        vtc_logclose(c->vl);
192 665
        free(c->spec);
193 665
        free(c->name);
194 665
        free(c->proxy_spec);
195
        /* XXX: MEMLEAK (?)*/
196 665
        FREE_OBJ(c);
197 665
}
198
199
/**********************************************************************
200
 * Start the client thread
201
 */
202
203
static void
204 1063
client_start(struct client *c)
205
{
206
207 1063
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
208 1063
        vtc_log(c->vl, 2, "Starting client");
209 1063
        AZ(pthread_create(&c->tp, NULL, client_thread, c));
210 1063
        c->running = 1;
211 1063
}
212
213
/**********************************************************************
214
 * Wait for client thread to stop
215
 */
216
217
static void
218 1063
client_wait(struct client *c)
219
{
220
        void *res;
221
222 1063
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
223 1063
        vtc_log(c->vl, 2, "Waiting for client");
224 1063
        AZ(pthread_join(c->tp, &res));
225 1063
        if (res != NULL)
226 0
                vtc_fatal(c->vl, "Client returned \"%s\"", (char *)res);
227 1063
        c->tp = 0;
228 1063
        c->running = 0;
229 1063
}
230
231
/**********************************************************************
232
 * Run the client thread
233
 */
234
235
static void
236 1000
client_run(struct client *c)
237
{
238
239 1000
        client_start(c);
240 1000
        client_wait(c);
241 1000
}
242
243
244
/**********************************************************************
245
 * Client command dispatch
246
 */
247
248
void
249 1848
cmd_client(CMD_ARGS)
250
{
251
        struct client *c, *c2;
252
253
        (void)priv;
254
        (void)cmd;
255
256 1848
        if (av == NULL) {
257
                /* Reset and free */
258 1343
                VTAILQ_FOREACH_SAFE(c, &clients, list, c2) {
259 665
                        VTAILQ_REMOVE(&clients, c, list);
260 665
                        if (c->tp != 0)
261 14
                                client_wait(c);
262 665
                        client_delete(c);
263
                }
264 2526
                return;
265
        }
266
267 1170
        AZ(strcmp(av[0], "client"));
268 1170
        av++;
269
270 1170
        VTC_CHECK_NAME(vl, av[0], "Client", 'c');
271 1333
        VTAILQ_FOREACH(c, &clients, list)
272 668
                if (!strcmp(c->name, av[0]))
273 505
                        break;
274 1170
        if (c == NULL)
275 665
                c = client_new(av[0]);
276 1170
        av++;
277
278 3402
        for (; *av != NULL; av++) {
279 2232
                if (vtc_error)
280 0
                        break;
281
282 2232
                if (!strcmp(*av, "-wait")) {
283 48
                        client_wait(c);
284 48
                        continue;
285
                }
286
287
                /* Don't muck about with a running client */
288 2184
                if (c->running)
289 1
                        client_wait(c);
290
291 2184
                if (!strcmp(*av, "-connect")) {
292 68
                        bprintf(c->connect, "%s", av[1]);
293 68
                        av++;
294 68
                        continue;
295
                }
296 2116
                if (!strcmp(*av, "-proxy1")) {
297 7
                        REPLACE(c->proxy_spec, av[1]);
298 7
                        c->proxy_version = 1;
299 7
                        av++;
300 7
                        continue;
301
                }
302 2109
                if (!strcmp(*av, "-proxy2")) {
303 2
                        REPLACE(c->proxy_spec, av[1]);
304 2
                        c->proxy_version = 2;
305 2
                        av++;
306 2
                        continue;
307
                }
308 2107
                if (!strcmp(*av, "-repeat")) {
309 3
                        c->repeat = atoi(av[1]);
310 3
                        av++;
311 3
                        continue;
312
                }
313 2104
                if (!strcmp(*av, "-start")) {
314 63
                        client_start(c);
315 63
                        continue;
316
                }
317 2041
                if (!strcmp(*av, "-run")) {
318 1000
                        client_run(c);
319 1000
                        continue;
320
                }
321 1041
                if (**av == '-')
322 0
                        vtc_fatal(c->vl, "Unknown client argument: %s", *av);
323 1041
                REPLACE(c->spec, *av);
324
        }
325
}