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 74751
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 74751
        AN(addr);
112 74751
        AN(errp);
113 74751
        fd = VTCP_open(addr, NULL, tmo, errp);
114 74751
        if (fd < 0)
115 0
                return (fd);
116 74751
        VTCP_myname(fd, mabuf, sizeof mabuf, mpbuf, sizeof mpbuf);
117 149502
        vtc_log(vl, 3, "connected fd %d from %s %s to %s", fd, mabuf, mpbuf,
118 74751
                addr);
119 74751
        return (fd);
120 74751
}
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 84840
client_connect(struct vtclog *vl, struct client *c)
186
{
187
        const char *err;
188
        int fd;
189
190 84840
        vtc_log(vl, 3, "Connect to %s", c->addr);
191 84840
        if (VUS_is(c->addr))
192 10080
                fd = client_uds_connect(vl, c->addr, 10., &err);
193
        else
194 74760
                fd = client_tcp_connect(vl, c->addr, 10., &err);
195 84840
        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 84840
        VTCP_blocking(fd);
200 84840
        if (c->proxy_spec != NULL)
201 400
                client_proxy(vl, fd, c->proxy_version, c->proxy_spec);
202 84840
        return (fd);
203
}
204
205
/**********************************************************************
206
 * Client thread
207
 */
208
209
static int
210 84840
client_conn(void *priv, struct vtclog *vl)
211
{
212
        struct client *c;
213
214 84840
        CAST_OBJ_NOTNULL(c, priv, CLIENT_MAGIC);
215 84840
        return (client_connect(vl, c));
216
}
217
218
static void
219 84829
client_disc(void *priv, struct vtclog *vl, int *fdp)
220
{
221 84829
        (void)priv;
222 84829
        vtc_log(vl, 3, "closing fd %d", *fdp);
223 84829
        VTCP_close(fdp);
224 84829
}
225
226
/**********************************************************************
227
 * Allocate and initialize a client
228
 */
229
230
static struct client *
231 44440
client_new(const char *name)
232
{
233
        struct client *c;
234
235 44440
        ALLOC_OBJ(c, CLIENT_MAGIC);
236 44440
        AN(c);
237 44440
        REPLACE(c->name, name);
238 44440
        c->vl = vtc_logopen("%s", name);
239 44440
        AN(c->vl);
240 44440
        c->vsp = Sess_New(c->vl, name);
241 44440
        AN(c->vsp);
242
243 44440
        bprintf(c->connect, "%s", "${v1_sock}");
244 44440
        VTAILQ_INSERT_TAIL(&clients, c, list);
245 44440
        return (c);
246
}
247
248
/**********************************************************************
249
 * Clean up client
250
 */
251
252
static void
253 44440
client_delete(struct client *c)
254
{
255
256 44440
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
257 44440
        Sess_Destroy(&c->vsp);
258 44440
        vtc_logclose(c->vl);
259 44440
        free(c->spec);
260 44440
        free(c->name);
261 44440
        free(c->addr);
262 44440
        free(c->proxy_spec);
263
        /* XXX: MEMLEAK (?)*/
264 44440
        FREE_OBJ(c);
265 44440
}
266
267
/**********************************************************************
268
 * Start the client thread
269
 */
270
271
static void
272 68520
client_start(struct client *c)
273
{
274
        struct vsb *vsb;
275
276 68520
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
277 68520
        vtc_log(c->vl, 2, "Starting client");
278 68520
        c->running = 1;
279 68520
        vsb = macro_expand(c->vl, c->connect);
280 68520
        AN(vsb);
281 68520
        REPLACE(c->addr, VSB_data(vsb));
282 68520
        VSB_destroy(&vsb);
283 68520
        c->tp = Sess_Start_Thread(
284 68520
            c,
285 68520
            c->vsp,
286
            client_conn,
287
            client_disc,
288 68520
            c->addr,
289
            NULL,
290 68520
            c->spec
291
        );
292 68520
}
293
294
/**********************************************************************
295
 * Wait for client thread to stop
296
 */
297
298
static void
299 68520
client_wait(struct client *c)
300
{
301
        void *res;
302
303 68520
        CHECK_OBJ_NOTNULL(c, CLIENT_MAGIC);
304 68520
        vtc_log(c->vl, 2, "Waiting for client");
305 68520
        PTOK(pthread_join(c->tp, &res));
306 68520
        if (res != NULL)
307 0
                vtc_fatal(c->vl, "Client returned \"%s\"", (char *)res);
308 68520
        c->tp = 0;
309 68520
        c->running = 0;
310 68520
}
311
312
/**********************************************************************
313
 * Run the client thread
314
 */
315
316
static void
317 61400
client_run(struct client *c)
318
{
319
320 61400
        client_start(c);
321 61400
        client_wait(c);
322 61400
}
323
324
325
/**********************************************************************
326
 * Client command dispatch
327
 */
328
329
void
330 117800
cmd_client(CMD_ARGS)
331
{
332
        struct client *c, *c2;
333
334 117800
        (void)priv;
335
336 117800
        if (av == NULL) {
337
                /* Reset and free */
338 84080
                VTAILQ_FOREACH_SAFE(c, &clients, list, c2) {
339 44440
                        VTAILQ_REMOVE(&clients, c, list);
340 44440
                        if (c->tp != 0)
341 800
                                client_wait(c);
342 44440
                        client_delete(c);
343 44440
                }
344 39640
                return;
345
        }
346
347 78160
        AZ(strcmp(av[0], "client"));
348 78160
        av++;
349
350 78160
        VTC_CHECK_NAME(vl, av[0], "Client", 'c');
351 109160
        VTAILQ_FOREACH(c, &clients, list)
352 64720
                if (!strcmp(c->name, av[0]))
353 33720
                        break;
354 78160
        if (c == NULL)
355 44440
                c = client_new(av[0]);
356 78160
        av++;
357
358 226880
        for (; *av != NULL; av++) {
359 148720
                if (vtc_error)
360 0
                        break;
361
362 148720
                if (!strcmp(*av, "-wait")) {
363 6280
                        client_wait(c);
364 6280
                        continue;
365
                }
366
367
                /* Don't muck about with a running client */
368 142440
                if (c->running)
369 40
                        client_wait(c);
370
371 142440
                AZ(c->running);
372 142440
                if (Sess_GetOpt(c->vsp, &av))
373 960
                        continue;
374
375 141480
                if (!strcmp(*av, "-connect")) {
376 5840
                        bprintf(c->connect, "%s", av[1]);
377 5840
                        av++;
378 5840
                        continue;
379
                }
380 135640
                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 135320
                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 135240
                if (!strcmp(*av, "-start")) {
393 7120
                        client_start(c);
394 7120
                        continue;
395
                }
396 128120
                if (!strcmp(*av, "-run")) {
397 61400
                        client_run(c);
398 61400
                        continue;
399
                }
400 66720
                if (**av == '-')
401 0
                        vtc_fatal(c->vl, "Unknown client argument: %s", *av);
402 66720
                REPLACE(c->spec, *av);
403 66720
        }
404 117800
}