proto_tcp.c revision 218193
1161748Scperciva/*- 2161748Scperciva * Copyright (c) 2009-2010 The FreeBSD Foundation 3161748Scperciva * All rights reserved. 4173441Scperciva * 5161748Scperciva * This software was developed by Pawel Jakub Dawidek under sponsorship from 6161748Scperciva * the FreeBSD Foundation. 7161748Scperciva * 8161748Scperciva * Redistribution and use in source and binary forms, with or without 9161748Scperciva * modification, are permitted provided that the following conditions 10161748Scperciva * are met: 11161748Scperciva * 1. Redistributions of source code must retain the above copyright 12161748Scperciva * notice, this list of conditions and the following disclaimer. 13161748Scperciva * 2. Redistributions in binary form must reproduce the above copyright 14161748Scperciva * notice, this list of conditions and the following disclaimer in the 15161748Scperciva * documentation and/or other materials provided with the distribution. 16161748Scperciva * 17161748Scperciva * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18161748Scperciva * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19161748Scperciva * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20161748Scperciva * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21161748Scperciva * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22161748Scperciva * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23161748Scperciva * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24161748Scperciva * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25161748Scperciva * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26161748Scperciva * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27161748Scperciva * SUCH DAMAGE. 28161748Scperciva */ 29161748Scperciva 30161748Scperciva#include <sys/cdefs.h> 31161748Scperciva__FBSDID("$FreeBSD: head/sbin/hastd/proto_tcp4.c 218193 2011-02-02 15:46:28Z pjd $"); 32161748Scperciva 33161748Scperciva#include <sys/param.h> /* MAXHOSTNAMELEN */ 34161748Scperciva 35161748Scperciva#include <netinet/in.h> 36161748Scperciva#include <netinet/tcp.h> 37161748Scperciva 38161748Scperciva#include <errno.h> 39161748Scperciva#include <fcntl.h> 40161748Scperciva#include <netdb.h> 41161748Scperciva#include <stdbool.h> 42161748Scperciva#include <stdint.h> 43161748Scperciva#include <stdio.h> 44161748Scperciva#include <string.h> 45161748Scperciva#include <unistd.h> 46161748Scperciva 47173564Scperciva#include "hast.h" 48161748Scperciva#include "pjdlog.h" 49161748Scperciva#include "proto_impl.h" 50161748Scperciva#include "subr.h" 51161748Scperciva 52161748Scperciva#define TCP4_CTX_MAGIC 0x7c441c 53161748Scpercivastruct tcp4_ctx { 54161748Scperciva int tc_magic; 55161748Scperciva struct sockaddr_in tc_sin; 56173564Scperciva int tc_fd; 57173564Scperciva int tc_side; 58161748Scperciva#define TCP4_SIDE_CLIENT 0 59181142Scperciva#define TCP4_SIDE_SERVER_LISTEN 1 60161748Scperciva#define TCP4_SIDE_SERVER_WORK 2 61161748Scperciva}; 62161748Scperciva 63161748Scpercivastatic int tcp4_connect_wait(void *ctx, int timeout); 64161748Scpercivastatic void tcp4_close(void *ctx); 65161748Scperciva 66161748Scpercivastatic in_addr_t 67161748Scpercivastr2ip(const char *str) 68161748Scperciva{ 69161748Scperciva struct hostent *hp; 70161748Scperciva in_addr_t ip; 71161748Scperciva 72161748Scperciva ip = inet_addr(str); 73161748Scperciva if (ip != INADDR_NONE) { 74161748Scperciva /* It is a valid IP address. */ 75161748Scperciva return (ip); 76161748Scperciva } 77161748Scperciva /* Check if it is a valid host name. */ 78161748Scperciva hp = gethostbyname(str); 79161748Scperciva if (hp == NULL) 80161748Scperciva return (INADDR_NONE); 81161748Scperciva return (((struct in_addr *)(void *)hp->h_addr)->s_addr); 82161748Scperciva} 83161748Scperciva 84161748Scperciva/* 85161748Scperciva * Function converts the given string to unsigned number. 86161748Scperciva */ 87161748Scpercivastatic int 88161748Scpercivanumfromstr(const char *str, intmax_t minnum, intmax_t maxnum, intmax_t *nump) 89161748Scperciva{ 90181142Scperciva intmax_t digit, num; 91196392Ssimon 92161748Scperciva if (str[0] == '\0') 93161748Scperciva goto invalid; /* Empty string. */ 94161748Scperciva num = 0; 95161748Scperciva for (; *str != '\0'; str++) { 96161748Scperciva if (*str < '0' || *str > '9') 97161748Scperciva goto invalid; /* Non-digit character. */ 98161748Scperciva digit = *str - '0'; 99161748Scperciva if (num > num * 10 + digit) 100161748Scperciva goto invalid; /* Overflow. */ 101161748Scperciva num = num * 10 + digit; 102161748Scperciva if (num > maxnum) 103161748Scperciva goto invalid; /* Too big. */ 104161748Scperciva } 105161748Scperciva if (num < minnum) 106161748Scperciva goto invalid; /* Too small. */ 107161748Scperciva *nump = num; 108161748Scperciva return (0); 109161748Scpercivainvalid: 110161748Scperciva errno = EINVAL; 111161748Scperciva return (-1); 112161748Scperciva} 113161748Scperciva 114161748Scpercivastatic int 115161748Scpercivatcp4_addr(const char *addr, struct sockaddr_in *sinp) 116161748Scperciva{ 117161748Scperciva char iporhost[MAXHOSTNAMELEN]; 118161748Scperciva const char *pp; 119161748Scperciva size_t size; 120161748Scperciva in_addr_t ip; 121161748Scperciva 122161748Scperciva if (addr == NULL) 123161748Scperciva return (-1); 124161748Scperciva 125161748Scperciva if (strncasecmp(addr, "tcp4://", 7) == 0) 126161748Scperciva addr += 7; 127161748Scperciva else if (strncasecmp(addr, "tcp://", 6) == 0) 128161748Scperciva addr += 6; 129161748Scperciva else { 130161748Scperciva /* 131161748Scperciva * Because TCP4 is the default assume IP or host is given without 132161748Scperciva * prefix. 133161748Scperciva */ 134161748Scperciva } 135161748Scperciva 136161748Scperciva sinp->sin_family = AF_INET; 137161748Scperciva sinp->sin_len = sizeof(*sinp); 138161748Scperciva /* Extract optional port. */ 139161748Scperciva pp = strrchr(addr, ':'); 140161748Scperciva if (pp == NULL) { 141161748Scperciva /* Port not given, use the default. */ 142161748Scperciva sinp->sin_port = htons(HASTD_PORT); 143161748Scperciva } else { 144161748Scperciva intmax_t port; 145161748Scperciva 146161748Scperciva if (numfromstr(pp + 1, 1, 65535, &port) < 0) 147161748Scperciva return (errno); 148161748Scperciva sinp->sin_port = htons(port); 149161748Scperciva } 150161748Scperciva /* Extract host name or IP address. */ 151161748Scperciva if (pp == NULL) { 152161748Scperciva size = sizeof(iporhost); 153161748Scperciva if (strlcpy(iporhost, addr, size) >= size) 154161748Scperciva return (ENAMETOOLONG); 155161748Scperciva } else { 156161748Scperciva size = (size_t)(pp - addr + 1); 157161748Scperciva if (size > sizeof(iporhost)) 158161748Scperciva return (ENAMETOOLONG); 159161748Scperciva (void)strlcpy(iporhost, addr, size); 160161748Scperciva } 161161748Scperciva /* Convert string (IP address or host name) to in_addr_t. */ 162161748Scperciva ip = str2ip(iporhost); 163161748Scperciva if (ip == INADDR_NONE) 164161748Scperciva return (EINVAL); 165161748Scperciva sinp->sin_addr.s_addr = ip; 166161748Scperciva 167161748Scperciva return (0); 168161748Scperciva} 169161748Scperciva 170161748Scpercivastatic int 171161748Scpercivatcp4_common_setup(const char *addr, void **ctxp, int side) 172161748Scperciva{ 173161748Scperciva struct tcp4_ctx *tctx; 174161748Scperciva int ret, nodelay; 175161748Scperciva 176161748Scperciva tctx = malloc(sizeof(*tctx)); 177161748Scperciva if (tctx == NULL) 178161748Scperciva return (errno); 179161748Scperciva 180161748Scperciva /* Parse given address. */ 181161748Scperciva if ((ret = tcp4_addr(addr, &tctx->tc_sin)) != 0) { 182161748Scperciva free(tctx); 183161748Scperciva return (ret); 184161748Scperciva } 185161748Scperciva 186161748Scperciva tctx->tc_fd = socket(AF_INET, SOCK_STREAM, 0); 187161748Scperciva if (tctx->tc_fd == -1) { 188161748Scperciva ret = errno; 189161748Scperciva free(tctx); 190161748Scperciva return (ret); 191161748Scperciva } 192161748Scperciva 193161748Scperciva /* Socket settings. */ 194161748Scperciva nodelay = 1; 195161748Scperciva if (setsockopt(tctx->tc_fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, 196161748Scperciva sizeof(nodelay)) == -1) { 197161748Scperciva pjdlog_warning("Unable to set TCP_NOELAY on %s", addr); 198161748Scperciva } 199161748Scperciva 200161748Scperciva tctx->tc_side = side; 201161748Scperciva tctx->tc_magic = TCP4_CTX_MAGIC; 202161748Scperciva *ctxp = tctx; 203161748Scperciva 204161748Scperciva return (0); 205161748Scperciva} 206161748Scperciva 207161748Scpercivastatic int 208161748Scpercivatcp4_client(const char *addr, void **ctxp) 209161748Scperciva{ 210161748Scperciva 211161748Scperciva return (tcp4_common_setup(addr, ctxp, TCP4_SIDE_CLIENT)); 212161748Scperciva} 213161748Scperciva 214161748Scpercivastatic int 215161748Scpercivatcp4_connect(void *ctx, int timeout) 216161748Scperciva{ 217161748Scperciva struct tcp4_ctx *tctx = ctx; 218161748Scperciva int error, flags; 219161748Scperciva 220161748Scperciva PJDLOG_ASSERT(tctx != NULL); 221161748Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 222161748Scperciva PJDLOG_ASSERT(tctx->tc_side == TCP4_SIDE_CLIENT); 223161748Scperciva PJDLOG_ASSERT(tctx->tc_fd >= 0); 224161748Scperciva PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC); 225161748Scperciva PJDLOG_ASSERT(timeout >= -1); 226161748Scperciva 227181142Scperciva flags = fcntl(tctx->tc_fd, F_GETFL); 228181142Scperciva if (flags == -1) { 229181142Scperciva KEEP_ERRNO(pjdlog_common(LOG_DEBUG, 1, errno, 230181142Scperciva "fcntl(F_GETFL) failed")); 231181142Scperciva return (errno); 232181142Scperciva } 233181142Scperciva /* 234161748Scperciva * We make socket non-blocking so we can handle connection timeout 235161748Scperciva * manually. 236161748Scperciva */ 237161748Scperciva flags |= O_NONBLOCK; 238161748Scperciva if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 239161748Scperciva KEEP_ERRNO(pjdlog_common(LOG_DEBUG, 1, errno, 240161748Scperciva "fcntl(F_SETFL, O_NONBLOCK) failed")); 241161748Scperciva return (errno); 242173564Scperciva } 243173564Scperciva 244173564Scperciva if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin, 245173564Scperciva sizeof(tctx->tc_sin)) == 0) { 246173564Scperciva if (timeout == -1) 247173564Scperciva return (0); 248173564Scperciva error = 0; 249173564Scperciva goto done; 250161748Scperciva } 251161748Scperciva if (errno != EINPROGRESS) { 252161748Scperciva error = errno; 253161748Scperciva pjdlog_common(LOG_DEBUG, 1, errno, "connect() failed"); 254161748Scperciva goto done; 255161748Scperciva } 256161748Scperciva if (timeout == -1) 257161748Scperciva return (0); 258161748Scperciva return (tcp4_connect_wait(ctx, timeout)); 259173564Scpercivadone: 260173564Scperciva flags &= ~O_NONBLOCK; 261173564Scperciva if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 262173564Scperciva if (error == 0) 263173564Scperciva error = errno; 264173564Scperciva pjdlog_common(LOG_DEBUG, 1, errno, 265173564Scperciva "fcntl(F_SETFL, ~O_NONBLOCK) failed"); 266173564Scperciva } 267173564Scperciva return (error); 268173564Scperciva} 269173564Scperciva 270173564Scpercivastatic int 271173564Scpercivatcp4_connect_wait(void *ctx, int timeout) 272173564Scperciva{ 273173564Scperciva struct tcp4_ctx *tctx = ctx; 274173564Scperciva struct timeval tv; 275173564Scperciva fd_set fdset; 276173564Scperciva socklen_t esize; 277173564Scperciva int error, flags, ret; 278173564Scperciva 279173564Scperciva PJDLOG_ASSERT(tctx != NULL); 280173564Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 281173564Scperciva PJDLOG_ASSERT(tctx->tc_side == TCP4_SIDE_CLIENT); 282173564Scperciva PJDLOG_ASSERT(tctx->tc_fd >= 0); 283173564Scperciva PJDLOG_ASSERT(timeout >= 0); 284173564Scperciva 285173564Scperciva tv.tv_sec = timeout; 286173564Scperciva tv.tv_usec = 0; 287197618Scpercivaagain: 288197618Scperciva FD_ZERO(&fdset); 289197618Scperciva FD_SET(tctx->tc_fd, &fdset); 290173564Scperciva ret = select(tctx->tc_fd + 1, NULL, &fdset, NULL, &tv); 291173564Scperciva if (ret == 0) { 292161748Scperciva error = ETIMEDOUT; 293161748Scperciva goto done; 294161748Scperciva } else if (ret == -1) { 295161748Scperciva if (errno == EINTR) 296161748Scperciva goto again; 297161748Scperciva error = errno; 298161748Scperciva pjdlog_common(LOG_DEBUG, 1, errno, "select() failed"); 299161748Scperciva goto done; 300161748Scperciva } 301161748Scperciva PJDLOG_ASSERT(ret > 0); 302161748Scperciva PJDLOG_ASSERT(FD_ISSET(tctx->tc_fd, &fdset)); 303161748Scperciva esize = sizeof(error); 304161748Scperciva if (getsockopt(tctx->tc_fd, SOL_SOCKET, SO_ERROR, &error, 305161748Scperciva &esize) == -1) { 306161748Scperciva error = errno; 307161748Scperciva pjdlog_common(LOG_DEBUG, 1, errno, 308161748Scperciva "getsockopt(SO_ERROR) failed"); 309161748Scperciva goto done; 310161748Scperciva } 311161748Scperciva if (error != 0) { 312161748Scperciva pjdlog_common(LOG_DEBUG, 1, error, 313161748Scperciva "getsockopt(SO_ERROR) returned error"); 314196392Ssimon goto done; 315196392Ssimon } 316196392Ssimon error = 0; 317196392Ssimondone: 318196392Ssimon flags = fcntl(tctx->tc_fd, F_GETFL); 319196392Ssimon if (flags == -1) { 320196392Ssimon if (error == 0) 321196392Ssimon error = errno; 322196392Ssimon pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed"); 323196392Ssimon return (error); 324196392Ssimon } 325196392Ssimon flags &= ~O_NONBLOCK; 326196392Ssimon if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { 327196392Ssimon if (error == 0) 328196392Ssimon error = errno; 329196392Ssimon pjdlog_common(LOG_DEBUG, 1, errno, 330196392Ssimon "fcntl(F_SETFL, ~O_NONBLOCK) failed"); 331196392Ssimon } 332196392Ssimon return (error); 333196392Ssimon} 334196392Ssimon 335196392Ssimonstatic int 336196392Ssimontcp4_server(const char *addr, void **ctxp) 337196392Ssimon{ 338196392Ssimon struct tcp4_ctx *tctx; 339196392Ssimon int ret, val; 340196392Ssimon 341196392Ssimon ret = tcp4_common_setup(addr, ctxp, TCP4_SIDE_SERVER_LISTEN); 342196392Ssimon if (ret != 0) 343196392Ssimon return (ret); 344196392Ssimon 345196392Ssimon tctx = *ctxp; 346196392Ssimon 347196392Ssimon val = 1; 348196392Ssimon /* Ignore failure. */ 349196392Ssimon (void)setsockopt(tctx->tc_fd, SOL_SOCKET, SO_REUSEADDR, &val, 350196392Ssimon sizeof(val)); 351196392Ssimon 352196392Ssimon if (bind(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin, 353196392Ssimon sizeof(tctx->tc_sin)) < 0) { 354196392Ssimon ret = errno; 355196392Ssimon tcp4_close(tctx); 356196392Ssimon return (ret); 357196392Ssimon } 358196392Ssimon if (listen(tctx->tc_fd, 8) < 0) { 359196392Ssimon ret = errno; 360196392Ssimon tcp4_close(tctx); 361196392Ssimon return (ret); 362196392Ssimon } 363196392Ssimon 364196392Ssimon return (0); 365196392Ssimon} 366196392Ssimon 367196392Ssimonstatic int 368196392Ssimontcp4_accept(void *ctx, void **newctxp) 369196392Ssimon{ 370196392Ssimon struct tcp4_ctx *tctx = ctx; 371196392Ssimon struct tcp4_ctx *newtctx; 372196392Ssimon socklen_t fromlen; 373196392Ssimon int ret; 374196392Ssimon 375196392Ssimon PJDLOG_ASSERT(tctx != NULL); 376196392Ssimon PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 377196392Ssimon PJDLOG_ASSERT(tctx->tc_side == TCP4_SIDE_SERVER_LISTEN); 378161748Scperciva PJDLOG_ASSERT(tctx->tc_fd >= 0); 379161748Scperciva 380161748Scperciva newtctx = malloc(sizeof(*newtctx)); 381161748Scperciva if (newtctx == NULL) 382161748Scperciva return (errno); 383161748Scperciva 384161748Scperciva fromlen = sizeof(tctx->tc_sin); 385161748Scperciva newtctx->tc_fd = accept(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin, 386161748Scperciva &fromlen); 387161748Scperciva if (newtctx->tc_fd < 0) { 388161748Scperciva ret = errno; 389161748Scperciva free(newtctx); 390161748Scperciva return (ret); 391161748Scperciva } 392161748Scperciva 393161748Scperciva newtctx->tc_side = TCP4_SIDE_SERVER_WORK; 394161748Scperciva newtctx->tc_magic = TCP4_CTX_MAGIC; 395161748Scperciva *newctxp = newtctx; 396161748Scperciva 397161748Scperciva return (0); 398161748Scperciva} 399161748Scperciva 400161748Scpercivastatic int 401161748Scpercivatcp4_send(void *ctx, const unsigned char *data, size_t size) 402161748Scperciva{ 403161748Scperciva struct tcp4_ctx *tctx = ctx; 404161748Scperciva 405161748Scperciva PJDLOG_ASSERT(tctx != NULL); 406161748Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 407161748Scperciva PJDLOG_ASSERT(tctx->tc_fd >= 0); 408161748Scperciva 409161748Scperciva return (proto_common_send(tctx->tc_fd, data, size)); 410161748Scperciva} 411161748Scperciva 412161748Scpercivastatic int 413161748Scpercivatcp4_recv(void *ctx, unsigned char *data, size_t size) 414161748Scperciva{ 415161748Scperciva struct tcp4_ctx *tctx = ctx; 416161748Scperciva 417161748Scperciva PJDLOG_ASSERT(tctx != NULL); 418161748Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 419161748Scperciva PJDLOG_ASSERT(tctx->tc_fd >= 0); 420161748Scperciva 421161748Scperciva return (proto_common_recv(tctx->tc_fd, data, size)); 422161748Scperciva} 423161748Scperciva 424161748Scpercivastatic int 425161748Scpercivatcp4_descriptor(const void *ctx) 426161748Scperciva{ 427161748Scperciva const struct tcp4_ctx *tctx = ctx; 428161748Scperciva 429161748Scperciva PJDLOG_ASSERT(tctx != NULL); 430161748Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 431161748Scperciva 432173564Scperciva return (tctx->tc_fd); 433173564Scperciva} 434173564Scperciva 435173564Scpercivastatic void 436161748Scpercivasin2str(struct sockaddr_in *sinp, char *addr, size_t size) 437161748Scperciva{ 438161748Scperciva in_addr_t ip; 439161748Scperciva unsigned int port; 440161748Scperciva 441161748Scperciva PJDLOG_ASSERT(addr != NULL); 442161748Scperciva PJDLOG_ASSERT(sinp->sin_family == AF_INET); 443161748Scperciva 444161748Scperciva ip = ntohl(sinp->sin_addr.s_addr); 445161748Scperciva port = ntohs(sinp->sin_port); 446161748Scperciva PJDLOG_VERIFY(snprintf(addr, size, "tcp4://%u.%u.%u.%u:%u", 447161748Scperciva ((ip >> 24) & 0xff), ((ip >> 16) & 0xff), ((ip >> 8) & 0xff), 448161748Scperciva (ip & 0xff), port) < (ssize_t)size); 449161748Scperciva} 450161748Scperciva 451161748Scpercivastatic bool 452161748Scpercivatcp4_address_match(const void *ctx, const char *addr) 453161748Scperciva{ 454181142Scperciva const struct tcp4_ctx *tctx = ctx; 455161748Scperciva struct sockaddr_in sin; 456161748Scperciva socklen_t sinlen; 457161748Scperciva in_addr_t ip1, ip2; 458161748Scperciva 459161748Scperciva PJDLOG_ASSERT(tctx != NULL); 460161748Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 461161748Scperciva 462161748Scperciva if (tcp4_addr(addr, &sin) != 0) 463161748Scperciva return (false); 464161748Scperciva ip1 = sin.sin_addr.s_addr; 465161748Scperciva 466161748Scperciva sinlen = sizeof(sin); 467161748Scperciva if (getpeername(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0) 468161748Scperciva return (false); 469161748Scperciva ip2 = sin.sin_addr.s_addr; 470161748Scperciva 471161748Scperciva return (ip1 == ip2); 472161748Scperciva} 473161748Scperciva 474161748Scpercivastatic void 475161748Scpercivatcp4_local_address(const void *ctx, char *addr, size_t size) 476161748Scperciva{ 477161748Scperciva const struct tcp4_ctx *tctx = ctx; 478161748Scperciva struct sockaddr_in sin; 479161748Scperciva socklen_t sinlen; 480161748Scperciva 481161748Scperciva PJDLOG_ASSERT(tctx != NULL); 482161748Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 483161748Scperciva 484161748Scperciva sinlen = sizeof(sin); 485161748Scperciva if (getsockname(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0) { 486161748Scperciva PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 487161748Scperciva return; 488161748Scperciva } 489161748Scperciva sin2str(&sin, addr, size); 490161748Scperciva} 491161748Scperciva 492161748Scpercivastatic void 493161748Scpercivatcp4_remote_address(const void *ctx, char *addr, size_t size) 494161748Scperciva{ 495161748Scperciva const struct tcp4_ctx *tctx = ctx; 496161748Scperciva struct sockaddr_in sin; 497161748Scperciva socklen_t sinlen; 498161748Scperciva 499161748Scperciva PJDLOG_ASSERT(tctx != NULL); 500161748Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 501161748Scperciva 502161748Scperciva sinlen = sizeof(sin); 503161748Scperciva if (getpeername(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0) { 504161748Scperciva PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 505161748Scperciva return; 506161748Scperciva } 507161748Scperciva sin2str(&sin, addr, size); 508161748Scperciva} 509161748Scperciva 510161748Scpercivastatic void 511161748Scpercivatcp4_close(void *ctx) 512161748Scperciva{ 513161748Scperciva struct tcp4_ctx *tctx = ctx; 514161748Scperciva 515161748Scperciva PJDLOG_ASSERT(tctx != NULL); 516161748Scperciva PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC); 517161748Scperciva 518161748Scperciva if (tctx->tc_fd >= 0) 519161748Scperciva close(tctx->tc_fd); 520161748Scperciva tctx->tc_magic = 0; 521161748Scperciva free(tctx); 522161748Scperciva} 523161748Scperciva 524161748Scpercivastatic struct hast_proto tcp4_proto = { 525161748Scperciva .hp_name = "tcp4", 526161748Scperciva .hp_client = tcp4_client, 527161748Scperciva .hp_connect = tcp4_connect, 528161748Scperciva .hp_connect_wait = tcp4_connect_wait, 529161748Scperciva .hp_server = tcp4_server, 530173564Scperciva .hp_accept = tcp4_accept, 531196392Ssimon .hp_send = tcp4_send, 532196392Ssimon .hp_recv = tcp4_recv, 533196392Ssimon .hp_descriptor = tcp4_descriptor, 534161748Scperciva .hp_address_match = tcp4_address_match, 535161748Scperciva .hp_local_address = tcp4_local_address, 536161748Scperciva .hp_remote_address = tcp4_remote_address, 537161748Scperciva .hp_close = tcp4_close 538161748Scperciva}; 539161748Scperciva 540161748Scpercivastatic __constructor void 541161748Scpercivatcp4_ctor(void) 542161748Scperciva{ 543161748Scperciva 544161748Scperciva proto_register(&tcp4_proto, true); 545161748Scperciva} 546161748Scperciva