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