varnish-cache/bin/varnishtest/vtc_client.c
0
/*-
1
 * Copyright (c) 2008-2011 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <sys/socket.h>
33
#include <sys/un.h>
34
35
#include <netdb.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <poll.h>
40
#include <unistd.h>
41
42
#include "vtc.h"
43
44
#include "vsa.h"
45
#include "vss.h"
46
#include "vtcp.h"
47
#include "vus.h"
48
49
struct client {
50
        unsigned                magic;
51
#define CLIENT_MAGIC            0x6242397c
52
        char                    *name;
53
        struct vtclog           *vl;
54
        VTAILQ_ENTRY(client)    list;
55
        struct vtc_sess         *vsp;
56
57
        char                    *spec;
58
59
        char                    connect[256];
60
        char                    *addr;
61
62
        char                    *proxy_spec;
63
        int                     proxy_version;
64
65
        unsigned                running;
66
        pthread_t               tp;
67
};
68
69
static VTAILQ_HEAD(, client)    clients = VTAILQ_HEAD_INITIALIZER(clients);
70
71
/**********************************************************************
72
 * Send the proxy header
73
 */
74
75
static void
76 480
client_proxy(struct vtclog *vl, int fd, int version, const char *speca)
77
{
78
        const struct suckaddr *sac, *sas;
79
        char *spec, *save, *p;
80
        struct vsb *tlv;
81
82 480
        spec = strdup(speca);
83 480
        AN(spec);
84 480
        save = NULL;
85
86 480
        p = strtok_r(spec, " ", &save);
87 480
        AN(p);
88 480
        sac = VSS_ResolveOne(NULL, p, NULL, 0, SOCK_STREAM, AI_PASSIVE);
89 480
        if (sac == NULL)
90 0
                vtc_fatal(vl, "Could not resolve client address");
91
92 480
        p = strtok_r(NULL, " ", &save);
93 480
        AN(p);
94 480
        sas = VSS_ResolveOne(NULL, p, NULL, 0, SOCK_STREAM, AI_PASSIVE);
95 480
        if (sas == NULL)
96 0
                vtc_fatal(vl, "Could not resolve client address");
97
98 480
        tlv = VSB_new_auto();
99 560
        while ((p = strtok_r(NULL, " ", &save)) != NULL)
100 80
                vtc_proxy_tlv(vl, tlv, p);
101
102 480
        free(spec);
103
104 480
        AZ(VSB_finish(tlv));
105 480
        if (vtc_send_proxy(fd, version, sac, sas, tlv))
106 0
                vtc_fatal(vl, "Write failed: %s", strerror(errno));
107 480
        VSA_free(&sac);
108 480
        VSA_free(&sas);
109 480
}
110
111
/**********************************************************************
112
 * Socket connect.
113
 */
114
115
static int
116 79237
client_tcp_connect(struct vtclog *vl, const char *addr, double tmo,
117
                   const char **errp)
118
{
119
        int fd;
120
        char mabuf[VTCP_ADDRBUFSIZE], mpbuf[VTCP_PORTBUFSIZE];
121
122 79237
        AN(addr);
123 79237
        AN(errp);
124 79237
        fd = VTCP_open(addr, NULL, tmo, errp);
125 79237
        if (fd < 0)
126 0
                return (fd);
127 79237
        VTCP_myname(fd, mabuf, sizeof mabuf, mpbuf, sizeof mpbuf);
128 158474
        vtc_log(vl, 3, "connected fd %d from %s %s to %s", fd, mabuf, mpbuf,
129 79237
                addr);
130 79237
        return (fd);
131 79237
}
132
133
/* cf. VTCP_Open() */
134
static int v_matchproto_(vus_resolved_f)
135 10080
uds_open(void *priv, const struct sockaddr_un *uds)
136
{
137
        double *p;
138
        int s, i, tmo;
139
        struct pollfd fds[1];
140
        socklen_t sl;
141
142 10080
        sl = VUS_socklen(uds);
143
144 10080
        AN(priv);
145 10080
        AN(uds);
146 10080
        p = priv;
147 10080
        assert(*p > 0.);
148 10080
        tmo = (int)(*p * 1e3);
149
150 10080
        s = socket(uds->sun_family, SOCK_STREAM, 0);
151 10080
        if (s < 0)
152 0
                return (s);
153
154 10080
        VTCP_nonblocking(s);
155 10080
        i = connect(s, (const void*)uds, sl);
156 10080
        if (i == 0)
157 10080
                return (s);
158 0
        if (errno != EINPROGRESS) {
159 0
                closefd(&s);
160 0
                return (-1);
161
        }
162
163 0
        fds[0].fd = s;
164 0
        fds[0].events = POLLWRNORM;
165 0
        fds[0].revents = 0;
166 0
        i = poll(fds, 1, tmo);
167
168 0
        if (i == 0) {
169 0
                closefd(&s);
170 0
                errno = ETIMEDOUT;
171 0
                return (-1);
172
        }
173
174 0
        return (VTCP_connected(s));
175 10080
}
176
177
static int
178 10080
client_uds_connect(struct vtclog *vl, const char *path, double tmo,
179
                   const char **errp)
