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