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 30
client_proxy(struct vtclog *vl, int fd, int version, const char *spec)
77
{
78
        const struct suckaddr *sac, *sas;
79
        char *p, *p2;
80
81 30
        p = strdup(spec);
82 30
        AN(p);
83 30
        p2 = strchr(p, ' ');
84 30
        AN(p2);
85 30
        *p2++ = '\0';
86
87 30
        sac = VSS_ResolveOne(NULL, p, NULL, 0, SOCK_STREAM, AI_PASSIVE);
88 30
        if (sac == NULL)
89 0
                vtc_fatal(vl, "Could not resolve client address");
90 30
        sas = VSS_ResolveOne(NULL, p2, NULL, 0, SOCK_STREAM, AI_PASSIVE);
91 30
        if (sas == NULL)
92 0
                vtc_fatal(vl, "Could not resolve server address");
93 30
        if (vtc_send_proxy(fd, version, sac, sas))
94 0
                vtc_fatal(vl, "Write failed: %s", strerror(errno));
95 30
        free(p);
96 30
        VSA_free(&sac);
97 30
        VSA_free(&sas);
98 30
}
99
100
/**********************************************************************
101
 * Socket connect.
102
 */
103
104
static int
105 5856
client_tcp_connect(struct vtclog *vl, const char *addr, double tmo,
106
                   const char **errp)
107
{
108
        int fd;
109
        char mabuf[VTCP_ADDRBUFSIZE], mpbuf[VTCP_PORTBUFSIZE];
110
111 5856
        AN(addr);
112 5856
        AN(errp);
113 5856
        fd = VTCP_open(addr, NULL, tmo, errp);
114 5856
        if (fd < 0)
115 0
                return (fd);
116 5856
        VTCP_myname(fd, mabuf, sizeof mabuf, mpbuf, sizeof mpbuf);
117 11712
        vtc_log(vl, 3, "connected fd %d from %s %s to %s", fd, mabuf, mpbuf,
118 5856
                addr);
119 5856
        return (fd);
120 5856
}
121
122
/* cf. VTCP_Open() */
123
static int v_matchproto_(vus_resolved_f)
124 756
uds_open(void *priv, const struct sockaddr_un *uds)
125
{
126
        double *p;
127
        int s, i, tmo;
128
        struct pollfd fds[1];
129
        socklen_t sl;
130
131 756
        sl = VUS_socklen(uds);
132
133 756
        AN(priv);
134 756
        AN(uds);
135 756
        p = priv;
136 756
        assert(*p > 0.);
137 756
        tmo = (int)(*p * 1e3);
138
139 756
        s = socket(uds->sun_family, SOCK_STREAM, 0);
140 756
        if (s < 0)
141 0
                return (s);
142
143 756
        VTCP_nonblocking(s);
144 756
        i = connect(s, (const void*)uds, sl);
145 756
        if (i == 0)
146 756
                return (s);
147 0
        if (errno != EINPROGRESS) {
148 0
                closefd(&s);
149 0
                return (-1);
150
        }
151
152 0
        fds[0].fd = s;
153 0
        fds[0].events = POLLWRNORM;
154 0
        fds[0].revents = 0;
155 0
        i = poll(fds, 1, tmo);
156
157 0
        if (i == 0) {
158 0
                closefd(&s);
159 0
                errno = ETIMEDOUT;
160 0
                return (-1);
161
        }
162
163 0
        return (VTCP_connected(s));
164 756
}
165
166
static int
167 756
client_uds_connect(struct vtclog *vl, const char *path, double tmo,
168
                   const char **errp)
169
{
170
        int fd;
171
172 756
        assert(tmo >= 0);
173
174 756
        errno = 0;
175 756
        fd = VUS_resolver(path, uds_open, &tmo, errp);
176 756
        if (fd < 0) {
177 0
                *errp = strerror(errno);
178 0
                return (fd);
179
        }
180 756
        vtc_log(vl, 3, "connected fd %d to %s", fd, path);
181 756
        return (fd);
182 756
}
183
184
static int
185 6612
client_connect(struct vtclog *vl, struct client *c)
186
{
187
        const char *err;
188
        int fd;
189
190 6612
        vtc_log(vl, 3, "Connect to %s", c->addr);
191 6612
        if (VUS_is(c->addr))
192 756
                fd = client_uds_connect(vl, c->addr, 10., &err);
193
        else
194 5856
                fd = client_tcp_connect(vl, c->addr, 10., &err);
195 6612
        if (fd < 0)
196 0
                vtc_fatal(c->vl, "Failed to open %s: %s",
197 0
                    c->addr, err);
198
        /* VTCP_blocking does its own checks, trust it */
199 6612
        VTCP_blocking(fd);
200 6612
        if (c->proxy_spec != NULL)
201 30
                client_proxy(vl, fd, c->proxy_version, c->proxy_spec);
202 6612
        return (fd);
203
}
204
205
/**********************************************************************
206
 * Client thread
207
 */
208
209
static int
210 6612
client_conn(void *priv, struct vtclog *vl)
211
{
212
        struct client *c;
213
214 6612
        CAST_OBJ_NOTNULL(c, priv, CLIENT_MAGIC);
215 6612
        return (client_connect(vl, c));
216
}
217
218
static void
219 6610
client_disc(void *priv, struct vtclog *vl, int *fdp)
220
{
221 6610
        (void)priv;
222 6610
        vtc_log(vl, 3, "closing fd %d", *fdp);
223 6610
        VTCP_close(fdp);
224 6610
}
225
226
/**********************************************************************
227
 * Allocate and initialize a client
228
 */