180
{
181
        int fd;
182
183 10080
        assert(tmo >= 0);
184
185 10080
        errno = 0;
186 10080
        fd = VUS_resolver(path, uds_open, &tmo, errp);
187 10080
        if (fd < 0) {
188 0
                *errp = strerror(errno);
189 0
                return (fd);
190
        }
191 10080
        vtc_log(vl, 3, "connected fd %d to %s", fd, path);
192 10080
        return (fd);
193 10080
}
194
195
static int
196 89320
client_connect(struct vtclog *vl, struct client *c)
197
{
198
        const char *err;
199
        int fd;
200
201 89320
        vtc_log(vl, 3, "Connect to %s", c->addr);
202 89320
        if (VUS_is(c->addr))
203 10080
                fd = client_uds_connect(vl, c->addr, 10., &err);
204
        else
205 79240
                fd = client_tcp_connect(vl, c->addr, 10., &err);
206 89320
        if (fd < 0)
207 0
                vtc_fatal(c->vl, "Failed to open %s: %s",
208 0
                    c->addr, err);
209
        /* VTCP_blocking does its own checks, trust it */
210 89320
        VTCP_blocking(fd);
211 89320
        if (c->proxy_spec != NULL)
212 480
                client_proxy(vl, fd, c->proxy_version, c->proxy_spec);
213 89320
        return (fd);
214
}
215
216
/**********************************************************************
217
 * Client thread
218
 */
219
220
static int
221 89320
client_conn(void *priv, struct vtclog *vl)
222
{
223
        struct client *c;
224
225 89320
        CAST_OBJ_NOTNULL(c, priv, CLIENT_MAGIC);
226 89320
        return (client_connect(vl, c));
227
}
228
229
static void
230 89300
client_disc(void *priv, struct vtclog *vl, int *fdp)
231
{
232 89300
        (void)priv;
233 89300
        vtc_log(vl, 3, "closing fd %d", *fdp);
234 89300
        VTCP_close(fdp);
235 89300
}
236
237
/**********************************************************************
238
 * Allocate and initialize a client
239
 */
240
241
static struct client *
242 46080
client_new(const char *name)
243
{
244
        struct client *c;
245
246 46080
        ALLOC_OBJ(c, CLIENT_MAGIC);
247 46080
        AN(c);
248 46080
        REPLACE(c->name, name);
249 46080
        c->vl = vtc_logopen("%s", name);
250 46080
        AN(c->vl);
251 46080
        c->vsp = Sess_New(c->vl, name);
252 46080
        AN(c->vsp);
253
254 46080
        bprintf(c->connect, "%s", "${v1_sock}");
255 46080
        VTAILQ_INSERT_TAIL(&clients, c, list);
256 46080
        return (c);
257
}
258
259
/**********************************************************************
260
 * Clean up client
261
 */
262
263
static void
264 46080
client_delete(struct client *c)
265
{
266
267 46080
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
268 46080
        Sess_Destroy(&c->vsp);
269 46080
        vtc_logclose(c->vl);
270 46080
        free(c->spec);
271 46080
        free(c->name);
272 46080
        free(c->addr);
273 46080
        free(c->proxy_spec);
274
        /* XXX: MEMLEAK (?)*/
275 46080
        FREE_OBJ(c);
276 46080
}
277
278
/**********************************************************************
279
 * Start the client thread
280
 */
