varnish-cache/lib/libvarnish/vus.c
0
/*-
1
 * Copyright 2018 UPLEX - Nils Goroll Systemoptimierung
2
 * All rights reserved.
3
 *
4
 * Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
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 <sys/socket.h>
31
#include <sys/un.h>
32
33
#include <unistd.h>
34
#include <string.h>
35
#include <poll.h>
36
#include <stdio.h>
37
38
#include "vdef.h"
39
#include "vas.h"
40
#include "vus.h"
41
#include "vtcp.h"
42
43
static int
44 13777
sun_init(struct sockaddr_un *uds, const char *path, const char **err)
45
{
46 13777
        AN(uds);
47 13777
        AN(path);
48 13777
        assert(VUS_is(path));
49
50 13777
        if (err)
51 10825
                *err = NULL;
52
53 13777
        if (strlen(path) + 1 > sizeof(uds->sun_path)) {
54 50
                errno = ENAMETOOLONG;
55 50
                if (err)
56 50
                        *err = "Path too long for a Unix domain socket";
57 50
                return (-1);
58
        }
59 13727
        if (! strcmp(path, "@")) {
60 0
                errno = EINVAL;
61 0
                if (err)
62 0
                        *err = "The empty abstract socket name is not"
63
                            " supported";
64 0
                return (-1);
65
        }
66 13727
        memset(uds->sun_path, 0, sizeof(uds->sun_path));
67 13727
        if (*path == '@')
68 25
                bprintf(uds->sun_path, "%c%s", 0, path + 1);
69
        else
70 13702
                bprintf(uds->sun_path, "%s", path);
71 13727
        uds->sun_family = PF_UNIX;
72 13727
        return (0);
73 13777
}
74
75
int
76 10850
VUS_resolver(const char *path, vus_resolved_f *func, void *priv,
77
             const char **err)
78
{
79
        struct sockaddr_un uds;
80
        int ret;
81
82 10850
        AN(err);
83
84 10850
        ret = sun_init(&uds, path, err);
85 10850
        if (ret)
86 50
                return (ret);
87
88 10800
        assert(uds.sun_path[1] != '\0');
89
90 10800
        if (func != NULL)
91 10775
                ret = func(priv, &uds);
92 10800
        return (ret);
93 10800
}
94
95
int
96 2925
VUS_bind(const struct sockaddr_un *uds, const char **errp)
97
{
98
        int sd, e;
99
        socklen_t sl;
100
101 2925
        sl = VUS_socklen(uds);
102
103 2925
        if (errp != NULL)
104 1475
                *errp = NULL;
105
106 2925
        sd = socket(PF_UNIX, SOCK_STREAM, 0);
107 2925
        if (sd < 0) {
108 0
                if (errp != NULL)
109 0
                        *errp = "socket(2)";
110 0
                return (-1);
111
        }
112
113 2925
        if (unlink(uds->sun_path) != 0 && errno != ENOENT) {
114 0
                if (errp != NULL)
115 0
                        *errp = "unlink(2)";
116 0
                e = errno;
117 0
                closefd(&sd);
118 0
                errno = e;
119 0
                return (-1);
120
        }
121
122 2925
        if (bind(sd, (const void*)uds, sl) != 0) {
123 25
                if (errp != NULL)
124 0
                        *errp = "bind(2)";
125 25
                e = errno;
126 25
                closefd(&sd);
127 25
                errno = e;
128 25
                return (-1);
129
        }
130 2900
        return (sd);
131 2925
}
132
133
int
134 2952
VUS_connect(const char *path, int msec)
135
{
136
        int s, i;
137
        struct pollfd fds[1];
138
        struct sockaddr_un uds;
139
        socklen_t sl;
140
141 2952
        if (path == NULL)
142 0
                return (-1);
143 2952
        i = sun_init(&uds, path, NULL);
144 2952
        if (i)
145 0
                return (i);
146
147 2952
        assert(uds.sun_path[1] != '\0');
148
149 2952
        sl = VUS_socklen(&uds);
150
151 2952
        AN(sl);
152
153 2952
        s = socket(PF_UNIX, SOCK_STREAM, 0);
154 2952
        if (s < 0)
155 0
                return (s);
156
157
        /* Set the socket non-blocking */
158 2952
        if (msec != 0)
159 2952
                VTCP_nonblocking(s);
160
161 2952
        i = connect(s, (const void*)&uds, sl);
162 2952
        if (i == 0)
163 2936
                return (s);
164 16
        if (errno != EINPROGRESS) {
165 16
                closefd(&s);
166 16
                return (-1);
167
        }
168
169 0
        if (msec < 0) {
170
                /*
171
                 * Caller is responsible for waiting and
172
                 * calling VTCP_connected
173
                 */
174 0
                return (s);
175
        }
176
177 0
        assert(msec > 0);
178
        /* Exercise our patience, polling for write */
179 0
        fds[0].fd = s;
180 0
        fds[0].events = POLLWRNORM;
181 0
        fds[0].revents = 0;
182 0
        i = poll(fds, 1, msec);
183
184 0
        if (i == 0) {
185
                /* Timeout, close and give up */
186 0
                closefd(&s);
187 0
                errno = ETIMEDOUT;
188 0
                return (-1);
189
        }
190
191 0
        return (VTCP_connected(s));
192 2952
}
193
194
socklen_t
195 12176
VUS_socklen(const struct sockaddr_un *uds)
196
{
197
        socklen_t sl;
198
        const char *p;
199 12176
        if (*uds->sun_path)
200 12151
                sl = sizeof(*uds);
201
        else {
202 25
                p = strchr(uds->sun_path + 1, '\0');
203 25
                assert(p != NULL);
204 25
                sl = p - (const char*)uds;
205
        }
206 12176
        assert(sl <= sizeof(*uds));
207 12176
        return sl;
208
}