1 /*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 4 * All rights reserved. 5 * 6 * This software was developed by Pawel Jakub Dawidek under sponsorship from 7 * the FreeBSD Foundation. 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 AUTHORS 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 THE AUTHORS 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 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto_tcp.c#2 $ 31 */ 32 33 #include <config/config.h> 34 35 #include <sys/param.h> /* MAXHOSTNAMELEN */ 36 #include <sys/socket.h> 37 38 #include <arpa/inet.h> 39 40 #include <netinet/in.h> 41 #include <netinet/tcp.h> 42 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <netdb.h> 46 #include <stdbool.h> 47 #include <stdint.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #ifndef HAVE_STRLCPY 54 #include <compat/strlcpy.h> 55 #endif 56 57 #include "pjdlog.h" 58 #include "proto_impl.h" 59 #include "subr.h" 60 61 #define TCP_CTX_MAGIC 0x7c41c 62 struct tcp_ctx { 63 int tc_magic; 64 struct sockaddr_storage tc_sa; 65 int tc_fd; 66 int tc_side; 67 #define TCP_SIDE_CLIENT 0 68 #define TCP_SIDE_SERVER_LISTEN 1 69 #define TCP_SIDE_SERVER_WORK 2 70 bool tc_wait_called; 71 }; 72 73 static int tcp_connect_wait(void *ctx, int timeout); 74 static void tcp_close(void *ctx); 75 76 /* 77 * Function converts the given string to unsigned number. 78 */ 79 static int 80 numfromstr(const char *str, intmax_t minnum, intmax_t maxnum, intmax_t *nump) 81 { 82 intmax_t digit, num; 83 84 if (str[0] == '\0') 85 goto invalid; /* Empty string. */ 86 num = 0; 87 for (; *str != '\0'; str++) { 88 if (*str < '0' || *str > '9') 89 goto invalid; /* Non-digit character. */ 90 digit = *str - '0'; 91 if (num > num * 10 + digit) 92 goto invalid; /* Overflow. */ 93 num = num * 10 + digit; 94 if (num > maxnum) 95 goto invalid; /* Too big. */ 96 } 97 if (num < minnum) 98 goto invalid; /* Too small. */ 99 *nump = num; 100 return (0); 101 invalid: 102 errno = EINVAL; 103 return (-1); 104 } 105 106 static int 107 tcp_addr(const char *addr, int defport, struct sockaddr_storage *sap) 108 { 109 char iporhost[MAXHOSTNAMELEN], portstr[6]; 110 struct addrinfo hints; 111 struct addrinfo *res; 112 const char *pp; 113 intmax_t port; 114 size_t size; 115 int error; 116 117 if (addr == NULL) 118 return (-1); 119 120 bzero(&hints, sizeof(hints)); 121 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; 122 hints.ai_family = PF_UNSPEC; 123 hints.ai_socktype = SOCK_STREAM; 124 hints.ai_protocol = IPPROTO_TCP; 125 126 if (strncasecmp(addr, "tcp4://", 7) == 0) { 127 addr += 7; 128 hints.ai_family = PF_INET; 129 } else if (strncasecmp(addr, "tcp6://", 7) == 0) { 130 addr += 7; 131 hints.ai_family = PF_INET6; 132 } else if (strncasecmp(addr, "tcp://", 6) == 0) { 133 addr += 6; 134 } else { 135 /* 136 * Because TCP is the default assume IP or host is given without 137 * prefix. 138 */ 139 } 140 141 /* 142 * Extract optional port. 143 * There are three cases to consider. 144 * 1. hostname with port, eg. freefall.freebsd.org:8457 145 * 2. IPv4 address with port, eg. 192.168.0.101:8457 146 * 3. IPv6 address with port, eg. [fe80::1]:8457 147 * We discover IPv6 address by checking for two colons and if port is 148 * given, the address has to start with [. 149 */ 150 pp = NULL; 151 if (strchr(addr, ':') != strrchr(addr, ':')) { 152 if (addr[0] == '[') 153 pp = strrchr(addr, ':'); 154 } else { 155 pp = strrchr(addr, ':'); 156 } 157 if (pp == NULL) { 158 /* Port not given, use the default. */ 159 port = defport; 160 } else { 161 if (numfromstr(pp + 1, 1, 65535, &port) < 0) 162 return (errno); 163 } 164 (void)snprintf(portstr, sizeof(portstr), "%jd", (intmax_t)port); 165 /* Extract host name or IP address. */ 166 if (pp == NULL) { 167 size = sizeof(iporhost); 168 if (strlcpy(iporhost, addr, size) >= size) 169 return (ENAMETOOLONG); 170 } else if (addr[0] == '[' && pp[-1] == ']') { 171 size = (size_t)(pp - addr - 2 + 1); 172 if (size > sizeof(iporhost)) 173 return (ENAMETOOLONG); 174 (void)strlcpy(iporhost, addr + 1, size); 175 } else { 176 size = (size_t)(pp - addr + 1); 177 if (size > sizeof(iporhost)) 178 return (ENAMETOOLONG); 179 (void)strlcpy(iporhost, addr, size); 180 } 181 182 error = getaddrinfo(iporhost, portstr, &hints, &res); 183 if (error != 0) { 184 pjdlog_debug(1, "getaddrinfo(%s, %s) failed: %s.", iporhost, 185 portstr, gai_strerror(error)); 186 return (EINVAL); 187 } 188 if (res == NULL) 189 return (ENOENT); 190 191 memcpy(sap, res->ai_addr, res->ai_addrlen); 192 193 freeaddrinfo(res); 194 195 return (0); 196 } 197 198 static int 199 tcp_setup_new(const char *addr, int side, struct tcp_ctx **tctxp) 200 { 201 struct tcp_ctx *tctx; 202 int error, nodelay; 203 204 PJDLOG_ASSERT(addr != NULL); 205 PJDLOG_ASSERT(side == TCP_SIDE_CLIENT || 206 side == TCP_SIDE_SERVER_LISTEN); 207 PJDLOG_ASSERT(tctxp != NULL); 208 209 tctx = malloc(sizeof(*tctx)); 210 if (tctx == NULL) 211 return (errno); 212 213 /* Parse given address. */ 214 error = tcp_addr(addr, atoi(proto_get("tcp:port")), &tctx->tc_sa); 215 if (error != 0) { 216 free(tctx); 217 return (error); 218 } 219 220 PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 221 222 tctx->tc_fd = socket(tctx->tc_sa.ss_family, SOCK_STREAM, 0); 223 if (tctx->tc_fd == -1) { 224 error = errno; 225 free(tctx); 226 return (error); 227 } 228 229 PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 230 231 /* Socket settings. */ 232 nodelay = 1; 233 if (setsockopt(tctx->tc_fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, 234 sizeof(nodelay)) == -1) { 235 pjdlog_errno(LOG_WARNING, "Unable to set TCP_NOELAY"); 236 } 237 238 tctx->tc_wait_called = (side == TCP_SIDE_CLIENT ? false : true); 239 tctx->tc_side = side; 240 tctx->tc_magic = TCP_CTX_MAGIC; 241 *tctxp = tctx; 242 243 return (0); 244 } 245 246 static socklen_t 247 sockaddr_len(const struct sockaddr_storage *ss) 248 { 249 250 #ifdef HAVE_SOCKADDR_STORAGE_SS_LEN 251 return (ss->ss_len); 252 #else 253 switch (ss->ss_family) { 254 case AF_INET: 255 return (sizeof(struct sockaddr_in)); 256 case AF_INET6: 257 return (sizeof(struct sockaddr_in6)); 258 default: 259 PJDLOG_ABORT("Unexpected family %hhu.", ss->ss_family); 260 } 261 #endif 262 } 263 264 static int 265 tcp_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp) 266 { 267 struct tcp_ctx *tctx; 268 struct sockaddr_storage sa; 269 int error, flags, ret; 270 271 PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0'); 272 PJDLOG_ASSERT(dstaddr != NULL); 273 PJDLOG_ASSERT(timeout >= -1); 274 275 error = tcp_setup_new(dstaddr, TCP_SIDE_CLIENT, &tctx); 276 if (error != 0) 277 return (error); 278 if (srcaddr != NULL) { 279 error = tcp_addr(srcaddr, 0, &sa); 280 if (error != 0) 281 goto fail; 282 if (bind(tctx->tc_fd, (struct sockaddr *)&sa, 283 sockaddr_len(&sa)) == -1) { 284 error = errno; 285 goto fail; 286 } 287 } 288 289 flags = fcntl(tctx->tc_fd, F_GETFL); 290 if (flags == -1) { 291 error = errno; 292 pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed"); 293 goto fail; 294 } 295 /* 296 * We make socket non-blocking so we can handle connection timeout 297 * manually. 298 */ 299 flags |= O_NONBLOCK; 300 if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 301 error = errno; 302 pjdlog_common(LOG_DEBUG, 1, errno, 303 "fcntl(F_SETFL, O_NONBLOCK) failed"); 304 goto fail; 305 } 306 307 ret = connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa, 308 sockaddr_len(&tctx->tc_sa)); 309 if (ret == -1 && errno != EINPROGRESS) { 310 error = errno; 311 pjdlog_common(LOG_DEBUG, 1, errno, "connect() failed"); 312 goto fail; 313 } 314 315 if (timeout >= 0) { 316 if (ret == -1) { 317 /* Connection still in progress. Wait for it. */ 318 error = tcp_connect_wait(tctx, timeout); 319 if (error != 0) 320 goto fail; 321 } else { 322 /* Connection already complete. */ 323 flags &= ~O_NONBLOCK; 324 if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 325 error = errno; 326 pjdlog_common(LOG_DEBUG, 1, errno, 327 "fcntl(F_SETFL, ~O_NONBLOCK) failed"); 328 goto fail; 329 } 330 } 331 } 332 333 *ctxp = tctx; 334 return (0); 335 fail: 336 tcp_close(tctx); 337 return (error); 338 } 339 340 static int 341 tcp_connect_wait(void *ctx, int timeout) 342 { 343 struct tcp_ctx *tctx = ctx; 344 struct timeval tv; 345 fd_set fdset; 346 socklen_t esize; 347 int error, flags, ret; 348 349 PJDLOG_ASSERT(tctx != NULL); 350 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 351 PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT); 352 PJDLOG_ASSERT(!tctx->tc_wait_called); 353 PJDLOG_ASSERT(tctx->tc_fd >= 0); 354 PJDLOG_ASSERT(timeout >= 0); 355 356 tv.tv_sec = timeout; 357 tv.tv_usec = 0; 358 again: 359 FD_ZERO(&fdset); 360 FD_SET(tctx->tc_fd, &fdset); 361 ret = select(tctx->tc_fd + 1, NULL, &fdset, NULL, &tv); 362 if (ret == 0) { 363 error = ETIMEDOUT; 364 goto done; 365 } else if (ret == -1) { 366 if (errno == EINTR) 367 goto again; 368 error = errno; 369 pjdlog_common(LOG_DEBUG, 1, errno, "select() failed"); 370 goto done; 371 } 372 PJDLOG_ASSERT(ret > 0); 373 PJDLOG_ASSERT(FD_ISSET(tctx->tc_fd, &fdset)); 374 esize = sizeof(error); 375 if (getsockopt(tctx->tc_fd, SOL_SOCKET, SO_ERROR, &error, 376 &esize) == -1) { 377 error = errno; 378 pjdlog_common(LOG_DEBUG, 1, errno, 379 "getsockopt(SO_ERROR) failed"); 380 goto done; 381 } 382 if (error != 0) { 383 pjdlog_common(LOG_DEBUG, 1, error, 384 "getsockopt(SO_ERROR) returned error"); 385 goto done; 386 } 387 error = 0; 388 tctx->tc_wait_called = true; 389 done: 390 flags = fcntl(tctx->tc_fd, F_GETFL); 391 if (flags == -1) { 392 if (error == 0) 393 error = errno; 394 pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed"); 395 return (error); 396 } 397 flags &= ~O_NONBLOCK; 398 if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 399 if (error == 0) 400 error = errno; 401 pjdlog_common(LOG_DEBUG, 1, errno, 402 "fcntl(F_SETFL, ~O_NONBLOCK) failed"); 403 } 404 return (error); 405 } 406 407 static int 408 tcp_server(const char *addr, void **ctxp) 409 { 410 struct tcp_ctx *tctx; 411 int error, val; 412 413 error = tcp_setup_new(addr, TCP_SIDE_SERVER_LISTEN, &tctx); 414 if (error != 0) 415 return (error); 416 417 val = 1; 418 /* Ignore failure. */ 419 (void)setsockopt(tctx->tc_fd, SOL_SOCKET, SO_REUSEADDR, &val, 420 sizeof(val)); 421 422 PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 423 424 if (bind(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa, 425 sockaddr_len(&tctx->tc_sa)) == -1) { 426 error = errno; 427 tcp_close(tctx); 428 return (error); 429 } 430 if (listen(tctx->tc_fd, 8) == -1) { 431 error = errno; 432 tcp_close(tctx); 433 return (error); 434 } 435 436 *ctxp = tctx; 437 438 return (0); 439 } 440 441 static int 442 tcp_accept(void *ctx, void **newctxp) 443 { 444 struct tcp_ctx *tctx = ctx; 445 struct tcp_ctx *newtctx; 446 socklen_t fromlen; 447 int ret; 448 449 PJDLOG_ASSERT(tctx != NULL); 450 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 451 PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_SERVER_LISTEN); 452 PJDLOG_ASSERT(tctx->tc_fd >= 0); 453 PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 454 455 newtctx = malloc(sizeof(*newtctx)); 456 if (newtctx == NULL) 457 return (errno); 458 459 fromlen = sockaddr_len(&tctx->tc_sa); 460 newtctx->tc_fd = accept(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa, 461 &fromlen); 462 if (newtctx->tc_fd < 0) { 463 ret = errno; 464 free(newtctx); 465 return (ret); 466 } 467 468 newtctx->tc_wait_called = true; 469 newtctx->tc_side = TCP_SIDE_SERVER_WORK; 470 newtctx->tc_magic = TCP_CTX_MAGIC; 471 *newctxp = newtctx; 472 473 return (0); 474 } 475 476 static int 477 tcp_wrap(int fd, bool client, void **ctxp) 478 { 479 struct tcp_ctx *tctx; 480 481 PJDLOG_ASSERT(fd >= 0); 482 PJDLOG_ASSERT(ctxp != NULL); 483 484 tctx = malloc(sizeof(*tctx)); 485 if (tctx == NULL) 486 return (errno); 487 488 tctx->tc_fd = fd; 489 tctx->tc_sa.ss_family = AF_UNSPEC; 490 tctx->tc_wait_called = (client ? false : true); 491 tctx->tc_side = (client ? TCP_SIDE_CLIENT : TCP_SIDE_SERVER_WORK); 492 tctx->tc_magic = TCP_CTX_MAGIC; 493 *ctxp = tctx; 494 495 return (0); 496 } 497 498 static int 499 tcp_send(void *ctx, const unsigned char *data, size_t size, int fd) 500 { 501 struct tcp_ctx *tctx = ctx; 502 503 PJDLOG_ASSERT(tctx != NULL); 504 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 505 PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT || 506 tctx->tc_side == TCP_SIDE_SERVER_WORK); 507 PJDLOG_ASSERT(tctx->tc_wait_called); 508 PJDLOG_ASSERT(tctx->tc_fd >= 0); 509 PJDLOG_ASSERT(fd == -1); 510 511 return (proto_common_send(tctx->tc_fd, data, size, -1)); 512 } 513 514 static int 515 tcp_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 516 { 517 struct tcp_ctx *tctx = ctx; 518 519 PJDLOG_ASSERT(tctx != NULL); 520 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 521 PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT || 522 tctx->tc_side == TCP_SIDE_SERVER_WORK); 523 PJDLOG_ASSERT(tctx->tc_wait_called); 524 PJDLOG_ASSERT(tctx->tc_fd >= 0); 525 PJDLOG_ASSERT(fdp == NULL); 526 527 return (proto_common_recv(tctx->tc_fd, data, size, NULL)); 528 } 529 530 static int 531 tcp_descriptor(const void *ctx) 532 { 533 const struct tcp_ctx *tctx = ctx; 534 535 PJDLOG_ASSERT(tctx != NULL); 536 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 537 538 return (tctx->tc_fd); 539 } 540 541 static bool 542 tcp_address_match(const void *ctx, const char *addr) 543 { 544 const struct tcp_ctx *tctx = ctx; 545 struct sockaddr_storage sa1, sa2; 546 socklen_t salen; 547 548 PJDLOG_ASSERT(tctx != NULL); 549 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 550 551 if (tcp_addr(addr, atoi(proto_get("tcp:port")), &sa1) != 0) 552 return (false); 553 554 salen = sizeof(sa2); 555 if (getpeername(tctx->tc_fd, (struct sockaddr *)&sa2, &salen) < 0) 556 return (false); 557 558 if (sa1.ss_family != sa2.ss_family) 559 return (false); 560 561 #ifdef HAVE_SOCKADDR_STORAGE_SS_LEN 562 if (sa1.ss_len != sa2.ss_len) 563 return (false); 564 #endif 565 566 switch (sa1.ss_family) { 567 case AF_INET: 568 { 569 struct sockaddr_in *sin1, *sin2; 570 571 sin1 = (struct sockaddr_in *)&sa1; 572 sin2 = (struct sockaddr_in *)&sa2; 573 574 return (memcmp(&sin1->sin_addr, &sin2->sin_addr, 575 sizeof(sin1->sin_addr)) == 0); 576 } 577 case AF_INET6: 578 { 579 struct sockaddr_in6 *sin1, *sin2; 580 581 sin1 = (struct sockaddr_in6 *)&sa1; 582 sin2 = (struct sockaddr_in6 *)&sa2; 583 584 return (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, 585 sizeof(sin1->sin6_addr)) == 0); 586 } 587 default: 588 return (false); 589 } 590 } 591 592 #ifndef __FreeBSD__ 593 static void 594 sockaddr_to_string(const void *sa, char *buf, size_t size) 595 { 596 const struct sockaddr_storage *ss; 597 598 ss = (const struct sockaddr_storage * const *)sa; 599 switch (ss->ss_family) { 600 case AF_INET: 601 { 602 char addr[INET_ADDRSTRLEN]; 603 const struct sockaddr_in *sin; 604 unsigned int port; 605 606 sin = (const struct sockaddr_in *)ss; 607 port = ntohs(sin->sin_port); 608 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr, 609 sizeof(addr)) == NULL) { 610 PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.", 611 strerror(errno)); 612 } 613 snprintf(buf, size, "%s:%u", addr, port); 614 break; 615 } 616 case AF_INET6: 617 { 618 char addr[INET6_ADDRSTRLEN]; 619 const struct sockaddr_in6 *sin; 620 unsigned int port; 621 622 sin = (const struct sockaddr_in6 *)ss; 623 port = ntohs(sin->sin6_port); 624 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr, 625 sizeof(addr)) == NULL) { 626 PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.", 627 strerror(errno)); 628 } 629 snprintf(buf, size, "[%s]:%u", addr, port); 630 break; 631 } 632 default: 633 snprintf(buf, size, "[unsupported family %hhu]", 634 ss->ss_family); 635 break; 636 } 637 } 638 #endif /* !__FreeBSD__ */ 639 640 static void 641 tcp_local_address(const void *ctx, char *addr, size_t size) 642 { 643 const struct tcp_ctx *tctx = ctx; 644 struct sockaddr_storage sa; 645 socklen_t salen; 646 647 PJDLOG_ASSERT(tctx != NULL); 648 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 649 650 salen = sizeof(sa); 651 if (getsockname(tctx->tc_fd, (struct sockaddr *)&sa, &salen) < 0) { 652 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 653 return; 654 } 655 #ifdef __FreeBSD__ 656 PJDLOG_VERIFY(snprintf(addr, size, "tcp://%S", &sa) < (ssize_t)size); 657 #else 658 strlcpy(addr, "tcp://", size); 659 if (size > 6) 660 sockaddr_to_string(&sa, addr + 6, size - 6); 661 #endif 662 } 663 664 static void 665 tcp_remote_address(const void *ctx, char *addr, size_t size) 666 { 667 const struct tcp_ctx *tctx = ctx; 668 struct sockaddr_storage sa; 669 socklen_t salen; 670 671 PJDLOG_ASSERT(tctx != NULL); 672 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 673 674 salen = sizeof(sa); 675 if (getpeername(tctx->tc_fd, (struct sockaddr *)&sa, &salen) < 0) { 676 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 677 return; 678 } 679 #ifdef __FreeBSD__ 680 PJDLOG_VERIFY(snprintf(addr, size, "tcp://%S", &sa) < (ssize_t)size); 681 #else 682 strlcpy(addr, "tcp://", size); 683 if (size > 6) 684 sockaddr_to_string(&sa, addr + 6, size - 6); 685 #endif 686 } 687 688 static void 689 tcp_close(void *ctx) 690 { 691 struct tcp_ctx *tctx = ctx; 692 693 PJDLOG_ASSERT(tctx != NULL); 694 PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 695 696 if (tctx->tc_fd >= 0) 697 close(tctx->tc_fd); 698 tctx->tc_magic = 0; 699 free(tctx); 700 } 701 702 static struct proto tcp_proto = { 703 .prt_name = "tcp", 704 .prt_connect = tcp_connect, 705 .prt_connect_wait = tcp_connect_wait, 706 .prt_server = tcp_server, 707 .prt_accept = tcp_accept, 708 .prt_wrap = tcp_wrap, 709 .prt_send = tcp_send, 710 .prt_recv = tcp_recv, 711 .prt_descriptor = tcp_descriptor, 712 .prt_address_match = tcp_address_match, 713 .prt_local_address = tcp_local_address, 714 .prt_remote_address = tcp_remote_address, 715 .prt_close = tcp_close 716 }; 717 718 static __constructor void 719 tcp_ctor(void) 720 { 721 722 proto_register(&tcp_proto, true); 723 } 724