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