| | 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 |
22089 |
sun_init(struct sockaddr_un *uds, const char *path, const char **err) |
45 |
|
{ |
46 |
22089 |
AN(uds); |
47 |
22089 |
AN(path); |
48 |
22089 |
assert(VUS_is(path)); |
49 |
|
|
50 |
22089 |
if (err) |
51 |
17319 |
*err = NULL; |
52 |
|
|
53 |
22089 |
if (strlen(path) + 1 > sizeof(uds->sun_path)) { |
54 |
80 |
errno = ENAMETOOLONG; |
55 |
80 |
if (err) |
56 |
80 |
*err = "Path too long for a Unix domain socket"; |
57 |
80 |
return (-1); |
58 |
|
} |
59 |
22009 |
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 |
22009 |
memset(uds->sun_path, 0, sizeof(uds->sun_path)); |
67 |
22009 |
if (*path == '@') |
68 |
40 |
bprintf(uds->sun_path, "%c%s", 0, path + 1); |
69 |
|
else |
70 |
21969 |
bprintf(uds->sun_path, "%s", path); |
71 |
22009 |
uds->sun_family = PF_UNIX; |
72 |
22009 |
return (0); |
73 |
22089 |
} |
74 |
|
|
75 |
|
int |
76 |
17360 |
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 |
17360 |
AN(err); |
83 |
|
|
84 |
17360 |
ret = sun_init(&uds, path, err); |
85 |
17360 |
if (ret) |
86 |
80 |
return (ret); |
87 |
|
|
88 |
17280 |
assert(uds.sun_path[1] != '\0'); |
89 |
|
|
90 |
17280 |
if (func != NULL) |
91 |
17240 |
ret = func(priv, &uds); |
92 |
17280 |
return (ret); |
93 |
17280 |
} |
94 |
|
|
95 |
|
int |
96 |
4680 |
VUS_bind(const struct sockaddr_un *uds, const char **errp) |
97 |
|
{ |
98 |
|
int sd, e; |
99 |
|
socklen_t sl; |
100 |
|
|
101 |
4680 |
sl = VUS_socklen(uds); |
102 |
|
|
103 |
4680 |
if (errp != NULL) |
104 |
2360 |
*errp = NULL; |
105 |
|
|
106 |
4680 |
sd = socket(PF_UNIX, SOCK_STREAM, 0); |
107 |
4680 |
if (sd < 0) { |
108 |
0 |
if (errp != NULL) |
109 |
0 |
*errp = "socket(2)"; |
110 |
0 |
return (-1); |
111 |
|
} |
112 |
|
|
113 |
4680 |
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 |
4680 |
if (bind(sd, (const void*)uds, sl) != 0) { |
123 |
40 |
if (errp != NULL) |
124 |
0 |
*errp = "bind(2)"; |
125 |
40 |
e = errno; |
126 |
40 |
closefd(&sd); |
127 |
40 |
errno = e; |
128 |
40 |
return (-1); |
129 |
|
} |
130 |
4640 |
return (sd); |
131 |
4680 |
} |
132 |
|
|
133 |
|
int |
134 |
4769 |
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 |
4769 |
if (path == NULL) |
142 |
0 |
return (-1); |
143 |
4769 |
i = sun_init(&uds, path, NULL); |
144 |
4769 |
if (i) |
145 |
0 |
return (i); |
146 |
|
|
147 |
4769 |
assert(uds.sun_path[1] != '\0'); |
148 |
|
|
149 |
4769 |
sl = VUS_socklen(&uds); |
150 |
|
|
151 |
4769 |
AN(sl); |
152 |
|
|
153 |
4769 |
s = socket(PF_UNIX, SOCK_STREAM, 0); |
154 |
4769 |
if (s < 0) |
155 |
0 |
return (s); |
156 |
|
|
157 |
|
/* Set the socket non-blocking */ |
158 |
4769 |
if (msec != 0) |
159 |
4769 |
VTCP_nonblocking(s); |
160 |
|
|
161 |
4769 |
i = connect(s, (const void*)&uds, sl); |
162 |
4769 |
if (i == 0) |
163 |
4744 |
return (s); |
164 |
25 |
if (errno != EINPROGRESS) { |
165 |
25 |
closefd(&s); |
166 |
25 |
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 |
4769 |
} |
193 |
|
|
194 |
|
socklen_t |
195 |
19528 |
VUS_socklen(const struct sockaddr_un *uds) |
196 |
|
{ |
197 |
|
socklen_t sl; |
198 |
|
const char *p; |
199 |
19528 |
if (*uds->sun_path) |
200 |
19488 |
sl = sizeof(*uds); |
201 |
|
else { |
202 |
40 |
p = strchr(uds->sun_path + 1, '\0'); |
203 |
40 |
assert(p != NULL); |
204 |
40 |
sl = p - (const char*)uds; |
205 |
|
} |
206 |
19528 |
assert(sl <= sizeof(*uds)); |
207 |
19528 |
return sl; |
208 |
|
} |