varnish-cache/lib/libvarnish/vus.c
1
/*-
2
 * Copyright 2018 UPLEX - Nils Goroll Systemoptimierung
3
 * All rights reserved.
4
 *
5
 * Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include <sys/socket.h>
32
#include <sys/un.h>
33
34
#include <unistd.h>
35
#include <string.h>
36
#include <poll.h>
37
#include <stdio.h>
38
39
#include "vdef.h"
40
#include "vas.h"
41
#include "vus.h"
42
#include "vtcp.h"
43
44
int
45 4720
VUS_resolver(const char *path, vus_resolved_f *func, void *priv,
46
             const char **err)
47
{
48
        struct sockaddr_un uds;
49 4720
        int ret = 0;
50
51 4720
        AN(path);
52 4720
        assert(*path == '/');
53
54 4720
        AN(err);
55 4720
        *err = NULL;
56 4720
        if (strlen(path) + 1 > sizeof(uds.sun_path)) {
57 40
                *err = "Path too long for a Unix domain socket";
58 40
                return (-1);
59
        }
60 4680
        bprintf(uds.sun_path, "%s", path);
61 4680
        uds.sun_family = PF_UNIX;
62 4680
        if (func != NULL)
63 4680
                ret = func(priv, &uds);
64 4640
        return (ret);
65 4680
}
66
67
int
68 3960
VUS_bind(const struct sockaddr_un *uds, const char **errp)
69
{
70
        int sd, e;
71 3960
        socklen_t sl = sizeof(*uds);
72
73 3960
        if (errp != NULL)
74 2080
                *errp = NULL;
75
76 3960
        sd = socket(PF_UNIX, SOCK_STREAM, 0);
77 3960
        if (sd < 0) {
78 0
                if (errp != NULL)
79 0
                        *errp = "socket(2)";
80 0
                return (-1);
81
        }
82
83 3960
        if (unlink(uds->sun_path) != 0 && errno != ENOENT) {
84 0
                if (errp != NULL)
85 0
                        *errp = "unlink(2)";
86 0
                e = errno;
87 0
                closefd(&sd);
88 0
                errno = e;
89 0
                return (-1);
90
        }
91
92 3960
        if (bind(sd, (const void*)uds, sl) != 0) {
93 0
                if (errp != NULL)
94 0
                        *errp = "bind(2)";
95 0
                e = errno;
96 0
                closefd(&sd);
97 0
                errno = e;
98 0
                return (-1);
99
        }
100 3960
        return (sd);
101 3960
}
102
103
int
104 4428
VUS_connect(const char *path, int msec)
105
{
106
        int s, i;
107
        struct pollfd fds[1];
108
        struct sockaddr_un uds;
109 4428
        socklen_t sl = (socklen_t) sizeof(uds);
110
111 4428
        if (path == NULL)
112 0
                return (-1);
113 4427
        uds.sun_family = PF_UNIX;
114 4427
        bprintf(uds.sun_path, "%s", path);
115 4427
        AN(sl);
116
117 4427
        s = socket(PF_UNIX, SOCK_STREAM, 0);
118 4427
        if (s < 0)
119 0
                return (s);
120
121
        /* Set the socket non-blocking */
122 4428
        if (msec != 0)
123 4427
                VTCP_nonblocking(s);
124
125 4427
        i = connect(s, (const void*)&uds, sl);
126 4427
        if (i == 0)
127 4425
                return (s);
128 3
        if (errno != EINPROGRESS) {
129 3
                closefd(&s);
130 3
                return (-1);
131
        }
132
133 0
        if (msec < 0) {
134
                /*
135
                 * Caller is responsible for waiting and
136
                 * calling VTCP_connected
137
                 */
138 0
                return (s);
139
        }
140
141 0
        assert(msec > 0);
142
        /* Exercise our patience, polling for write */
143 0
        fds[0].fd = s;
144 0
        fds[0].events = POLLWRNORM;
145 0
        fds[0].revents = 0;
146 0
        i = poll(fds, 1, msec);
147
148 0
        if (i == 0) {
149
                /* Timeout, close and give up */
150 0
                closefd(&s);
151 0
                errno = ETIMEDOUT;
152 0
                return (-1);
153
        }
154
155 0
        return (VTCP_connected(s));
156 4428
}