229
230
static struct client *
231 3423
client_new(const char *name)
232
{
233
        struct client *c;
234
235 3423
        ALLOC_OBJ(c, CLIENT_MAGIC);
236 3423
        AN(c);
237 3423
        REPLACE(c->name, name);
238 3423
        c->vl = vtc_logopen("%s", name);
239 3423
        AN(c->vl);
240 3423
        c->vsp = Sess_New(c->vl, name);
241 3423
        AN(c->vsp);
242
243 3423
        bprintf(c->connect, "%s", "${v1_sock}");
244 3423
        VTAILQ_INSERT_TAIL(&clients, c, list);
245 3423
        return (c);
246
}
247
248
/**********************************************************************
249
 * Clean up client
250
 */
251
252
static void
253 3423
client_delete(struct client *c)
254
{
255
256 3423
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
257 3423
        Sess_Destroy(&c->vsp);
258 3423
        vtc_logclose(c->vl);
259 3423
        free(c->spec);
260 3423
        free(c->name);
261 3423
        free(c->addr);
262 3423
        free(c->proxy_spec);
263
        /* XXX: MEMLEAK (?)*/
264 3423
        FREE_OBJ(c);
265 3423
}
266
267
/**********************************************************************
268
 * Start the client thread
269
 */
270
271
static void
272 5271
client_start(struct client *c)
273
{
274
        struct vsb *vsb;
275
276 5271
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
277 5271
        vtc_log(c->vl, 2, "Starting client");
278 5271
        c->running = 1;
279 5271
        vsb = macro_expand(c->vl, c->connect);
280 5271
        AN(vsb);
281 5271
        REPLACE(c->addr, VSB_data(vsb));
282 5271
        VSB_destroy(&vsb);
283 5271
        c->tp = Sess_Start_Thread(
284 5271
            c,
285 5271
            c->vsp,
286
            client_conn,
287
            client_disc,
288 5271
            c->addr,
289
            NULL,
290 5271
            c->spec
291
        );
292 5271
}
293
294
/**********************************************************************
295
 * Wait for client thread to stop
296
 */
297
298
static void
299 5271
client_wait(struct client *c)
300
{
301
        void *res;
302
303 5271
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
304 5271
        vtc_log(c->vl, 2, "Waiting for client");
305 5271
        PTOK(pthread_join(c->tp, &res));
306 5271
        if (res != NULL)
307 0
                vtc_fatal(c->vl, "Client returned \"%s\"", (char *)res);
308 5271
        c->tp = 0;
309 5271
        c->running = 0;
310 5271
}
311
312
/**********************************************************************
313
 * Run the client thread
314
 */
315
316
static void
317 4680
client_run(struct client *c)
318
{
319
320 4680
        client_start(c);
321 4680
        client_wait(c);
322 4680
}
323
324
325
/**********************************************************************
326
 * Client command dispatch
327
 */
328
329
void
330 9069
cmd_client(CMD_ARGS)
331
{
332
        struct client *c, *c2;
333
334 9069
        (void)priv;
335
336 9069
        if (av == NULL) {
337
                /* Reset and free */
338 6444
                VTAILQ_FOREACH_SAFE(c, &clients, list, c2) {
339 3423
                        VTAILQ_REMOVE(&clients, c, list);
340 3423
                        if (c->tp != 0)
341 63
                                client_wait(c);
342 3423
                        client_delete(c);
343 3423
                }
344 3021
                return;
345
        }
346
347 6048
        AZ(strcmp(av[0], "client"));
348 6048
        av++;
349
350 6048
        VTC_CHECK_NAME(vl, av[0], "Client", 'c');
351 8799
        VTAILQ_FOREACH(c, &clients, list)
352 5376
                if (!strcmp(c->name, av[0]))
353 2625
                        break;
354 6048
        if (c == NULL)
355 3423
                c = client_new(av[0]);
356 6048
        av++;
357
358 17550
        for (; *av != NULL; av++) {
359 11502
                if (vtc_error)
360 0
                        break;
361
362 11502
                if (!strcmp(*av, "-wait")) {
363 525
                        client_wait(c);
364 525
                        continue;
365
                }
366
367
                /* Don't muck about with a running client */
368 10977
                if (c->running)
369 3
                        client_wait(c);
370
371 10977
                AZ(c->running);
372 10977
                if (Sess_GetOpt(c->vsp, &av))
373 96
                        continue;
374
375 10881
                if (!strcmp(*av, "-connect")) {
376 444
                        bprintf(c->connect, "%s", av[1]);
377 444
                        av++;
378 444
                        continue;
379
                }
380 10437
                if (!strcmp(*av, "-proxy1")) {
381 24
                        REPLACE(c->proxy_spec, av[1]);
382 24
                        c->proxy_version = 1;
383 24
                        av++;
384 24
                        continue;
385
                }
386 10413
                if (!strcmp(*av, "-proxy2")) {
387 6
                        REPLACE(c->proxy_spec, av[1]);
388 6
                        c->proxy_version = 2;
389 6
                        av++;
390 6
                        continue;
391
                }
392 10407
                if (!strcmp(*av, "-start")) {
393 591
                        client_start(c);
394 591
                        continue;
395
                }
396 9816
                if (!strcmp(*av, "-run")) {
397 4680
                        client_run(c);
398 4680
                        continue;
399
                }
400 5136
                if (**av == '-')
401 0
                        vtc_fatal(c->vl, "Unknown client argument: %s", *av);
402 5136
                REPLACE(c->spec, *av);
403 5136
        }
404 9069
}