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