281
282
static void
283 71040
client_start(struct client *c)
284
{
285
        struct vsb *vsb;
286
287 71040
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
288 71040
        vtc_log(c->vl, 2, "Starting client");
289 71040
        c->running = 1;
290 71040
        vsb = macro_expand(c->vl, c->connect);
291 71040
        AN(vsb);
292 71040
        REPLACE(c->addr, VSB_data(vsb));
293 71040
        VSB_destroy(&vsb);
294 71040
        c->tp = Sess_Start_Thread(
295 71040
            c,
296 71040
            c->vsp,
297
            client_conn,
298
            client_disc,
299 71040
            c->addr,
300
            NULL,
301 71040
            c->spec
302
        );
303 71040
}
304
305
/**********************************************************************
306
 * Wait for client thread to stop
307
 */
308
309
static void
310 71040
client_wait(struct client *c)
311
{
312
        void *res;
313
314 71040
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
315 71040
        vtc_log(c->vl, 2, "Waiting for client");
316 71040
        PTOK(pthread_join(c->tp, &res));
317 71040
        if (res != NULL)
318 0
                vtc_fatal(c->vl, "Client returned \"%s\"", (char *)res);
319 71040
        c->tp = 0;
320 71040
        c->running = 0;
321 71040
}
322
323
/**********************************************************************
324
 * Run the client thread
325
 */
326
327
static void
328 63160
client_run(struct client *c)
329
{
330
331 63160
        client_start(c);
332 63160
        client_wait(c);
333 63160
}
334
335
336
/**********************************************************************
337
 * Client command dispatch
338
 */
339
340
void
341 121960
cmd_client(CMD_ARGS)
342
{
343
        struct client *c, *c2;
344
345 121960
        (void)priv;
346
347 121960
        if (av == NULL) {
348
                /* Reset and free */
349 86640
                VTAILQ_FOREACH_SAFE(c, &clients, list, c2) {
350 46080
                        VTAILQ_REMOVE(&clients, c, list);
351 46080
                        if (c->tp != 0)
352 840
                                client_wait(c);
353 46080
                        client_delete(c);
354 46080
                }
355 40560
                return;
356
        }
357
358 81400
        AZ(strcmp(av[0], "client"));
359 81400
        av++;
360
361 81400
        VTC_CHECK_NAME(vl, av[0], "Client", 'c');
362 118360
        VTAILQ_FOREACH(c, &clients, list)
363 72280
                if (!strcmp(c->name, av[0]))
364 35320
                        break;
365 81400
        if (c == NULL)
366 46080
                c = client_new(av[0]);
367 81400
        av++;
368
369 236440
        for (; *av != NULL; av++) {
370 155040
                if (vtc_error)
371 0
                        break;
372
373 155040
                if (!strcmp(*av, "-wait")) {
374 7000
                        client_wait(c);
375 7000
                        continue;
376
                }
377
378
                /* Don't muck about with a running client */
379 148040
                if (c->running)
380 40
                        client_wait(c);
381
382 148040
                AZ(c->running);
383 148040
                if (Sess_GetOpt(c->vsp, &av))
384 1320
                        continue;
385
386 146720
                if (!strcmp(*av, "-connect")) {
387 5960
                        bprintf(c->connect, "%s", av[1]);
388 5960
                        av++;
389 5960
                        continue;
390
                }
391 140760
                if (!strcmp(*av, "-proxy1")) {
392 320
                        REPLACE(c->proxy_spec, av[1]);
393 320
                        c->proxy_version = 1;
394 320
                        av++;
395 320
                        continue;
396
                }
397 140440
                if (!strcmp(*av, "-proxy2")) {
398 160
                        REPLACE(c->proxy_spec, av[1]);
399 160
                        c->proxy_version = 2;
400 160
                        av++;
401 160
                        continue;
402
                }
403 140280
                if (!strcmp(*av, "-start")) {
404 7880
                        client_start(c);
405 7880
                        continue;
406
                }
407 132400
                if (!strcmp(*av, "-run")) {
408 63160
                        client_run(c);
409 63160
                        continue;
410
                }
411 69240
                if (**av == '-')
412 0
                        vtc_fatal(c->vl, "Unknown client argument: %s", *av);
413 69240
                REPLACE(c->spec, *av);
414 69240
        }
415 121960
}