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
#include <sys/un.h>
33
34
#include <errno.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <poll.h>
39
#include <unistd.h>
40
41
#include "vtc.h"
42
43
#include "vsa.h"
44
#include "vss.h"
45
#include "vtcp.h"
46
#include "vus.h"
47
48
struct client {
49
        unsigned                magic;
50
#define CLIENT_MAGIC            0x6242397c
51
        char                    *name;
52
        struct vtclog           *vl;
53
        VTAILQ_ENTRY(client)    list;
54
55
        char                    *spec;
56
57
        char                    connect[256];
58
59
        char                    *proxy_spec;
60
        int                     proxy_version;
61
62
        unsigned                repeat;
63
64
        unsigned                running;
65
        pthread_t               tp;
66
};
67
68
static VTAILQ_HEAD(, client)    clients =
69
    VTAILQ_HEAD_INITIALIZER(clients);
70
71
/**********************************************************************
72
 * Send the proxy header
73
 */
74
75
static int v_matchproto_(vss_resolved_f)
76 20
proxy_cb(void *priv, const struct suckaddr *sa)
77
{
78 20
        struct suckaddr **addr = priv;
79 20
        *addr = VSA_Clone(sa);
80 20
        return (1);
81
}
82
83
static void
84 10
client_proxy(struct vtclog *vl, int fd, int version, const char *spec)
85
{
86
        struct suckaddr *sac, *sas;
87
        const char *err;
88
        char *p, *p2;
89
        int error;
90
91 10
        p = strdup(spec);
92 10
        AN(p);
93 10
        p2 = strchr(p, ' ');
94 10
        AN(p2);
95 10
        *p2++ = '\0';
96
97 10
        error = VSS_resolver(p, NULL, proxy_cb, &sac, &err);
98 10
        if (err != NULL)
99 0
                vtc_fatal(vl, "Could not resolve client address: %s", err);
100 10
        assert(error == 1);
101 10
        error = VSS_resolver(p2, NULL, proxy_cb, &sas, &err);
102 10
        if (err != NULL)
103 0
                vtc_fatal(vl, "Could not resolve server address: %s", err);
104 10
        assert(error == 1);
105 10
        if (vtc_send_proxy(fd, version, sac, sas))
106 0
                vtc_fatal(vl, "Write failed: %s", strerror(errno));
107 10
        free(p);
108 10
        free(sac);
109 10
        free(sas);
110 10
}
111
112
/**********************************************************************
113
 * Socket connect.
114
 */
115
116
static int
117 1490
client_tcp_connect(struct vtclog *vl, const char *addr, double tmo,
118
                   const char **errp)
119
{
120
        int fd;
121
        char mabuf[32], mpbuf[32];
122
123 1490
        fd = VTCP_open(addr, NULL, tmo, errp);
124 1490
        if (fd < 0)
125 0
                return fd;
126 1490
        VTCP_myname(fd, mabuf, sizeof mabuf, mpbuf, sizeof mpbuf);
127 1490
        vtc_log(vl, 3, "connected fd %d from %s %s to %s", fd, mabuf, mpbuf,
128
                addr);
129 1490
        return fd;
130
}
131
132
/* cf. VTCP_Open() */
133
static int v_matchproto_(vus_resolved_f)
134 40
uds_open(void *priv, const struct sockaddr_un *uds)
135
{
136
        double *p;
137
        int s, i, tmo;
138
        struct pollfd fds[1];
139 40
        socklen_t sl = sizeof(*uds);
140
141 40
        AN(priv);
142 40
        AN(uds);
143 40
        p = priv;
144 40
        assert(*p > 0.);
145 40
        tmo = (int)(*p * 1e3);
146
147 40
        s = socket(uds->sun_family, SOCK_STREAM, 0);
148 40
        if (s < 0)
149 0
                return (s);
150
151 40
        (void) VTCP_nonblocking(s);
152 40
        i = connect(s, (const void*)uds, sl);
153 40
        if (i == 0)
154 40
                return(s);
155 0
        if (errno != EINPROGRESS) {
156 0
                closefd(&s);
157 0
                return (-1);
158
        }
159
160 0
        fds[0].fd = s;
161 0
        fds[0].events = POLLWRNORM;
162 0
        fds[0].revents = 0;
163 0
        i = poll(fds, 1, tmo);
164
165 0
        if (i == 0) {
166 0
                closefd(&s);
167 0
                errno = ETIMEDOUT;
168 0
                return (-1);
169
        }
170
171 0
        return (VTCP_connected(s));
172
}
173
174
static int
175 40
client_uds_connect(struct vtclog *vl, const char *path, double tmo,
176
                   const char **errp)
