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