| | varnish-cache/lib/libvarnish/vtcp.c |
| 0 |
|
/*- |
| 1 |
|
* Copyright (c) 2006 Verdens Gang AS |
| 2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
| 3 |
|
* All rights reserved. |
| 4 |
|
* |
| 5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
| 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 "config.h" |
| 32 |
|
|
| 33 |
|
#include <sys/types.h> |
| 34 |
|
#include <sys/socket.h> |
| 35 |
|
#include <sys/time.h> // for NetBSD |
| 36 |
|
#include <sys/ioctl.h> |
| 37 |
|
#ifdef HAVE_SYS_FILIO_H |
| 38 |
|
# include <sys/filio.h> |
| 39 |
|
#endif |
| 40 |
|
|
| 41 |
|
#include <netinet/in.h> |
| 42 |
|
#include <netinet/tcp.h> |
| 43 |
|
|
| 44 |
|
#include <math.h> |
| 45 |
|
#include <netdb.h> |
| 46 |
|
#include <poll.h> |
| 47 |
|
#include <stdio.h> |
| 48 |
|
#include <string.h> |
| 49 |
|
#include <unistd.h> |
| 50 |
|
#include <stdlib.h> |
| 51 |
|
|
| 52 |
|
#include "vdef.h" |
| 53 |
|
#include "miniobj.h" |
| 54 |
|
#include "vas.h" |
| 55 |
|
#include "vsa.h" |
| 56 |
|
#include "vss.h" |
| 57 |
|
#include "vtcp.h" |
| 58 |
|
#include "vtim.h" |
| 59 |
|
|
| 60 |
|
/*--------------------------------------------------------------------*/ |
| 61 |
|
static void |
| 62 |
28777 |
vtcp_sa_to_ascii(const void *sa, socklen_t l, char *abuf, unsigned alen, |
| 63 |
|
char *pbuf, unsigned plen) |
| 64 |
|
{ |
| 65 |
|
int i; |
| 66 |
|
|
| 67 |
28777 |
assert(abuf == NULL || alen > 0); |
| 68 |
28777 |
assert(pbuf == NULL || plen > 0); |
| 69 |
28777 |
i = getnameinfo(sa, l, abuf, alen, pbuf, plen, |
| 70 |
|
NI_NUMERICHOST | NI_NUMERICSERV); |
| 71 |
28777 |
if (i) { |
| 72 |
|
/* |
| 73 |
|
* XXX this printf is shitty, but we may not have space |
| 74 |
|
* for the gai_strerror in the buffer :-( |
| 75 |
|
*/ |
| 76 |
0 |
fprintf(stderr, "getnameinfo = %d %s\n", i, gai_strerror(i)); |
| 77 |
0 |
if (i == EAI_SYSTEM) |
| 78 |
0 |
fprintf(stderr, "errno = %d %s\n", errno, VAS_errtxt(errno)); |
| 79 |
0 |
if (abuf != NULL) |
| 80 |
0 |
(void)snprintf(abuf, alen, "Conversion"); |
| 81 |
0 |
if (pbuf != NULL) |
| 82 |
0 |
(void)snprintf(pbuf, plen, "Failed"); |
| 83 |
0 |
return; |
| 84 |
|
} |
| 85 |
|
/* XXX dirty hack for v4-to-v6 mapped addresses */ |
| 86 |
28777 |
if (abuf != NULL && strncmp(abuf, "::ffff:", 7) == 0) { |
| 87 |
0 |
for (i = 0; abuf[i + 7]; ++i) |
| 88 |
0 |
abuf[i] = abuf[i + 7]; |
| 89 |
0 |
abuf[i] = '\0'; |
| 90 |
0 |
} |
| 91 |
28777 |
} |
| 92 |
|
|
| 93 |
|
/*--------------------------------------------------------------------*/ |
| 94 |
|
|
| 95 |
|
void |
| 96 |
28775 |
VTCP_name(const struct suckaddr *addr, char *abuf, unsigned alen, |
| 97 |
|
char *pbuf, unsigned plen) |
| 98 |
|
{ |
| 99 |
|
const struct sockaddr *sa; |
| 100 |
|
socklen_t sl; |
| 101 |
|
|
| 102 |
28775 |
sa = VSA_Get_Sockaddr(addr, &sl); |
| 103 |
28775 |
AN(sa); |
| 104 |
28775 |
vtcp_sa_to_ascii(sa, sl, abuf, alen, pbuf, plen); |
| 105 |
28775 |
} |
| 106 |
|
|
| 107 |
|
/*--------------------------------------------------------------------*/ |
| 108 |
|
|
| 109 |
|
struct suckaddr * |
| 110 |
974 |
VTCP_my_suckaddr(int sock) |
| 111 |
|
{ |
| 112 |
|
struct suckaddr *r; |
| 113 |
|
|
| 114 |
974 |
r = malloc(vsa_suckaddr_len); |
| 115 |
974 |
AN(VSA_getsockname(sock, r, vsa_suckaddr_len)); |
| 116 |
974 |
return (r); |
| 117 |
|
} |
| 118 |
|
|
| 119 |
|
/*--------------------------------------------------------------------*/ |
| 120 |
|
|
| 121 |
|
void |
| 122 |
12681 |
VTCP_myname(int sock, char *abuf, unsigned alen, char *pbuf, unsigned plen) |
| 123 |
|
{ |
| 124 |
12681 |
char buf[vsa_suckaddr_len]; |
| 125 |
|
|
| 126 |
25362 |
VTCP_name(VSA_getsockname(sock, buf, sizeof buf), |
| 127 |
12681 |
abuf, alen, pbuf, plen); |
| 128 |
12681 |
} |
| 129 |
|
|
| 130 |
|
/*--------------------------------------------------------------------*/ |
| 131 |
|
|
| 132 |
|
void |
| 133 |
7928 |
VTCP_hisname(int sock, char *abuf, unsigned alen, char *pbuf, unsigned plen) |
| 134 |
|
{ |
| 135 |
7928 |
char buf[vsa_suckaddr_len]; |
| 136 |
|
const struct suckaddr *sua; |
| 137 |
|
|
| 138 |
7928 |
sua = VSA_getpeername(sock, buf, sizeof buf); |
| 139 |
7928 |
if (sua != NULL) |
| 140 |
7928 |
VTCP_name(sua, abuf, alen, pbuf, plen); |
| 141 |
|
else { |
| 142 |
0 |
(void)snprintf(abuf, alen, "<none>"); |
| 143 |
0 |
(void)snprintf(pbuf, plen, "<none>"); |
| 144 |
|
} |
| 145 |
7928 |
} |
| 146 |
|
|
| 147 |
|
/*--------------------------------------------------------------------*/ |
| 148 |
|
|
| 149 |
|
#ifdef HAVE_ACCEPT_FILTERS |
| 150 |
|
|
| 151 |
|
int |
| 152 |
931 |
VTCP_filter_http(int sock) |
| 153 |
|
{ |
| 154 |
|
int retval; |
| 155 |
|
struct accept_filter_arg afa; |
| 156 |
|
|
| 157 |
931 |
memset(&afa, 0, sizeof afa); |
| 158 |
931 |
bprintf(afa.af_name, "%s", "httpready"); |
| 159 |
931 |
retval = setsockopt(sock, SOL_SOCKET, SO_ACCEPTFILTER, |
| 160 |
|
&afa, sizeof afa); |
| 161 |
931 |
return (retval); |
| 162 |
|
} |
| 163 |
|
|
| 164 |
|
#elif defined(__linux) |
| 165 |
|
|
| 166 |
|
int |
| 167 |
|
VTCP_filter_http(int sock) |
| 168 |
|
{ |
| 169 |
|
int retval; |
| 170 |
|
int defer = 1; |
| 171 |
|
|
| 172 |
|
retval = setsockopt(sock, SOL_TCP, TCP_DEFER_ACCEPT, |
| 173 |
|
&defer, sizeof defer); |
| 174 |
|
return (retval); |
| 175 |
|
} |
| 176 |
|
|
| 177 |
|
#else |
| 178 |
|
|
| 179 |
|
int |
| 180 |
|
VTCP_filter_http(int sock) |
| 181 |
|
{ |
| 182 |
|
errno = EOPNOTSUPP; |
| 183 |
|
(void)sock; |
| 184 |
|
return (-1); |
| 185 |
|
} |
| 186 |
|
|
| 187 |
|
#endif |
| 188 |
|
|
| 189 |
|
/*--------------------------------------------------------------------*/ |
| 190 |
|
|
| 191 |
|
|
| 192 |
|
int |
| 193 |
0 |
VTCP_fastopen(int sock, int depth) |
| 194 |
|
{ |
| 195 |
|
#ifdef HAVE_TCP_FASTOPEN |
| 196 |
|
# ifndef SOL_TCP |
| 197 |
|
# define SOL_TCP IPPROTO_TCP |
| 198 |
|
# endif |
| 199 |
0 |
return (setsockopt(sock, SOL_TCP, TCP_FASTOPEN, &depth, sizeof depth)); |
| 200 |
|
#else |
| 201 |
|
errno = EOPNOTSUPP; |
| 202 |
|
(void)sock; |
| 203 |
|
(void)depth; |
| 204 |
|
return (-1); |
| 205 |
|
#endif |
| 206 |
|
} |
| 207 |
|
|
| 208 |
|
|
| 209 |
|
/*-------------------------------------------------------------------- |
| 210 |
|
* Functions for controlling NONBLOCK mode. |
| 211 |
|
* |
| 212 |
|
* We use FIONBIO because it is cheaper than fcntl(2), which requires |
| 213 |
|
* us to do two syscalls, one to get and one to set, the latter of |
| 214 |
|
* which mucks about a bit before it ends up calling ioctl(FIONBIO), |
| 215 |
|
* at least on FreeBSD. |
| 216 |
|
* On Solaris ioctl(FIONBIO) can fail with connection related errnos, |
| 217 |
|
* but as long as that is how they fail, we're fine. |
| 218 |
|
*/ |
| 219 |
|
|
| 220 |
|
void |
| 221 |
14277 |
VTCP_blocking(int sock) |
| 222 |
|
{ |
| 223 |
|
int i, j; |
| 224 |
|
|
| 225 |
14277 |
i = 0; |
| 226 |
14277 |
j = ioctl(sock, FIONBIO, &i); |
| 227 |
14277 |
VTCP_Assert(j); |
| 228 |
14277 |
} |
| 229 |
|
|
| 230 |
|
void |
| 231 |
5019 |
VTCP_nonblocking(int sock) |
| 232 |
|
{ |
| 233 |
|
int i, j; |
| 234 |
|
|
| 235 |
5019 |
i = 1; |
| 236 |
5019 |
j = ioctl(sock, FIONBIO, &i); |
| 237 |
5019 |
VTCP_Assert(j); |
| 238 |
5019 |
} |
| 239 |
|
|
| 240 |
|
/*-------------------------------------------------------------------- |
| 241 |
|
* On TCP a connect(2) can block for a looong time, and we don't want that. |
| 242 |
|
* Unfortunately, the SocketWizards back in those days were happy to wait |
| 243 |
|
* any amount of time for a connection, so the connect(2) syscall does not |
| 244 |
|
* take an argument for patience. |
| 245 |
|
* |
| 246 |
|
* There is a little used work-around, and we employ it at our peril. |
| 247 |
|
* |
| 248 |
|
*/ |
| 249 |
|
|
| 250 |
|
int |
| 251 |
4412 |
VTCP_connected(int s) |
| 252 |
|
{ |
| 253 |
|
int k; |
| 254 |
|
socklen_t l; |
| 255 |
|
|
| 256 |
|
/* Find out if we got a connection */ |
| 257 |
4412 |
l = sizeof k; |
| 258 |
4412 |
AZ(getsockopt(s, SOL_SOCKET, SO_ERROR, &k, &l)); |
| 259 |
|
|
| 260 |
|
/* An error means no connection established */ |
| 261 |
4412 |
errno = k; |
| 262 |
4412 |
if (k) { |
| 263 |
25 |
closefd(&s); |
| 264 |
25 |
return (-1); |
| 265 |
|
} |
| 266 |
|
|
| 267 |
4387 |
VTCP_blocking(s); |
| 268 |
4387 |
return (s); |
| 269 |
4412 |
} |
| 270 |
|
|
| 271 |
|
int |
| 272 |
4601 |
VTCP_connect(const struct suckaddr *name, int msec) |
| 273 |
|
{ |
| 274 |
|
int s, i; |
| 275 |
|
struct pollfd fds[1]; |
| 276 |
|
const struct sockaddr *sa; |
| 277 |
|
socklen_t sl; |
| 278 |
|
int val; |
| 279 |
|
|
| 280 |
4601 |
if (name == NULL) |
| 281 |
28 |
return (-1); |
| 282 |
|
/* Attempt the connect */ |
| 283 |
4573 |
AN(VSA_Sane(name)); |
| 284 |
4573 |
sa = VSA_Get_Sockaddr(name, &sl); |
| 285 |
4573 |
AN(sa); |
| 286 |
4573 |
AN(sl); |
| 287 |
|
|
| 288 |
4573 |
s = socket(sa->sa_family, SOCK_STREAM, 0); |
| 289 |
4573 |
if (s < 0) |
| 290 |
0 |
return (s); |
| 291 |
|
|
| 292 |
|
/* Set the socket non-blocking */ |
| 293 |
4573 |
if (msec != 0) |
| 294 |
4420 |
VTCP_nonblocking(s); |
| 295 |
|
|
| 296 |
4573 |
val = 1; |
| 297 |
4573 |
AZ(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val)); |
| 298 |
|
|
| 299 |
4573 |
i = connect(s, sa, sl); |
| 300 |
4573 |
if (i == 0) |
| 301 |
159 |
return (s); |
| 302 |
4414 |
if (errno != EINPROGRESS) { |
| 303 |
0 |
closefd(&s); |
| 304 |
0 |
return (-1); |
| 305 |
|
} |
| 306 |
|
|
| 307 |
4414 |
if (msec < 0) { |
| 308 |
|
/* |
| 309 |
|
* Caller is responsible for waiting and |
| 310 |
|
* calling VTCP_connected |
| 311 |
|
*/ |
| 312 |
947 |
return (s); |
| 313 |
|
} |
| 314 |
|
|
| 315 |
3467 |
assert(msec > 0); |
| 316 |
|
/* Exercise our patience, polling for write */ |
| 317 |
3467 |
fds[0].fd = s; |
| 318 |
3467 |
fds[0].events = POLLWRNORM; |
| 319 |
3467 |
fds[0].revents = 0; |
| 320 |
3467 |
i = poll(fds, 1, msec); |
| 321 |
|
|
| 322 |
3467 |
if (i == 0) { |
| 323 |
|
/* Timeout, close and give up */ |
| 324 |
1 |
closefd(&s); |
| 325 |
1 |
errno = ETIMEDOUT; |
| 326 |
1 |
return (-1); |
| 327 |
|
} |
| 328 |
|
|
| 329 |
3466 |
return (VTCP_connected(s)); |
| 330 |
4601 |
} |
| 331 |
|
|
| 332 |
|
/*-------------------------------------------------------------------- |
| 333 |
|
* When closing a TCP connection, a couple of errno's are legit, we |
| 334 |
|
* can't be held responsible for the other end wanting to talk to us. |
| 335 |
|
*/ |
| 336 |
|
|
| 337 |
|
void |
| 338 |
6424 |
VTCP_close(int *s) |
| 339 |
|
{ |
| 340 |
|
int i; |
| 341 |
|
|
| 342 |
6424 |
i = close(*s); |
| 343 |
|
|
| 344 |
6424 |
VTCP_Assert(i); |
| 345 |
6424 |
*s = -1; |
| 346 |
6424 |
} |
| 347 |
|
|
| 348 |
|
void |
| 349 |
2038 |
VTCP_set_read_timeout(int s, vtim_dur seconds) |
| 350 |
|
{ |
| 351 |
2038 |
struct timeval timeout = VTIM_timeval_sock(seconds); |
| 352 |
|
|
| 353 |
|
/* |
| 354 |
|
* Solaris bug (present at least in snv_151 and older): If this fails |
| 355 |
|
* with EINVAL, the socket is half-closed (SS_CANTSENDMORE) and the |
| 356 |
|
* timeout does not get set. Needs to be fixed in Solaris, there is |
| 357 |
|
* nothing we can do about this. |
| 358 |
|
*/ |
| 359 |
2038 |
VTCP_Assert(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, |
| 360 |
|
&timeout, sizeof timeout)); |
| 361 |
2038 |
} |
| 362 |
|
|
| 363 |
|
/*-------------------------------------------------------------------- |
| 364 |
|
*/ |
| 365 |
|
|
| 366 |
|
struct vto_priv { |
| 367 |
|
unsigned magic; |
| 368 |
|
#define VTO_PRIV_MAGIC 0xca70b0e7 |
| 369 |
|
int latest_errno; |
| 370 |
|
int fd; |
| 371 |
|
double timeout; |
| 372 |
|
}; |
| 373 |
|
|
| 374 |
|
static int v_matchproto_(vss_resolved_f) |
| 375 |
2201 |
vtcp_open_callback(void *priv, const struct suckaddr *sa) |
| 376 |
|
{ |
| 377 |
|
struct vto_priv *vto; |
| 378 |
|
int fd; |
| 379 |
|
|
| 380 |
2201 |
CAST_OBJ_NOTNULL(vto, priv, VTO_PRIV_MAGIC); |
| 381 |
|
|
| 382 |
2201 |
errno = 0; |
| 383 |
2201 |
fd = VTCP_connect(sa, (int)floor(vto->timeout * 1e3)); |
| 384 |
2201 |
if (fd >= 0) { |
| 385 |
2200 |
vto->fd = fd; |
| 386 |
2200 |
vto->latest_errno = 0; |
| 387 |
2200 |
return (1); |
| 388 |
|
} |
| 389 |
1 |
vto->latest_errno = errno; |
| 390 |
1 |
return (0); |
| 391 |
2201 |
} |
| 392 |
|
|
| 393 |
|
int |
| 394 |
2201 |
VTCP_open(const char *addr, const char *def_port, vtim_dur timeout, |
| 395 |
|
const char **errp) |
| 396 |
|
{ |
| 397 |
|
struct vto_priv vto[1]; |
| 398 |
|
|
| 399 |
2201 |
AN(errp); |
| 400 |
2201 |
assert(timeout >= 0); |
| 401 |
2201 |
INIT_OBJ(vto, VTO_PRIV_MAGIC); |
| 402 |
2201 |
vto->fd = -1; |
| 403 |
2201 |
vto->timeout = timeout; |
| 404 |
|
|
| 405 |
2201 |
if (VSS_resolver(addr, def_port, vtcp_open_callback, vto, errp) < 0) |
| 406 |
0 |
return (-1); |
| 407 |
2201 |
if (vto->fd < 0) |
| 408 |
1 |
*errp = strerror(vto->latest_errno); |
| 409 |
2201 |
return (vto->fd); |
| 410 |
2201 |
} |
| 411 |
|
|
| 412 |
|
/*-------------------------------------------------------------------- |
| 413 |
|
* Given a struct suckaddr, open a socket of the appropriate type, and bind |
| 414 |
|
* it to the requested address. |
| 415 |
|
* |
| 416 |
|
* If the address is an IPv6 address, the IPV6_V6ONLY option is set to |
| 417 |
|
* avoid conflicts between INADDR_ANY and IN6ADDR_ANY. |
| 418 |
|
*/ |
| 419 |
|
|
| 420 |
|
int |
| 421 |
8971 |
VTCP_bind(const struct suckaddr *sa, const char **errp) |
| 422 |
|
{ |
| 423 |
|
int sd, val, e; |
| 424 |
|
socklen_t sl; |
| 425 |
|
const struct sockaddr *so; |
| 426 |
|
int proto; |
| 427 |
|
|
| 428 |
8971 |
if (errp != NULL) |
| 429 |
5026 |
*errp = NULL; |
| 430 |
|
|
| 431 |
8971 |
proto = VSA_Get_Proto(sa); |
| 432 |
8971 |
sd = socket(proto, SOCK_STREAM, 0); |
| 433 |
8971 |
if (sd < 0) { |
| 434 |
0 |
if (errp != NULL) |
| 435 |
0 |
*errp = "socket(2)"; |
| 436 |
0 |
return (-1); |
| 437 |
|
} |
| 438 |
8971 |
val = 1; |
| 439 |
8971 |
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val) != 0) { |
| 440 |
0 |
if (errp != NULL) |
| 441 |
0 |
*errp = "setsockopt(SO_REUSEADDR, 1)"; |
| 442 |
0 |
e = errno; |
| 443 |
0 |
closefd(&sd); |
| 444 |
0 |
errno = e; |
| 445 |
0 |
return (-1); |
| 446 |
|
} |
| 447 |
|
#ifdef IPV6_V6ONLY |
| 448 |
|
/* forcibly use separate sockets for IPv4 and IPv6 */ |
| 449 |
8971 |
val = 1; |
| 450 |
8971 |
if (proto == AF_INET6 && |
| 451 |
2044 |
setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof val) != 0) { |
| 452 |
0 |
if (errp != NULL) |
| 453 |
0 |
*errp = "setsockopt(IPV6_V6ONLY, 1)"; |
| 454 |
0 |
e = errno; |
| 455 |
0 |
closefd(&sd); |
| 456 |
0 |
errno = e; |
| 457 |
0 |
return (-1); |
| 458 |
|
} |
| 459 |
|
#endif |
| 460 |
8971 |
so = VSA_Get_Sockaddr(sa, &sl); |
| 461 |
8971 |
if (bind(sd, so, sl) != 0) { |
| 462 |
1 |
if (errp != NULL) |
| 463 |
0 |
*errp = "bind(2)"; |
| 464 |
1 |
e = errno; |
| 465 |
1 |
closefd(&sd); |
| 466 |
1 |
errno = e; |
| 467 |
1 |
return (-1); |
| 468 |
|
} |
| 469 |
8970 |
return (sd); |
| 470 |
8971 |
} |
| 471 |
|
|
| 472 |
|
/*-------------------------------------------------------------------- |
| 473 |
|
* Given a struct suckaddr, open a socket of the appropriate type, bind it |
| 474 |
|
* to the requested address, and start listening. |
| 475 |
|
*/ |
| 476 |
|
|
| 477 |
|
int |
| 478 |
5026 |
VTCP_listen(const struct suckaddr *sa, int depth, const char **errp) |
| 479 |
|
{ |
| 480 |
|
int sd; |
| 481 |
|
int e; |
| 482 |
|
|
| 483 |
5026 |
if (errp != NULL) |
| 484 |
5026 |
*errp = NULL; |
| 485 |
5026 |
sd = VTCP_bind(sa, errp); |
| 486 |
5026 |
if (sd >= 0) { |
| 487 |
5026 |
if (listen(sd, depth) != 0) { |
| 488 |
0 |
e = errno; |
| 489 |
0 |
closefd(&sd); |
| 490 |
0 |
errno = e; |
| 491 |
0 |
if (errp != NULL) |
| 492 |
0 |
*errp = "listen(2)"; |
| 493 |
0 |
return (-1); |
| 494 |
|
} |
| 495 |
5026 |
} |
| 496 |
5026 |
return (sd); |
| 497 |
5026 |
} |
| 498 |
|
|
| 499 |
|
/*--------------------------------------------------------------------*/ |
| 500 |
|
|
| 501 |
|
struct helper { |
| 502 |
|
int depth; |
| 503 |
|
const char **errp; |
| 504 |
|
}; |
| 505 |
|
|
| 506 |
|
static int v_matchproto_(vss_resolved_f) |
| 507 |
3100 |
vtcp_lo_cb(void *priv, const struct suckaddr *sa) |
| 508 |
|
{ |
| 509 |
|
int sock; |
| 510 |
3100 |
struct helper *hp = priv; |
| 511 |
|
|
| 512 |
3100 |
sock = VTCP_listen(sa, hp->depth, hp->errp); |
| 513 |
3100 |
if (sock >= 0) { |
| 514 |
3100 |
*hp->errp = NULL; |
| 515 |
3100 |
return (sock); |
| 516 |
|
} |
| 517 |
0 |
AN(*hp->errp); |
| 518 |
0 |
return (0); |
| 519 |
3100 |
} |
| 520 |
|
|
| 521 |
|
int |
| 522 |
3100 |
VTCP_listen_on(const char *addr, const char *def_port, int depth, |
| 523 |
|
const char **errp) |
| 524 |
|
{ |
| 525 |
|
struct helper h; |
| 526 |
|
int sock; |
| 527 |
|
|
| 528 |
3100 |
AN(errp); |
| 529 |
3100 |
h.depth = depth; |
| 530 |
3100 |
h.errp = errp; |
| 531 |
|
|
| 532 |
3100 |
sock = VSS_resolver(addr, def_port, vtcp_lo_cb, &h, errp); |
| 533 |
3100 |
if (*errp != NULL) |
| 534 |
0 |
return (-1); |
| 535 |
3100 |
return (sock); |
| 536 |
3100 |
} |
| 537 |
|
|
| 538 |
|
/*-------------------------------------------------------------------- |
| 539 |
|
* Set or reset SO_LINGER flag |
| 540 |
|
*/ |
| 541 |
|
|
| 542 |
|
int |
| 543 |
0 |
VTCP_linger(int sock, int linger) |
| 544 |
|
{ |
| 545 |
|
struct linger lin; |
| 546 |
|
int i; |
| 547 |
|
|
| 548 |
0 |
memset(&lin, 0, sizeof lin); |
| 549 |
0 |
lin.l_onoff = linger; |
| 550 |
0 |
i = setsockopt(sock, SOL_SOCKET, SO_LINGER, &lin, sizeof lin); |
| 551 |
0 |
VTCP_Assert(i); |
| 552 |
0 |
return (i); |
| 553 |
|
} |
| 554 |
|
|
| 555 |
|
/*-------------------------------------------------------------------- |
| 556 |
|
* Do a poll to check for remote HUP |
| 557 |
|
*/ |
| 558 |
|
|
| 559 |
|
int |
| 560 |
0 |
VTCP_check_hup(int sock) |
| 561 |
|
{ |
| 562 |
|
struct pollfd pfd; |
| 563 |
|
|
| 564 |
0 |
assert(sock > 0); |
| 565 |
0 |
pfd.fd = sock; |
| 566 |
0 |
pfd.events = POLLOUT; |
| 567 |
0 |
pfd.revents = 0; |
| 568 |
|
|
| 569 |
0 |
if (poll(&pfd, 1, 0) == 1 && pfd.revents & POLLHUP) |
| 570 |
0 |
return (1); |
| 571 |
0 |
return (0); |
| 572 |
0 |
} |
| 573 |
|
|
| 574 |
|
/*-------------------------------------------------------------------- |
| 575 |
|
* Check if a TCP syscall return value is fatal |
| 576 |
|
*/ |
| 577 |
|
|
| 578 |
|
int |
| 579 |
49773 |
VTCP_Check(ssize_t a) |
| 580 |
|
{ |
| 581 |
49773 |
if (a == 0) |
| 582 |
42625 |
return (1); |
| 583 |
7148 |
if (a > 0) |
| 584 |
7119 |
return (1); |
| 585 |
29 |
if (errno == ECONNRESET || errno == ENOTCONN || errno == EPIPE) |
| 586 |
20 |
return (1); |
| 587 |
|
/* Accept EAGAIN (and EWOULDBLOCK in case they are not the same) |
| 588 |
|
* as errno values. Even though our sockets are all non-blocking, |
| 589 |
|
* when a SO_{SND|RCV}TIMEO expires, read() or write() on the |
| 590 |
|
* socket will return (-1) and errno set to EAGAIN. (This is not |
| 591 |
|
* documented in the read(2) and write(2) manpages, but is |
| 592 |
|
* described in the socket(7) manpage.) */ |
| 593 |
9 |
if (errno == EAGAIN || errno == EWOULDBLOCK) |
| 594 |
9 |
return (1); |
| 595 |
|
/* tcp(7): The other end didn't acknowledge retransmitted data after |
| 596 |
|
* some time. */ |
| 597 |
0 |
if (errno == ETIMEDOUT) |
| 598 |
0 |
return (1); |
| 599 |
|
/* #3539 various errnos documented on linux as POSIX.1 */ |
| 600 |
0 |
if (errno == ENETDOWN || errno == ENETUNREACH || errno == ENETRESET || |
| 601 |
0 |
errno == ECONNABORTED || /* ECONNRESET see above */ |
| 602 |
0 |
errno == EHOSTUNREACH || errno == EHOSTDOWN) { |
| 603 |
0 |
return (1); |
| 604 |
|
} |
| 605 |
|
|
| 606 |
|
#if (defined (__SVR4) && defined (__sun)) |
| 607 |
|
if (errno == ECONNREFUSED) // in r02702.vtc |
| 608 |
|
return (1); |
| 609 |
|
if (errno == EPROTO) |
| 610 |
|
return (1); |
| 611 |
|
#endif |
| 612 |
|
#if (defined (__SVR4) && defined (__sun)) || \ |
| 613 |
|
defined (__NetBSD__) || \ |
| 614 |
|
defined (__APPLE__) |
| 615 |
|
/* |
| 616 |
|
* Solaris and macOS returns EINVAL if the other end unexpectedly reset |
| 617 |
|
* the connection. |
| 618 |
|
* |
| 619 |
|
* On NetBSD it is documented behaviour. |
| 620 |
|
*/ |
| 621 |
|
if (errno == EINVAL) |
| 622 |
|
return (1); |
| 623 |
|
#endif |
| 624 |
|
#if defined(ENABLE_SANITIZER) |
| 625 |
|
if (errno == EINTR) |
| 626 |
|
return (1); |
| 627 |
|
#endif |
| 628 |
0 |
return (0); |
| 629 |
49773 |
} |
| 630 |
|
|
| 631 |
|
/*-------------------------------------------------------------------- |
| 632 |
|
* |
| 633 |
|
*/ |
| 634 |
|
|
| 635 |
|
int |
| 636 |
8451 |
VTCP_read(int fd, void *ptr, size_t len, vtim_dur tmo) |
| 637 |
|
{ |
| 638 |
|
struct pollfd pfd[1]; |
| 639 |
|
int i, j; |
| 640 |
|
|
| 641 |
8451 |
if (tmo > 0.0) { |
| 642 |
8391 |
pfd[0].fd = fd; |
| 643 |
8391 |
pfd[0].events = POLLIN; |
| 644 |
8391 |
pfd[0].revents = 0; |
| 645 |
8391 |
j = poll(pfd, 1, VTIM_poll_tmo(tmo)); |
| 646 |
8391 |
if (j == 0) |
| 647 |
276 |
return (-2); |
| 648 |
8115 |
} |
| 649 |
8175 |
i = read(fd, ptr, len); |
| 650 |
8175 |
VTCP_Assert(i); |
| 651 |
8175 |
return (i < 0 ? -1 : i); |
| 652 |
8451 |
} |