177
{
178
        int fd;
179
180 40
        assert(tmo >= 0);
181
182 40
        errno = 0;
183 40
        fd = VUS_resolver(path, uds_open, &tmo, errp);
184 40
        if (fd < 0) {
185 0
                *errp = strerror(errno);
186 0
                return fd;
187
        }
188 40
        vtc_log(vl, 3, "connected fd %d to %s", fd, path);
189 40
        return fd;
190
}
191
192
/**********************************************************************
193
 * Client thread
194
 */
195
196
static void *
197 1257
client_thread(void *priv)
198
{
199
        struct client *c;
200
        struct vtclog *vl;
201
        int fd;
202
        unsigned u;
203
        struct vsb *vsb;
204
        const char *err;
205
206 1257
        CAST_OBJ_NOTNULL(c, priv, CLIENT_MAGIC);
207 1257
        AN(*c->connect);
208
209 1257
        vl = vtc_logopen(c->name);
210 1257
        pthread_cleanup_push(vtc_logclose, vl);
211
212 1257
        vsb = macro_expand(vl, c->connect);
213 1257
        AN(vsb);
214
215 1257
        if (c->repeat == 0)
216 782
                c->repeat = 1;
217 1257
        if (c->repeat != 1)
218 7
                vtc_log(vl, 2, "Started (%u iterations)", c->repeat);
219 2787
        for (u = 0; u < c->repeat; u++) {
220 1530
                char *addr = VSB_data(vsb);
221
222 1530
                vtc_log(vl, 3, "Connect to %s", addr);
223 1530
                if (*addr == '/')
224 40
                        fd = client_uds_connect(vl, addr, 10., &err);
225
                else
226 1490
                        fd = client_tcp_connect(vl, VSB_data(vsb), 10., &err);
227 1530
                if (fd < 0)
228 0
                        vtc_fatal(c->vl, "Failed to open %s: %s",
229
                            VSB_data(vsb), err);
230
                /* VTCP_blocking does its own checks, trust it */
231 1530
                (void)VTCP_blocking(fd);
232 1530
                if (c->proxy_spec != NULL)
233 10
                        client_proxy(vl, fd, c->proxy_version, c->proxy_spec);
234 1530
                fd = http_process(vl, c->spec, fd, NULL, addr);
235 1530
                vtc_log(vl, 3, "closing fd %d", fd);
236 1530
                VTCP_close(&fd);
237
        }
238 1257
        vtc_log(vl, 2, "Ending");
239 1257
        VSB_destroy(&vsb);
240 1257
        pthread_cleanup_pop(0);
241 1257
        vtc_logclose(vl);
242 1257
        return (NULL);
243
}
244
245
/**********************************************************************
246
 * Allocate and initialize a client
247
 */
248
249
static struct client *
250 787
client_new(const char *name)
251
{
252
        struct client *c;
253
254 787
        ALLOC_OBJ(c, CLIENT_MAGIC);
255 787
        AN(c);
256 787
        REPLACE(c->name, name);
257 787
        c->vl = vtc_logopen(name);
258 787
        AN(c->vl);
259
260 787
        bprintf(c->connect, "%s", "${v1_sock}");
261 787
        VTAILQ_INSERT_TAIL(&clients, c, list);
262 787
        return (c);
263
}
264
265
/**********************************************************************
266
 * Clean up client
267
 */
