proto_tcp.c revision 229509
1126756Smlaier/*- 2244647Sdelphij * Copyright (c) 2009-2010 The FreeBSD Foundation 3126756Smlaier * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 4126756Smlaier * All rights reserved. 5126756Smlaier * 6126756Smlaier * This software was developed by Pawel Jakub Dawidek under sponsorship from 7126756Smlaier * the FreeBSD Foundation. 8126756Smlaier * 9126756Smlaier * Redistribution and use in source and binary forms, with or without 10126756Smlaier * modification, are permitted provided that the following conditions 11126756Smlaier * are met: 12126756Smlaier * 1. Redistributions of source code must retain the above copyright 13126756Smlaier * notice, this list of conditions and the following disclaimer. 14126756Smlaier * 2. Redistributions in binary form must reproduce the above copyright 15126756Smlaier * notice, this list of conditions and the following disclaimer in the 16126756Smlaier * documentation and/or other materials provided with the distribution. 17126756Smlaier * 18126756Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19126756Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20126756Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21126756Smlaier * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22126756Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23126756Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24126756Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25135183Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26135183Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27126756Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28126756Smlaier * SUCH DAMAGE. 29126756Smlaier */ 30126756Smlaier 31126756Smlaier#include <sys/cdefs.h> 32126756Smlaier__FBSDID("$FreeBSD: stable/9/sbin/hastd/proto_tcp.c 229509 2012-01-04 17:22:10Z trociny $"); 33126756Smlaier 34126756Smlaier#include <sys/param.h> /* MAXHOSTNAMELEN */ 35126756Smlaier#include <sys/socket.h> 36126756Smlaier 37126756Smlaier#include <arpa/inet.h> 38126756Smlaier 39126756Smlaier#include <netinet/in.h> 40126756Smlaier#include <netinet/tcp.h> 41126756Smlaier 42126756Smlaier#include <errno.h> 43126756Smlaier#include <fcntl.h> 44126756Smlaier#include <netdb.h> 45126756Smlaier#include <stdbool.h> 46126756Smlaier#include <stdint.h> 47126756Smlaier#include <stdio.h> 48126756Smlaier#include <string.h> 49126756Smlaier#include <unistd.h> 50126756Smlaier 51126756Smlaier#include "pjdlog.h" 52126756Smlaier#include "proto_impl.h" 53126756Smlaier#include "subr.h" 54126756Smlaier 55126756Smlaier#define TCP_CTX_MAGIC 0x7c41c 56126756Smlaierstruct tcp_ctx { 57126756Smlaier int tc_magic; 58126756Smlaier struct sockaddr_storage tc_sa; 59126756Smlaier int tc_fd; 60126756Smlaier int tc_side; 61126756Smlaier#define TCP_SIDE_CLIENT 0 62126756Smlaier#define TCP_SIDE_SERVER_LISTEN 1 63126756Smlaier#define TCP_SIDE_SERVER_WORK 2 64126756Smlaier}; 65126756Smlaier 66126756Smlaierstatic int tcp_connect_wait(void *ctx, int timeout); 67126756Smlaierstatic void tcp_close(void *ctx); 68126756Smlaier 69126756Smlaier/* 70126756Smlaier * Function converts the given string to unsigned number. 71126756Smlaier */ 72126756Smlaierstatic int 73126756Smlaiernumfromstr(const char *str, intmax_t minnum, intmax_t maxnum, intmax_t *nump) 74126756Smlaier{ 75126756Smlaier intmax_t digit, num; 76126756Smlaier 77126756Smlaier if (str[0] == '\0') 78126756Smlaier goto invalid; /* Empty string. */ 79126756Smlaier num = 0; 80126756Smlaier for (; *str != '\0'; str++) { 81126756Smlaier if (*str < '0' || *str > '9') 82126756Smlaier goto invalid; /* Non-digit character. */ 83126756Smlaier digit = *str - '0'; 84126756Smlaier if (num > num * 10 + digit) 85126756Smlaier goto invalid; /* Overflow. */ 86126756Smlaier num = num * 10 + digit; 87126756Smlaier if (num > maxnum) 88126756Smlaier goto invalid; /* Too big. */ 89126756Smlaier } 90126756Smlaier if (num < minnum) 91126756Smlaier goto invalid; /* Too small. */ 92126756Smlaier *nump = num; 93126756Smlaier return (0); 94126756Smlaierinvalid: 95126756Smlaier errno = EINVAL; 96126756Smlaier return (-1); 97126756Smlaier} 98126756Smlaier 99126756Smlaierstatic int 100126756Smlaiertcp_addr(const char *addr, int defport, struct sockaddr_storage *sap) 101126756Smlaier{ 102126756Smlaier char iporhost[MAXHOSTNAMELEN], portstr[6]; 103126756Smlaier struct addrinfo hints; 104126756Smlaier struct addrinfo *res; 105126756Smlaier const char *pp; 106126756Smlaier intmax_t port; 107126756Smlaier size_t size; 108126756Smlaier int error; 109126756Smlaier 110126756Smlaier if (addr == NULL) 111126756Smlaier return (-1); 112126756Smlaier 113126756Smlaier bzero(&hints, sizeof(hints)); 114126756Smlaier hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; 115126756Smlaier hints.ai_family = PF_UNSPEC; 116126756Smlaier hints.ai_socktype = SOCK_STREAM; 117126756Smlaier hints.ai_protocol = IPPROTO_TCP; 118126756Smlaier 119126756Smlaier if (strncasecmp(addr, "tcp4://", 7) == 0) { 120126756Smlaier addr += 7; 121126756Smlaier hints.ai_family = PF_INET; 122126756Smlaier } else if (strncasecmp(addr, "tcp6://", 7) == 0) { 123126756Smlaier addr += 7; 124126756Smlaier hints.ai_family = PF_INET6; 125126756Smlaier } else if (strncasecmp(addr, "tcp://", 6) == 0) { 126126756Smlaier addr += 6; 127126756Smlaier } else { 128126756Smlaier /* 129126756Smlaier * Because TCP is the default assume IP or host is given without 130126756Smlaier * prefix. 131126756Smlaier */ 132126756Smlaier } 133126756Smlaier 134126756Smlaier /* 135126756Smlaier * Extract optional port. 136126756Smlaier * There are three cases to consider. 137126756Smlaier * 1. hostname with port, eg. freefall.freebsd.org:8457 138126756Smlaier * 2. IPv4 address with port, eg. 192.168.0.101:8457 139126756Smlaier * 3. IPv6 address with port, eg. [fe80::1]:8457 140126756Smlaier * We discover IPv6 address by checking for two colons and if port is 141126756Smlaier * given, the address has to start with [. 142126756Smlaier */ 143126756Smlaier pp = NULL; 144126756Smlaier if (strchr(addr, ':') != strrchr(addr, ':')) { 145135183Smlaier if (addr[0] == '[') 146135183Smlaier pp = strrchr(addr, ':'); 147126756Smlaier } else { 148126756Smlaier pp = strrchr(addr, ':'); 149126756Smlaier } 150126756Smlaier if (pp == NULL) { 151126756Smlaier /* Port not given, use the default. */ 152126756Smlaier port = defport; 153126756Smlaier } else { 154126756Smlaier if (numfromstr(pp + 1, 1, 65535, &port) < 0) 155135183Smlaier return (errno); 156135183Smlaier } 157135183Smlaier (void)snprintf(portstr, sizeof(portstr), "%jd", (intmax_t)port); 158135183Smlaier /* Extract host name or IP address. */ 159126756Smlaier if (pp == NULL) { 160126756Smlaier size = sizeof(iporhost); 161126756Smlaier if (strlcpy(iporhost, addr, size) >= size) 162126756Smlaier return (ENAMETOOLONG); 163126756Smlaier } else if (addr[0] == '[' && pp[-1] == ']') { 164126756Smlaier size = (size_t)(pp - addr - 2 + 1); 165126756Smlaier if (size > sizeof(iporhost)) 166126756Smlaier return (ENAMETOOLONG); 167126756Smlaier (void)strlcpy(iporhost, addr + 1, size); 168126756Smlaier } else { 169126756Smlaier size = (size_t)(pp - addr + 1); 170126756Smlaier if (size > sizeof(iporhost)) 171126756Smlaier return (ENAMETOOLONG); 172126756Smlaier (void)strlcpy(iporhost, addr, size); 173126756Smlaier } 174126756Smlaier 175126756Smlaier error = getaddrinfo(iporhost, portstr, &hints, &res); 176126756Smlaier if (error != 0) { 177126756Smlaier pjdlog_debug(1, "getaddrinfo(%s, %s) failed: %s.", iporhost, 178126756Smlaier portstr, gai_strerror(error)); 179126756Smlaier return (EINVAL); 180126756Smlaier } 181126756Smlaier if (res == NULL) 182126756Smlaier return (ENOENT); 183126756Smlaier 184126756Smlaier memcpy(sap, res->ai_addr, res->ai_addrlen); 185126756Smlaier 186126756Smlaier freeaddrinfo(res); 187126756Smlaier 188126756Smlaier return (0); 189126756Smlaier} 190126756Smlaier 191126756Smlaierstatic int 192126756Smlaiertcp_setup_new(const char *addr, int side, void **ctxp) 193126756Smlaier{ 194126756Smlaier struct tcp_ctx *tctx; 195126756Smlaier int ret, nodelay; 196126756Smlaier 197126756Smlaier PJDLOG_ASSERT(addr != NULL); 198126756Smlaier PJDLOG_ASSERT(side == TCP_SIDE_CLIENT || 199126756Smlaier side == TCP_SIDE_SERVER_LISTEN); 200126756Smlaier PJDLOG_ASSERT(ctxp != NULL); 201135183Smlaier 202126756Smlaier tctx = malloc(sizeof(*tctx)); 203126756Smlaier if (tctx == NULL) 204126756Smlaier return (errno); 205126756Smlaier 206126756Smlaier /* Parse given address. */ 207126756Smlaier if ((ret = tcp_addr(addr, PROTO_TCP_DEFAULT_PORT, &tctx->tc_sa)) != 0) { 208126756Smlaier free(tctx); 209126756Smlaier return (ret); 210126756Smlaier } 211126756Smlaier 212126756Smlaier PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 213126756Smlaier 214135183Smlaier tctx->tc_fd = socket(tctx->tc_sa.ss_family, SOCK_STREAM, 0); 215126756Smlaier if (tctx->tc_fd == -1) { 216126756Smlaier ret = errno; 217126756Smlaier free(tctx); 218126756Smlaier return (ret); 219126756Smlaier } 220126756Smlaier 221126756Smlaier PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 222126756Smlaier 223126756Smlaier /* Socket settings. */ 224126756Smlaier nodelay = 1; 225126756Smlaier if (setsockopt(tctx->tc_fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, 226163621Sdelphij sizeof(nodelay)) == -1) { 227163621Sdelphij pjdlog_errno(LOG_WARNING, "Unable to set TCP_NOELAY"); 228163621Sdelphij } 229126756Smlaier 230244647Sdelphij tctx->tc_side = side; 231244647Sdelphij tctx->tc_magic = TCP_CTX_MAGIC; 232244647Sdelphij *ctxp = tctx; 233244647Sdelphij 234244647Sdelphij return (0); 235244647Sdelphij} 236244647Sdelphij 237135183Smlaierstatic int 238126756Smlaiertcp_setup_wrap(int fd, int side, void **ctxp) 239135183Smlaier{ 240135183Smlaier struct tcp_ctx *tctx; 241126756Smlaier 242126756Smlaier PJDLOG_ASSERT(fd >= 0); 243126756Smlaier PJDLOG_ASSERT(side == TCP_SIDE_CLIENT || 244126756Smlaier side == TCP_SIDE_SERVER_WORK); 245126756Smlaier PJDLOG_ASSERT(ctxp != NULL); 246126756Smlaier 247126756Smlaier tctx = malloc(sizeof(*tctx)); 248126756Smlaier if (tctx == NULL) 249126756Smlaier return (errno); 250126756Smlaier 251126756Smlaier tctx->tc_fd = fd; 252126756Smlaier tctx->tc_sa.ss_family = AF_UNSPEC; 253126756Smlaier tctx->tc_side = side; 254126756Smlaier tctx->tc_magic = TCP_CTX_MAGIC; 255126756Smlaier *ctxp = tctx; 256126756Smlaier 257126756Smlaier return (0); 258126756Smlaier} 259126756Smlaier 260126756Smlaierstatic int 261126756Smlaiertcp_client(const char *srcaddr, const char *dstaddr, void **ctxp) 262126756Smlaier{ 263126756Smlaier struct tcp_ctx *tctx; 264126756Smlaier struct sockaddr_storage sa; 265126756Smlaier int ret; 266126756Smlaier 267126756Smlaier ret = tcp_setup_new(dstaddr, TCP_SIDE_CLIENT, ctxp); 268126756Smlaier if (ret != 0) 269126756Smlaier return (ret); 270163621Sdelphij tctx = *ctxp; 271163621Sdelphij if (srcaddr == NULL) 272163621Sdelphij return (0); 273126756Smlaier ret = tcp_addr(srcaddr, 0, &sa); 274126756Smlaier if (ret != 0) { 275126756Smlaier tcp_close(tctx); 276126756Smlaier return (ret); 277126756Smlaier } 278163621Sdelphij if (bind(tctx->tc_fd, (struct sockaddr *)&sa, sa.ss_len) < 0) { 279126756Smlaier ret = errno; 280163621Sdelphij tcp_close(tctx); 281126756Smlaier return (ret); 282163621Sdelphij } 283163621Sdelphij return (0); 284163621Sdelphij} 285163621Sdelphij 286126756Smlaierstatic int 287135183Smlaiertcp_connect(void *ctx, int timeout) 288163621Sdelphij{ 289163621Sdelphij struct tcp_ctx *tctx = ctx; 290163621Sdelphij int error, flags; 291163621Sdelphij 292135183Smlaier PJDLOG_ASSERT(tctx != NULL); 293126756Smlaier PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 294126756Smlaier PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT); 295126756Smlaier PJDLOG_ASSERT(tctx->tc_fd >= 0); 296126756Smlaier PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 297135183Smlaier PJDLOG_ASSERT(timeout >= -1); 298126756Smlaier 299126756Smlaier flags = fcntl(tctx->tc_fd, F_GETFL); 300126756Smlaier if (flags == -1) { 301126756Smlaier pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed"); 302135183Smlaier return (errno); 303135183Smlaier } 304126756Smlaier /* 305126756Smlaier * We make socket non-blocking so we can handle connection timeout 306126756Smlaier * manually. 307126756Smlaier */ 308225452Sdelphij flags |= O_NONBLOCK; 309225452Sdelphij if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 310163621Sdelphij pjdlog_common(LOG_DEBUG, 1, errno, 311163621Sdelphij "fcntl(F_SETFL, O_NONBLOCK) failed"); 312126756Smlaier return (errno); 313163621Sdelphij } 314126756Smlaier 315225452Sdelphij if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa, 316225452Sdelphij tctx->tc_sa.ss_len) == 0) { 317225452Sdelphij if (timeout == -1) 318126756Smlaier return (0); 319126756Smlaier error = 0; 320126756Smlaier goto done; 321126756Smlaier } 322126756Smlaier if (errno != EINPROGRESS) { 323126756Smlaier error = errno; 324126756Smlaier pjdlog_common(LOG_DEBUG, 1, errno, "connect() failed"); 325126756Smlaier goto done; 326126756Smlaier } 327126756Smlaier if (timeout == -1) 328126756Smlaier return (0); 329135183Smlaier return (tcp_connect_wait(ctx, timeout)); 330135183Smlaierdone: 331163621Sdelphij flags &= ~O_NONBLOCK; 332163621Sdelphij if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 333135183Smlaier if (error == 0) 334126756Smlaier error = errno; 335126756Smlaier pjdlog_common(LOG_DEBUG, 1, errno, 336126756Smlaier "fcntl(F_SETFL, ~O_NONBLOCK) failed"); 337126756Smlaier } 338126756Smlaier return (error); 339126756Smlaier} 340126756Smlaier 341126756Smlaierstatic int 342126756Smlaiertcp_connect_wait(void *ctx, int timeout) 343126756Smlaier{ 344163621Sdelphij struct tcp_ctx *tctx = ctx; 345163621Sdelphij struct timeval tv; 346163621Sdelphij fd_set fdset; 347126756Smlaier socklen_t esize; 348126756Smlaier int error, flags, ret; 349135183Smlaier 350126756Smlaier PJDLOG_ASSERT(tctx != NULL); 351126756Smlaier PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 352126756Smlaier PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT); 353126756Smlaier PJDLOG_ASSERT(tctx->tc_fd >= 0); 354126756Smlaier PJDLOG_ASSERT(timeout >= 0); 355126756Smlaier 356126756Smlaier tv.tv_sec = timeout; 357126756Smlaier tv.tv_usec = 0; 358126756Smlaieragain: 359126756Smlaier FD_ZERO(&fdset); 360135183Smlaier FD_SET(tctx->tc_fd, &fdset); 361135183Smlaier ret = select(tctx->tc_fd + 1, NULL, &fdset, NULL, &tv); 362135183Smlaier if (ret == 0) { 363135183Smlaier error = ETIMEDOUT; 364126756Smlaier goto done; 365126756Smlaier } else if (ret == -1) { 366135183Smlaier if (errno == EINTR) 367135183Smlaier goto again; 368135183Smlaier error = errno; 369126756Smlaier pjdlog_common(LOG_DEBUG, 1, errno, "select() failed"); 370135183Smlaier goto done; 371126756Smlaier } 372126756Smlaier PJDLOG_ASSERT(ret > 0); 373135183Smlaier PJDLOG_ASSERT(FD_ISSET(tctx->tc_fd, &fdset)); 374225452Sdelphij esize = sizeof(error); 375135183Smlaier if (getsockopt(tctx->tc_fd, SOL_SOCKET, SO_ERROR, &error, 376135183Smlaier &esize) == -1) { 377135183Smlaier error = errno; 378135183Smlaier pjdlog_common(LOG_DEBUG, 1, errno, 379126756Smlaier "getsockopt(SO_ERROR) failed"); 380135183Smlaier goto done; 381135183Smlaier } 382135183Smlaier if (error != 0) { 383126756Smlaier pjdlog_common(LOG_DEBUG, 1, error, 384135183Smlaier "getsockopt(SO_ERROR) returned error"); 385135183Smlaier goto done; 386135183Smlaier } 387135183Smlaier error = 0; 388126756Smlaierdone: 389135183Smlaier flags = fcntl(tctx->tc_fd, F_GETFL); 390135183Smlaier if (flags == -1) { 391135183Smlaier if (error == 0) 392135183Smlaier error = errno; 393126756Smlaier pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed"); 394126756Smlaier return (error); 395126756Smlaier } 396135183Smlaier flags &= ~O_NONBLOCK; 397126756Smlaier if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 398126756Smlaier if (error == 0) 399126756Smlaier error = errno; 400135183Smlaier pjdlog_common(LOG_DEBUG, 1, errno, 401126756Smlaier "fcntl(F_SETFL, ~O_NONBLOCK) failed"); 402126756Smlaier } 403126756Smlaier return (error); 404126756Smlaier} 405126756Smlaier 406126756Smlaierstatic int 407126756Smlaiertcp_server(const char *addr, void **ctxp) 408126756Smlaier{ 409135183Smlaier struct tcp_ctx *tctx; 410135183Smlaier int ret, val; 411126756Smlaier 412126756Smlaier ret = tcp_setup_new(addr, TCP_SIDE_SERVER_LISTEN, ctxp); 413130151Sschweikh if (ret != 0) 414126756Smlaier return (ret); 415126756Smlaier 416126756Smlaier tctx = *ctxp; 417126756Smlaier 418126756Smlaier val = 1; 419126756Smlaier /* Ignore failure. */ 420135183Smlaier (void)setsockopt(tctx->tc_fd, SOL_SOCKET, SO_REUSEADDR, &val, 421135183Smlaier sizeof(val)); 422135183Smlaier 423135183Smlaier PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 424135183Smlaier 425135183Smlaier if (bind(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa, 426135183Smlaier tctx->tc_sa.ss_len) < 0) { 427126756Smlaier ret = errno; 428135183Smlaier tcp_close(tctx); 429135183Smlaier return (ret); 430135183Smlaier } 431135183Smlaier if (listen(tctx->tc_fd, 8) < 0) { 432135183Smlaier ret = errno; 433135183Smlaier tcp_close(tctx); 434135183Smlaier return (ret); 435135183Smlaier } 436135183Smlaier 437135183Smlaier return (0); 438244647Sdelphij} 439244647Sdelphij 440126756Smlaierstatic int 441126756Smlaiertcp_accept(void *ctx, void **newctxp) 442135183Smlaier{ 443135183Smlaier struct tcp_ctx *tctx = ctx; 444135183Smlaier struct tcp_ctx *newtctx; 445135183Smlaier socklen_t fromlen; 446135183Smlaier int ret; 447126756Smlaier 448163621Sdelphij PJDLOG_ASSERT(tctx != NULL); 449163621Sdelphij PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 450163621Sdelphij PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_SERVER_LISTEN); 451163621Sdelphij PJDLOG_ASSERT(tctx->tc_fd >= 0); 452163621Sdelphij PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); 453135183Smlaier 454135183Smlaier newtctx = malloc(sizeof(*newtctx)); 455135183Smlaier if (newtctx == NULL) 456126756Smlaier return (errno); 457126756Smlaier 458126756Smlaier fromlen = tctx->tc_sa.ss_len; 459126756Smlaier newtctx->tc_fd = accept(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa, 460126756Smlaier &fromlen); 461126756Smlaier if (newtctx->tc_fd < 0) { 462126756Smlaier ret = errno; 463126756Smlaier free(newtctx); 464126756Smlaier return (ret); 465126756Smlaier } 466126756Smlaier 467126756Smlaier newtctx->tc_side = TCP_SIDE_SERVER_WORK; 468126756Smlaier newtctx->tc_magic = TCP_CTX_MAGIC; 469126756Smlaier *newctxp = newtctx; 470126756Smlaier 471135183Smlaier return (0); 472126756Smlaier} 473135183Smlaier 474135183Smlaierstatic int 475135183Smlaiertcp_wrap(int fd, bool client, void **ctxp) 476135183Smlaier{ 477163621Sdelphij 478126756Smlaier return (tcp_setup_wrap(fd, 479126756Smlaier client ? TCP_SIDE_CLIENT : TCP_SIDE_SERVER_WORK, ctxp)); 480126756Smlaier} 481126756Smlaier 482126756Smlaierstatic int 483126756Smlaiertcp_send(void *ctx, const unsigned char *data, size_t size, int fd) 484126756Smlaier{ 485126756Smlaier struct tcp_ctx *tctx = ctx; 486126756Smlaier 487126756Smlaier PJDLOG_ASSERT(tctx != NULL); 488126756Smlaier PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 489126756Smlaier PJDLOG_ASSERT(tctx->tc_fd >= 0); 490126756Smlaier PJDLOG_ASSERT(fd == -1); 491163621Sdelphij 492126756Smlaier return (proto_common_send(tctx->tc_fd, data, size, -1)); 493126756Smlaier} 494126756Smlaier 495126756Smlaierstatic int 496126756Smlaiertcp_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 497126756Smlaier{ 498126756Smlaier struct tcp_ctx *tctx = ctx; 499126756Smlaier 500126756Smlaier PJDLOG_ASSERT(tctx != NULL); 501126756Smlaier PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 502126756Smlaier PJDLOG_ASSERT(tctx->tc_fd >= 0); 503126756Smlaier PJDLOG_ASSERT(fdp == NULL); 504126756Smlaier 505135183Smlaier return (proto_common_recv(tctx->tc_fd, data, size, NULL)); 506135183Smlaier} 507126756Smlaier 508126756Smlaierstatic int 509126756Smlaiertcp_descriptor(const void *ctx) 510126756Smlaier{ 511126756Smlaier const struct tcp_ctx *tctx = ctx; 512126756Smlaier 513126756Smlaier PJDLOG_ASSERT(tctx != NULL); 514126756Smlaier PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 515126756Smlaier 516126756Smlaier return (tctx->tc_fd); 517126756Smlaier} 518126756Smlaier 519126756Smlaierstatic bool 520135183Smlaiertcp_address_match(const void *ctx, const char *addr) 521126756Smlaier{ 522135183Smlaier const struct tcp_ctx *tctx = ctx; 523135183Smlaier struct sockaddr_storage sa1, sa2; 524135183Smlaier socklen_t salen; 525126756Smlaier 526135183Smlaier PJDLOG_ASSERT(tctx != NULL); 527163621Sdelphij PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 528135183Smlaier 529126756Smlaier if (tcp_addr(addr, PROTO_TCP_DEFAULT_PORT, &sa1) != 0) 530126756Smlaier return (false); 531126756Smlaier 532126756Smlaier salen = sizeof(sa2); 533163621Sdelphij if (getpeername(tctx->tc_fd, (struct sockaddr *)&sa2, &salen) < 0) 534126756Smlaier return (false); 535135183Smlaier 536135183Smlaier if (sa1.ss_family != sa2.ss_family || sa1.ss_len != sa2.ss_len) 537135183Smlaier return (false); 538163621Sdelphij 539135183Smlaier switch (sa1.ss_family) { 540135183Smlaier case AF_INET: 541135183Smlaier { 542135183Smlaier struct sockaddr_in *sin1, *sin2; 543135183Smlaier 544135183Smlaier sin1 = (struct sockaddr_in *)&sa1; 545135183Smlaier sin2 = (struct sockaddr_in *)&sa2; 546163621Sdelphij 547163621Sdelphij return (memcmp(&sin1->sin_addr, &sin2->sin_addr, 548163621Sdelphij sizeof(sin1->sin_addr)) == 0); 549163621Sdelphij } 550135183Smlaier case AF_INET6: 551135183Smlaier { 552135183Smlaier struct sockaddr_in6 *sin1, *sin2; 553135183Smlaier 554135183Smlaier sin1 = (struct sockaddr_in6 *)&sa1; 555135183Smlaier sin2 = (struct sockaddr_in6 *)&sa2; 556135183Smlaier 557135183Smlaier return (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, 558135183Smlaier sizeof(sin1->sin6_addr)) == 0); 559135183Smlaier } 560135183Smlaier default: 561135183Smlaier return (false); 562135183Smlaier } 563126756Smlaier} 564126756Smlaier 565126756Smlaierstatic void 566126756Smlaiertcp_local_address(const void *ctx, char *addr, size_t size) 567126756Smlaier{ 568126756Smlaier const struct tcp_ctx *tctx = ctx; 569126756Smlaier struct sockaddr_storage sa; 570126756Smlaier socklen_t salen; 571126756Smlaier 572126756Smlaier PJDLOG_ASSERT(tctx != NULL); 573135183Smlaier PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 574135183Smlaier 575135183Smlaier salen = sizeof(sa); 576135183Smlaier if (getsockname(tctx->tc_fd, (struct sockaddr *)&sa, &salen) < 0) { 577135183Smlaier PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 578135183Smlaier return; 579135183Smlaier } 580135183Smlaier PJDLOG_VERIFY(snprintf(addr, size, "tcp://%S", &sa) < (ssize_t)size); 581163621Sdelphij} 582135183Smlaier 583163621Sdelphijstatic void 584163621Sdelphijtcp_remote_address(const void *ctx, char *addr, size_t size) 585126756Smlaier{ 586126756Smlaier const struct tcp_ctx *tctx = ctx; 587126756Smlaier struct sockaddr_storage sa; 588126756Smlaier socklen_t salen; 589126756Smlaier 590126756Smlaier PJDLOG_ASSERT(tctx != NULL); 591126756Smlaier PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 592126756Smlaier 593126756Smlaier salen = sizeof(sa); 594126756Smlaier if (getpeername(tctx->tc_fd, (struct sockaddr *)&sa, &salen) < 0) { 595126756Smlaier PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 596126756Smlaier return; 597126756Smlaier } 598126756Smlaier PJDLOG_VERIFY(snprintf(addr, size, "tcp://%S", &sa) < (ssize_t)size); 599135183Smlaier} 600126756Smlaier 601126756Smlaierstatic void 602135183Smlaiertcp_close(void *ctx) 603126756Smlaier{ 604135183Smlaier struct tcp_ctx *tctx = ctx; 605135183Smlaier 606135183Smlaier PJDLOG_ASSERT(tctx != NULL); 607126756Smlaier PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC); 608126756Smlaier 609126756Smlaier if (tctx->tc_fd >= 0) 610126756Smlaier close(tctx->tc_fd); 611126756Smlaier tctx->tc_magic = 0; 612126756Smlaier free(tctx); 613126756Smlaier} 614126756Smlaier 615126756Smlaierstatic struct proto tcp_proto = { 616163621Sdelphij .prt_name = "tcp", 617163621Sdelphij .prt_client = tcp_client, 618163621Sdelphij .prt_connect = tcp_connect, 619163621Sdelphij .prt_connect_wait = tcp_connect_wait, 620126756Smlaier .prt_server = tcp_server, 621126756Smlaier .prt_accept = tcp_accept, 622126756Smlaier .prt_wrap = tcp_wrap, 623126756Smlaier .prt_send = tcp_send, 624126756Smlaier .prt_recv = tcp_recv, 625126756Smlaier .prt_descriptor = tcp_descriptor, 626126756Smlaier .prt_address_match = tcp_address_match, 627135183Smlaier .prt_local_address = tcp_local_address, 628163621Sdelphij .prt_remote_address = tcp_remote_address, 629163621Sdelphij .prt_close = tcp_close 630126756Smlaier}; 631126756Smlaier 632126756Smlaierstatic __constructor void 633163621Sdelphijtcp_ctor(void) 634163621Sdelphij{ 635163621Sdelphij 636163621Sdelphij proto_register(&tcp_proto, true); 637126756Smlaier} 638163621Sdelphij