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