268
269
static void
270 787
client_delete(struct client *c)
271
{
272
273 787
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
274 787
        vtc_logclose(c->vl);
275 787
        free(c->spec);
276 787
        free(c->name);
277 787
        free(c->proxy_spec);
278
        /* XXX: MEMLEAK (?)*/
279 787
        FREE_OBJ(c);
280 787
}
281
282
/**********************************************************************
283
 * Start the client thread
284
 */
285
286
static void
287 1257
client_start(struct client *c)
288
{
289
290 1257
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
291 1257
        vtc_log(c->vl, 2, "Starting client");
292 1257
        AZ(pthread_create(&c->tp, NULL, client_thread, c));
293 1257
        c->running = 1;
294 1257
}
295
296
/**********************************************************************
297
 * Wait for client thread to stop
298
 */
299
300
static void
301 1257
client_wait(struct client *c)
302
{
303
        void *res;
304
305 1257
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
306 1257
        vtc_log(c->vl, 2, "Waiting for client");
307 1257
        AZ(pthread_join(c->tp, &res));
308 1257
        if (res != NULL)
309 0
                vtc_fatal(c->vl, "Client returned \"%s\"", (char *)res);
310 1257
        c->tp = 0;
311 1257
        c->running = 0;
312 1257
}
313
314
/**********************************************************************
315
 * Run the client thread
316
 */
317
318
static void
319 1166
client_run(struct client *c)
320
{
321
322 1166
        client_start(c);
323 1166
        client_wait(c);
324 1166
}
325
326
327
/**********************************************************************
328
 * Client command dispatch
329
 */
330
331
void
332 2172
cmd_client(CMD_ARGS)
333
{
334
        struct client *c, *c2;
335
336
        (void)priv;
337
        (void)cmd;
338
339 2172
        if (av == NULL) {
340
                /* Reset and free */
341 1550
                VTAILQ_FOREACH_SAFE(c, &clients, list, c2) {
342 787
                        VTAILQ_REMOVE(&clients, c, list);
343 787
                        if (c->tp != 0)
344 14
                                client_wait(c);
345 787
                        client_delete(c);
346
                }
347 763
                return;
348
        }
349
350 1409
        AZ(strcmp(av[0], "client"));
351 1409
        av++;
352
353 1409
        VTC_CHECK_NAME(vl, av[0], "Client", 'c');
354 1732
        VTAILQ_FOREACH(c, &clients, list)
355 945
                if (!strcmp(c->name, av[0]))
356 622
                        break;
357 1409
        if (c == NULL)
358 787
                c = client_new(av[0]);
359 1409
        av++;
360
361 4096
        for (; *av != NULL; av++) {
362 2687
                if (vtc_error)
363 0
                        break;
364
365 2687
                if (!strcmp(*av, "-wait")) {
366 76
                        client_wait(c);
367 76
                        continue;
368
                }
369
370
                /* Don't muck about with a running client */
371 2611
                if (c->running)
372 1
                        client_wait(c);
373
374 2611
                if (!strcmp(*av, "-connect")) {
375 115
                        bprintf(c->connect, "%s", av[1]);
376 115
                        av++;
377 115
                        continue;
378
                }
379 2496
                if (!strcmp(*av, "-proxy1")) {
380 8
                        REPLACE(c->proxy_spec, av[1]);
381 8
                        c->proxy_version = 1;
382 8
                        av++;
383 8
                        continue;
384
                }
385 2488
                if (!strcmp(*av, "-proxy2")) {
386 2
                        REPLACE(c->proxy_spec, av[1]);
387 2
                        c->proxy_version = 2;
388 2
                        av++;
389 2
                        continue;
390
                }
391 2486
                if (!strcmp(*av, "-repeat")) {
392 5
                        c->repeat = atoi(av[1]);
393 5
                        av++;
394 5
                        continue;
395
                }
396 2481
                if (!strcmp(*av, "-start")) {
397 91
                        client_start(c);
398 91
                        continue;
399
                }
400 2390
                if (!strcmp(*av, "-run")) {
401 1166
                        client_run(c);
402 1166
                        continue;
403
                }
404 1224
                if (**av == '-')
405 0
                        vtc_fatal(c->vl, "Unknown client argument: %s", *av);
406 1224
                REPLACE(c->spec, *av);
407
        }
408
}