test_common.c revision 65c5d502
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */ 2#if __GNUC__ 3#define _GNU_SOURCE /* For struct in6_pktinfo */ 4#endif 5#include <assert.h> 6#include <errno.h> 7#include <string.h> 8#include <stdlib.h> 9#include <stdio.h> 10#include <sys/types.h> 11#if defined(__APPLE__) 12# define __APPLE_USE_RFC_3542 1 13#endif 14#ifndef WIN32 15#include <netinet/in.h> 16#include <netinet/ip.h> 17#include <arpa/inet.h> 18#include <sys/socket.h> 19#include <unistd.h> 20#else 21#include <Windows.h> 22#include <WinSock2.h> 23#include <MSWSock.h> 24#include<io.h> 25#pragma warning(disable:4996)//posix name deprecated 26#define close closesocket 27#endif 28#include <sys/stat.h> 29#include <sys/queue.h> 30#include <fcntl.h> 31 32#include "test_config.h" 33 34#if HAVE_REGEX 35#ifndef WIN32 36#include <regex.h> 37#else 38#include <pcreposix.h> 39#endif 40#endif 41 42#include <event2/event.h> 43 44#include "lsquic.h" 45#include "test_common.h" 46#include "prog.h" 47#include "lsxpack_header.h" 48 49#include "../src/liblsquic/lsquic_logger.h" 50 51#define MAX(a, b) ((a) > (b) ? (a) : (b)) 52#define MIN(a, b) ((a) < (b) ? (a) : (b)) 53 54#ifndef LSQUIC_USE_POOLS 55#define LSQUIC_USE_POOLS 1 56#endif 57 58#if __linux__ 59# define NDROPPED_SZ CMSG_SPACE(sizeof(uint32_t)) /* SO_RXQ_OVFL */ 60#else 61# define NDROPPED_SZ 0 62#endif 63 64#if __linux__ && defined(IP_RECVORIGDSTADDR) 65# define DST_MSG_SZ sizeof(struct sockaddr_in) 66#elif WIN32 67# define DST_MSG_SZ sizeof(struct sockaddr_in) 68#elif __linux__ 69# define DST_MSG_SZ sizeof(struct in_pktinfo) 70#else 71# define DST_MSG_SZ sizeof(struct sockaddr_in) 72#endif 73 74#if ECN_SUPPORTED 75#define ECN_SZ CMSG_SPACE(sizeof(int)) 76#else 77#define ECN_SZ 0 78#endif 79 80#define MAX_PACKET_SZ 0xffff 81 82#define CTL_SZ (CMSG_SPACE(MAX(DST_MSG_SZ, \ 83 sizeof(struct in6_pktinfo))) + NDROPPED_SZ + ECN_SZ) 84 85/* There are `n_alloc' elements in `vecs', `local_addresses', and 86 * `peer_addresses' arrays. `ctlmsg_data' is n_alloc * CTL_SZ. Each packets 87 * gets a single `vecs' element that points somewhere into `packet_data'. 88 * 89 * `n_alloc' is calculated at run-time based on the socket's receive buffer 90 * size. 91 */ 92struct packets_in 93{ 94 unsigned char *packet_data; 95 unsigned char *ctlmsg_data; 96#ifndef WIN32 97 struct iovec *vecs; 98#else 99 WSABUF *vecs; 100#endif 101#if ECN_SUPPORTED 102 int *ecn; 103#endif 104 struct sockaddr_storage *local_addresses, 105 *peer_addresses; 106 unsigned n_alloc; 107 unsigned data_sz; 108}; 109 110 111#if WIN32 112LPFN_WSARECVMSG pfnWSARecvMsg; 113GUID recvGuid = WSAID_WSARECVMSG; 114LPFN_WSASENDMSG pfnWSASendMsg; 115GUID sendGuid = WSAID_WSASENDMSG; 116 117CRITICAL_SECTION initLock; 118LONG initialized = 0; 119 120static void getExtensionPtrs() 121{ 122 if (InterlockedCompareExchange(&initialized, 1, 0) == 0) 123 { 124 InitializeCriticalSection(&initLock); 125 } 126 EnterCriticalSection(&initLock); 127 if(pfnWSARecvMsg == NULL|| pfnWSASendMsg == NULL) 128 { 129 SOCKET sock= socket(PF_INET, SOCK_DGRAM, 0); 130 DWORD dwBytes; 131 int rc = 0; 132 if (pfnWSARecvMsg == NULL) 133 { 134 rc = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &recvGuid, 135 sizeof(recvGuid), &pfnWSARecvMsg, sizeof(pfnWSARecvMsg), 136 &dwBytes, NULL, NULL); 137 } 138 if (rc != SOCKET_ERROR) 139 { 140 if (pfnWSASendMsg == NULL) 141 { 142 rc = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, 143 &sendGuid, sizeof(sendGuid), &pfnWSASendMsg, 144 sizeof(pfnWSASendMsg), &dwBytes, NULL, NULL); 145 } 146 } 147 if (rc == SOCKET_ERROR) 148 { 149 LSQ_ERROR("Can't get extension function pointers: %d", 150 WSAGetLastError()); 151 } 152 closesocket(sock); 153 } 154 LeaveCriticalSection(&initLock); 155} 156 157 158#endif 159 160 161static struct packets_in * 162allocate_packets_in (SOCKET_TYPE fd) 163{ 164 struct packets_in *packs_in; 165 unsigned n_alloc; 166 socklen_t opt_len; 167 int recvsz; 168 169 opt_len = sizeof(recvsz); 170 if (0 != getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&recvsz, &opt_len)) 171 { 172 LSQ_ERROR("getsockopt failed: %s", strerror(errno)); 173 return NULL; 174 } 175 176 n_alloc = (unsigned) recvsz / 1370; 177 LSQ_INFO("socket buffer size: %d bytes; max # packets is set to %u", 178 recvsz, n_alloc); 179 recvsz += MAX_PACKET_SZ; 180 181 packs_in = malloc(sizeof(*packs_in)); 182 packs_in->data_sz = recvsz; 183 packs_in->n_alloc = n_alloc; 184 packs_in->packet_data = malloc(recvsz); 185 packs_in->ctlmsg_data = malloc(n_alloc * CTL_SZ); 186 packs_in->vecs = malloc(n_alloc * sizeof(packs_in->vecs[0])); 187 packs_in->local_addresses = malloc(n_alloc * sizeof(packs_in->local_addresses[0])); 188 packs_in->peer_addresses = malloc(n_alloc * sizeof(packs_in->peer_addresses[0])); 189#if ECN_SUPPORTED 190 packs_in->ecn = malloc(n_alloc * sizeof(packs_in->ecn[0])); 191#endif 192 193 return packs_in; 194} 195 196 197static void 198free_packets_in (struct packets_in *packs_in) 199{ 200#if ECN_SUPPORTED 201 free(packs_in->ecn); 202#endif 203 free(packs_in->peer_addresses); 204 free(packs_in->local_addresses); 205 free(packs_in->ctlmsg_data); 206 free(packs_in->vecs); 207 free(packs_in->packet_data); 208 free(packs_in); 209} 210 211 212void 213sport_destroy (struct service_port *sport) 214{ 215 if (sport->ev) 216 { 217 event_del(sport->ev); 218 event_free(sport->ev); 219 } 220 if (sport->fd >= 0) 221 (void) CLOSE_SOCKET(sport->fd); 222 if (sport->packs_in) 223 free_packets_in(sport->packs_in); 224 free(sport->sp_token_buf); 225 free(sport); 226} 227 228 229struct service_port * 230sport_new (const char *optarg, struct prog *prog) 231{ 232 struct service_port *const sport = calloc(1, sizeof(*sport)); 233#if HAVE_REGEX 234 regex_t re; 235 regmatch_t matches[5]; 236 int re_code; 237 const char *port_str; 238 char errbuf[80]; 239#else 240 char *port_str; 241#endif 242 int port, e; 243 const char *host; 244 struct addrinfo hints, *res = NULL; 245#if __linux__ 246 sport->n_dropped = 0; 247 sport->drop_init = 0; 248#endif 249 sport->ev = NULL; 250 sport->packs_in = NULL; 251 sport->fd = -1; 252 char *const addr = strdup(optarg); 253#if __linux__ 254 char *if_name; 255 if_name = strrchr(addr, ','); 256 if (if_name) 257 { 258 strncpy(sport->if_name, if_name + 1, sizeof(sport->if_name) - 1); 259 sport->if_name[ sizeof(sport->if_name) - 1 ] = '\0'; 260 *if_name = '\0'; 261 } 262 else 263 sport->if_name[0] = '\0'; 264#endif 265#if HAVE_REGEX 266 re_code = regcomp(&re, "^(.*):([0-9][0-9]*)$" 267 "|^([0-9][0-9]*)$" 268 "|^(..*)$" 269 , REG_EXTENDED); 270 if (re_code != 0) 271 { 272 regerror(re_code, &re, errbuf, sizeof(errbuf)); 273 LSQ_ERROR("cannot compile regex: %s", errbuf); 274 goto err; 275 } 276 if (0 != regexec(&re, addr, sizeof(matches) / sizeof(matches[0]), 277 matches, 0)) 278 { 279 LSQ_ERROR("Invalid argument `%s'", addr); 280 goto err; 281 } 282 if (matches[1].rm_so >= 0) 283 { 284 addr[ matches[1].rm_so + matches[1].rm_eo ] = '\0'; 285 host = addr; 286 port_str = &addr[ matches[2].rm_so ]; 287 port = atoi(port_str); 288 } 289 else if (matches[3].rm_so >= 0) 290 { 291 if (!prog->prog_hostname) 292 { 293 LSQ_ERROR("hostname is not specified"); 294 goto err; 295 } 296 host = prog->prog_hostname; 297 port_str = &addr[ matches[3].rm_so ]; 298 port = atoi(port_str); 299 } 300 else 301 { 302 assert(matches[4].rm_so >= 0); 303 host = addr; 304 port_str = "443"; 305 port = 443; 306 } 307#else 308 host = addr; 309 port_str = strrchr(addr, ':'); 310 if (port_str) 311 { 312 *port_str++ = '\0'; 313 port = atoi(port_str); 314 } 315 else 316 { 317 port_str = "443"; 318 port = 443; 319 } 320#endif 321 assert(host); 322 LSQ_DEBUG("host: %s; port: %d", host, port); 323 if (strlen(host) > sizeof(sport->host) - 1) 324 { 325 LSQ_ERROR("argument `%s' too long", host); 326 goto err; 327 } 328 strcpy(sport->host, host); 329 330 struct sockaddr_in *const sa4 = (void *) &sport->sas; 331 struct sockaddr_in6 *const sa6 = (void *) &sport->sas; 332 if (inet_pton(AF_INET, host, &sa4->sin_addr)) { 333 sa4->sin_family = AF_INET; 334 sa4->sin_port = htons(port); 335 } else if (memset(sa6, 0, sizeof(*sa6)), 336 inet_pton(AF_INET6, host, &sa6->sin6_addr)) { 337 sa6->sin6_family = AF_INET6; 338 sa6->sin6_port = htons(port); 339 } else 340 { 341 memset(&hints, 0, sizeof(hints)); 342 hints.ai_flags = AI_NUMERICSERV; 343 if (prog->prog_ipver == 4) 344 hints.ai_family = AF_INET; 345 else if (prog->prog_ipver == 6) 346 hints.ai_family = AF_INET6; 347 e = getaddrinfo(host, port_str, &hints, &res); 348 if (e != 0) 349 { 350 LSQ_ERROR("could not resolve %s:%s: %s", host, port_str, 351 gai_strerror(e)); 352 goto err; 353 } 354 if (res->ai_addrlen > sizeof(sport->sas)) 355 { 356 LSQ_ERROR("resolved socket length is too long"); 357 goto err; 358 } 359 memcpy(&sport->sas, res->ai_addr, res->ai_addrlen); 360 if (!prog->prog_hostname) 361 prog->prog_hostname = sport->host; 362 } 363 364#if HAVE_REGEX 365 if (0 == re_code) 366 regfree(&re); 367#endif 368 if (res) 369 freeaddrinfo(res); 370 free(addr); 371 sport->sp_prog = prog; 372 return sport; 373 374 err: 375#if HAVE_REGEX 376 if (0 == re_code) 377 regfree(&re); 378#endif 379 if (res) 380 freeaddrinfo(res); 381 free(sport); 382 free(addr); 383 return NULL; 384} 385 386 387/* Replace IP address part of `sa' with that provided in ancillary messages 388 * in `msg'. 389 */ 390static void 391proc_ancillary ( 392#ifndef WIN32 393 struct msghdr 394#else 395 WSAMSG 396#endif 397 *msg, struct sockaddr_storage *storage 398#if __linux__ 399 , uint32_t *n_dropped 400#endif 401#if ECN_SUPPORTED 402 , int *ecn 403#endif 404 ) 405{ 406 const struct in6_pktinfo *in6_pkt; 407 struct cmsghdr *cmsg; 408 409 for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) 410 { 411 if (cmsg->cmsg_level == IPPROTO_IP && 412 cmsg->cmsg_type == 413#if __linux__ && defined(IP_RECVORIGDSTADDR) 414 IP_ORIGDSTADDR 415#elif __linux__ || WIN32 || __APPLE__ 416 IP_PKTINFO 417#else 418 IP_RECVDSTADDR 419#endif 420 ) 421 { 422#if __linux__ && defined(IP_RECVORIGDSTADDR) 423 memcpy(storage, CMSG_DATA(cmsg), sizeof(struct sockaddr_in)); 424#elif WIN32 425 const struct in_pktinfo *in_pkt; 426 in_pkt = (void *) WSA_CMSG_DATA(cmsg); 427 ((struct sockaddr_in *) storage)->sin_addr = in_pkt->ipi_addr; 428#elif __linux__ || __APPLE__ 429 const struct in_pktinfo *in_pkt; 430 in_pkt = (void *) CMSG_DATA(cmsg); 431 ((struct sockaddr_in *) storage)->sin_addr = in_pkt->ipi_addr; 432#else 433 memcpy(&((struct sockaddr_in *) storage)->sin_addr, 434 CMSG_DATA(cmsg), sizeof(struct in_addr)); 435#endif 436 } 437 else if (cmsg->cmsg_level == IPPROTO_IPV6 && 438 cmsg->cmsg_type == IPV6_PKTINFO) 439 { 440#ifndef WIN32 441 in6_pkt = (void *) CMSG_DATA(cmsg); 442#else 443 in6_pkt = (void *) WSA_CMSG_DATA(cmsg); 444#endif 445 ((struct sockaddr_in6 *) storage)->sin6_addr = 446 in6_pkt->ipi6_addr; 447 } 448#if __linux__ 449 else if (cmsg->cmsg_level == SOL_SOCKET && 450 cmsg->cmsg_type == SO_RXQ_OVFL) 451 memcpy(n_dropped, CMSG_DATA(cmsg), sizeof(*n_dropped)); 452#endif 453#if ECN_SUPPORTED 454 else if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TOS) 455 || (cmsg->cmsg_level == IPPROTO_IPV6 456 && cmsg->cmsg_type == IPV6_TCLASS)) 457 { 458 memcpy(ecn, CMSG_DATA(cmsg), sizeof(*ecn)); 459 *ecn &= IPTOS_ECN_MASK; 460 } 461#ifdef __FreeBSD__ 462 else if (cmsg->cmsg_level == IPPROTO_IP 463 && cmsg->cmsg_type == IP_RECVTOS) 464 { 465 unsigned char tos; 466 memcpy(&tos, CMSG_DATA(cmsg), sizeof(tos)); 467 *ecn = tos & IPTOS_ECN_MASK; 468 } 469#endif 470#endif 471 } 472} 473 474 475struct read_iter 476{ 477 struct service_port *ri_sport; 478 unsigned ri_idx; /* Current element */ 479 unsigned ri_off; /* Offset into packet_data */ 480}; 481 482 483enum rop { ROP_OK, ROP_NOROOM, ROP_ERROR, }; 484 485static enum rop 486read_one_packet (struct read_iter *iter) 487{ 488 unsigned char *ctl_buf; 489 struct packets_in *packs_in; 490#if __linux__ 491 uint32_t n_dropped; 492#endif 493#ifndef WIN32 494 ssize_t nread; 495#else 496 DWORD nread; 497 int socket_ret; 498#endif 499 struct sockaddr_storage *local_addr; 500 struct service_port *sport; 501 502 sport = iter->ri_sport; 503 packs_in = sport->packs_in; 504 505 if (iter->ri_idx >= packs_in->n_alloc || 506 iter->ri_off + MAX_PACKET_SZ > packs_in->data_sz) 507 { 508 LSQ_DEBUG("out of room in packets_in"); 509 return ROP_NOROOM; 510 } 511 512#ifndef WIN32 513 packs_in->vecs[iter->ri_idx].iov_base = packs_in->packet_data + iter->ri_off; 514 packs_in->vecs[iter->ri_idx].iov_len = MAX_PACKET_SZ; 515#else 516 packs_in->vecs[iter->ri_idx].buf = (char*)packs_in->packet_data + iter->ri_off; 517 packs_in->vecs[iter->ri_idx].len = MAX_PACKET_SZ; 518#endif 519 520#ifndef WIN32 521 top: 522#endif 523 ctl_buf = packs_in->ctlmsg_data + iter->ri_idx * CTL_SZ; 524 525#ifndef WIN32 526 struct msghdr msg = { 527 .msg_name = &packs_in->peer_addresses[iter->ri_idx], 528 .msg_namelen = sizeof(packs_in->peer_addresses[iter->ri_idx]), 529 .msg_iov = &packs_in->vecs[iter->ri_idx], 530 .msg_iovlen = 1, 531 .msg_control = ctl_buf, 532 .msg_controllen = CTL_SZ, 533 }; 534 nread = recvmsg(sport->fd, &msg, 0); 535 if (-1 == nread) { 536 if (!(EAGAIN == errno || EWOULDBLOCK == errno)) 537 LSQ_ERROR("recvmsg: %s", strerror(errno)); 538 return ROP_ERROR; 539 } 540 if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) 541 { 542 if (msg.msg_flags & MSG_TRUNC) 543 LSQ_INFO("packet truncated - drop it"); 544 if (msg.msg_flags & MSG_CTRUNC) 545 LSQ_WARN("packet's auxilicary data truncated - drop it"); 546 goto top; 547 } 548#else 549 WSAMSG msg = { 550 .name = (LPSOCKADDR)&packs_in->peer_addresses[iter->ri_idx], 551 .namelen = sizeof(packs_in->peer_addresses[iter->ri_idx]), 552 .lpBuffers = &packs_in->vecs[iter->ri_idx], 553 .dwBufferCount = 1, 554 .Control = {CTL_SZ,(char*)ctl_buf} 555 }; 556 socket_ret = pfnWSARecvMsg(sport->fd, &msg, &nread, NULL, NULL); 557 if (SOCKET_ERROR == socket_ret) { 558 if (WSAEWOULDBLOCK != WSAGetLastError()) 559 LSQ_ERROR("recvmsg: %d", WSAGetLastError()); 560 return ROP_ERROR; 561 } 562#endif 563 564 local_addr = &packs_in->local_addresses[iter->ri_idx]; 565 memcpy(local_addr, &sport->sp_local_addr, sizeof(*local_addr)); 566#if __linux__ 567 n_dropped = 0; 568#endif 569#if ECN_SUPPORTED 570 packs_in->ecn[iter->ri_idx] = 0; 571#endif 572 proc_ancillary(&msg, local_addr 573#if __linux__ 574 , &n_dropped 575#endif 576#if ECN_SUPPORTED 577 , &packs_in->ecn[iter->ri_idx] 578#endif 579 ); 580#if LSQUIC_ECN_BLACK_HOLE && ECN_SUPPORTED 581 { 582 const char *s; 583 s = getenv("LSQUIC_ECN_BLACK_HOLE"); 584 if (s && atoi(s) && packs_in->ecn[iter->ri_idx]) 585 { 586 LSQ_NOTICE("ECN blackhole: drop packet"); 587 return ROP_OK; 588 } 589 } 590#endif 591#if __linux__ 592 if (sport->drop_init) 593 { 594 if (sport->n_dropped < n_dropped) 595 LSQ_INFO("dropped %u packets", n_dropped - sport->n_dropped); 596 } 597 else 598 sport->drop_init = 1; 599 sport->n_dropped = n_dropped; 600#endif 601 602#ifndef WIN32 603 packs_in->vecs[iter->ri_idx].iov_len = nread; 604#else 605 packs_in->vecs[iter->ri_idx].len = nread; 606#endif 607 iter->ri_off += nread; 608 iter->ri_idx += 1; 609 610 return ROP_OK; 611} 612 613 614#if HAVE_RECVMMSG 615static enum rop 616read_using_recvmmsg (struct read_iter *iter) 617{ 618#if __linux__ 619 uint32_t n_dropped; 620#endif 621 int s; 622 unsigned n; 623 struct sockaddr_storage *local_addr; 624 struct service_port *const sport = iter->ri_sport; 625 struct packets_in *const packs_in = sport->packs_in; 626 /* XXX TODO We allocate this array on the stack and initialize the 627 * headers each time the function is invoked. This is suboptimal. 628 * What we should really be doing is allocate mmsghdrs as part of 629 * packs_in and initialize it there. While we are at it, we should 630 * make packs_in shared between all service ports. 631 */ 632 struct mmsghdr mmsghdrs[ packs_in->n_alloc ]; 633 634 /* Sanity check: we assume that the iterator is reset */ 635 assert(iter->ri_off == 0 && iter->ri_idx == 0); 636 637 /* Initialize mmsghdrs */ 638 for (n = 0; n < sizeof(mmsghdrs) / sizeof(mmsghdrs[0]); ++n) 639 { 640 packs_in->vecs[n].iov_base = packs_in->packet_data + MAX_PACKET_SZ * n; 641 packs_in->vecs[n].iov_len = MAX_PACKET_SZ; 642 mmsghdrs[n].msg_hdr = (struct msghdr) { 643 .msg_name = &packs_in->peer_addresses[n], 644 .msg_namelen = sizeof(packs_in->peer_addresses[n]), 645 .msg_iov = &packs_in->vecs[n], 646 .msg_iovlen = 1, 647 .msg_control = packs_in->ctlmsg_data + CTL_SZ * n, 648 .msg_controllen = CTL_SZ, 649 }; 650 } 651 652 /* Read packets */ 653 s = recvmmsg(sport->fd, mmsghdrs, n, 0, NULL); 654 if (s < 0) 655 { 656 if (!(EAGAIN == errno || EWOULDBLOCK == errno)) 657 LSQ_ERROR("recvmmsg: %s", strerror(errno)); 658 return ROP_ERROR; 659 } 660 661 /* Process ancillary data and update vecs */ 662 for (n = 0; n < (unsigned) s; ++n) 663 { 664 local_addr = &packs_in->local_addresses[n]; 665 memcpy(local_addr, &sport->sp_local_addr, sizeof(*local_addr)); 666#if __linux__ 667 n_dropped = 0; 668#endif 669#if ECN_SUPPORTED 670 packs_in->ecn[n] = 0; 671#endif 672 proc_ancillary(&mmsghdrs[n].msg_hdr, local_addr 673#if __linux__ 674 , &n_dropped 675#endif 676#if ECN_SUPPORTED 677 , &packs_in->ecn[n] 678#endif 679 ); 680#if __linux__ 681 if (sport->drop_init) 682 { 683 if (sport->n_dropped < n_dropped) 684 LSQ_INFO("dropped %u packets", n_dropped - sport->n_dropped); 685 } 686 else 687 sport->drop_init = 1; 688 sport->n_dropped = n_dropped; 689#endif 690 packs_in->vecs[n].iov_len = mmsghdrs[n].msg_len; 691 } 692 693 iter->ri_idx = n; 694 695 return n == sizeof(mmsghdrs) / sizeof(mmsghdrs[0]) ? ROP_NOROOM : ROP_OK; 696} 697 698 699#endif 700 701 702#if __GNUC__ 703# define UNLIKELY(cond) __builtin_expect(cond, 0) 704#else 705# define UNLIKELY(cond) cond 706#endif 707 708 709static void 710read_handler (evutil_socket_t fd, short flags, void *ctx) 711{ 712 struct service_port *sport = ctx; 713 lsquic_engine_t *const engine = sport->engine; 714 struct packets_in *packs_in = sport->packs_in; 715 struct read_iter iter; 716 unsigned n, n_batches; 717 /* Save the value in case program is stopped packs_in is freed: */ 718 const unsigned n_alloc = packs_in->n_alloc; 719 enum rop rop; 720 721 n_batches = 0; 722 iter.ri_sport = sport; 723 724 sport->sp_prog->prog_read_count += 1; 725 do 726 { 727 iter.ri_off = 0; 728 iter.ri_idx = 0; 729 730#if HAVE_RECVMMSG 731 if (sport->sp_prog->prog_use_recvmmsg) 732 rop = read_using_recvmmsg(&iter); 733 else 734#endif 735 do 736 rop = read_one_packet(&iter); 737 while (ROP_OK == rop); 738 739 if (UNLIKELY(ROP_ERROR == rop && (sport->sp_flags & SPORT_CONNECT) 740 && errno == ECONNREFUSED)) 741 { 742 LSQ_ERROR("connection refused: exit program"); 743 prog_cleanup(sport->sp_prog); 744 exit(1); 745 } 746 747 n_batches += iter.ri_idx > 0; 748 749 for (n = 0; n < iter.ri_idx; ++n) 750 if (0 > lsquic_engine_packet_in(engine, 751#ifndef WIN32 752 packs_in->vecs[n].iov_base, 753 packs_in->vecs[n].iov_len, 754#else 755 (const unsigned char *) packs_in->vecs[n].buf, 756 packs_in->vecs[n].len, 757#endif 758 (struct sockaddr *) &packs_in->local_addresses[n], 759 (struct sockaddr *) &packs_in->peer_addresses[n], 760 sport, 761#if ECN_SUPPORTED 762 packs_in->ecn[n] 763#else 764 0 765#endif 766 )) 767 break; 768 769 if (n > 0) 770 prog_process_conns(sport->sp_prog); 771 } 772 while (ROP_NOROOM == rop && !prog_is_stopped()); 773 774 if (n_batches) 775 n += n_alloc * (n_batches - 1); 776 777 LSQ_DEBUG("read %u packet%.*s in %u batch%s", n, n != 1, "s", n_batches, n_batches != 1 ? "es" : ""); 778} 779 780 781static int 782add_to_event_loop (struct service_port *sport, struct event_base *eb) 783{ 784 sport->ev = event_new(eb, sport->fd, EV_READ|EV_PERSIST, read_handler, 785 sport); 786 if (sport->ev) 787 { 788 event_add(sport->ev, NULL); 789 return 0; 790 } 791 else 792 return -1; 793} 794 795 796int 797sport_init_server (struct service_port *sport, struct lsquic_engine *engine, 798 struct event_base *eb) 799{ 800 const struct sockaddr *sa_local = (struct sockaddr *) &sport->sas; 801 int sockfd, saved_errno, s; 802#ifndef WIN32 803 int flags; 804#endif 805 SOCKOPT_VAL on; 806 socklen_t socklen; 807 char addr_str[0x20]; 808 809 switch (sa_local->sa_family) 810 { 811 case AF_INET: 812 socklen = sizeof(struct sockaddr_in); 813 break; 814 case AF_INET6: 815 socklen = sizeof(struct sockaddr_in6); 816 break; 817 default: 818 errno = EINVAL; 819 return -1; 820 } 821 822#if WIN32 823 getExtensionPtrs(); 824#endif 825 sockfd = socket(sa_local->sa_family, SOCK_DGRAM, 0); 826 if (-1 == sockfd) 827 return -1; 828 829 if (0 != bind(sockfd, sa_local, socklen)) { 830 saved_errno = errno; 831 LSQ_WARN("bind failed: %s", strerror(errno)); 832 close(sockfd); 833 errno = saved_errno; 834 return -1; 835 } 836 837 /* Make socket non-blocking */ 838#ifndef WIN32 839 flags = fcntl(sockfd, F_GETFL); 840 if (-1 == flags) { 841 saved_errno = errno; 842 close(sockfd); 843 errno = saved_errno; 844 return -1; 845 } 846 flags |= O_NONBLOCK; 847 if (0 != fcntl(sockfd, F_SETFL, flags)) { 848 saved_errno = errno; 849 close(sockfd); 850 errno = saved_errno; 851 return -1; 852 } 853#else 854 { 855 u_long on = 1; 856 ioctlsocket(sockfd, FIONBIO, &on); 857 } 858#endif 859 860 on = 1; 861 if (AF_INET == sa_local->sa_family) 862 s = setsockopt(sockfd, IPPROTO_IP, 863#if __linux__ && defined(IP_RECVORIGDSTADDR) 864 IP_RECVORIGDSTADDR, 865#elif __linux__ || __APPLE__ || defined(WIN32) 866 IP_PKTINFO, 867#else 868 IP_RECVDSTADDR, 869#endif 870 CHAR_CAST &on, sizeof(on)); 871 else 872 { 873#ifndef WIN32 874 s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); 875#else 876 s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, CHAR_CAST &on, sizeof(on)); 877#endif 878 } 879 880 if (0 != s) 881 { 882 saved_errno = errno; 883 close(sockfd); 884 errno = saved_errno; 885 return -1; 886 } 887 888#if (__linux__ && !defined(IP_RECVORIGDSTADDR)) || __APPLE__ || defined(WIN32) 889 /* Need to set IP_PKTINFO for sending */ 890 if (AF_INET == sa_local->sa_family) 891 { 892 on = 1; 893 s = setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, CHAR_CAST &on, sizeof(on)); 894 if (0 != s) 895 { 896 saved_errno = errno; 897 close(sockfd); 898 errno = saved_errno; 899 return -1; 900 } 901 } 902#elif IP_RECVDSTADDR != IP_SENDSRCADDR 903 /* On FreeBSD, IP_RECVDSTADDR is the same as IP_SENDSRCADDR, but I do not 904 * know about other BSD systems. 905 */ 906 if (AF_INET == sa_local->sa_family) 907 { 908 on = 1; 909 s = setsockopt(sockfd, IPPROTO_IP, IP_SENDSRCADDR, &on, sizeof(on)); 910 if (0 != s) 911 { 912 saved_errno = errno; 913 close(sockfd); 914 errno = saved_errno; 915 return -1; 916 } 917 } 918#endif 919 920#if __linux__ && defined(SO_RXQ_OVFL) 921 on = 1; 922 s = setsockopt(sockfd, SOL_SOCKET, SO_RXQ_OVFL, &on, sizeof(on)); 923 if (0 != s) 924 { 925 saved_errno = errno; 926 close(sockfd); 927 errno = saved_errno; 928 return -1; 929 } 930#endif 931 932#if __linux__ 933 if (sport->if_name[0] && 934 0 != setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, sport->if_name, 935 IFNAMSIZ)) 936 { 937 saved_errno = errno; 938 close(sockfd); 939 errno = saved_errno; 940 return -1; 941 } 942#endif 943 944#if LSQUIC_DONTFRAG_SUPPORTED 945 if (!(sport->sp_flags & SPORT_FRAGMENT_OK)) 946 { 947 if (AF_INET == sa_local->sa_family) 948 { 949#if __linux__ 950 on = IP_PMTUDISC_DO; 951 s = setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &on, 952 sizeof(on)); 953#else 954 on = 1; 955 s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, CHAR_CAST &on, sizeof(on)); 956#endif 957 if (0 != s) 958 { 959 saved_errno = errno; 960 close(sockfd); 961 errno = saved_errno; 962 return -1; 963 } 964 } 965 } 966#endif 967 968#if ECN_SUPPORTED 969 on = 1; 970 if (AF_INET == sa_local->sa_family) 971 s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS, CHAR_CAST &on, sizeof(on)); 972 else 973 s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS, CHAR_CAST &on, sizeof(on)); 974 if (0 != s) 975 { 976 saved_errno = errno; 977 close(sockfd); 978 errno = saved_errno; 979 return -1; 980 } 981#endif 982 983 if (sport->sp_flags & SPORT_SET_SNDBUF) 984 { 985 s = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, CHAR_CAST &sport->sp_sndbuf, 986 sizeof(sport->sp_sndbuf)); 987 if (0 != s) 988 { 989 saved_errno = errno; 990 close(sockfd); 991 errno = saved_errno; 992 return -1; 993 } 994 } 995 996 if (sport->sp_flags & SPORT_SET_RCVBUF) 997 { 998 s = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, CHAR_CAST &sport->sp_rcvbuf, 999 sizeof(sport->sp_rcvbuf)); 1000 if (0 != s) 1001 { 1002 saved_errno = errno; 1003 close(sockfd); 1004 errno = saved_errno; 1005 return -1; 1006 } 1007 } 1008 1009 if (0 != getsockname(sockfd, (struct sockaddr *) sa_local, &socklen)) 1010 { 1011 saved_errno = errno; 1012 close(sockfd); 1013 errno = saved_errno; 1014 return -1; 1015 } 1016 1017 sport->packs_in = allocate_packets_in(sockfd); 1018 if (!sport->packs_in) 1019 { 1020 saved_errno = errno; 1021 close(sockfd); 1022 errno = saved_errno; 1023 return -1; 1024 } 1025 1026 memcpy((void *) &sport->sp_local_addr, sa_local, 1027 sa_local->sa_family == AF_INET ? 1028 sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); 1029 switch (sa_local->sa_family) { 1030 case AF_INET: 1031 LSQ_DEBUG("local address: %s:%d", 1032 inet_ntop(AF_INET, &((struct sockaddr_in *) sa_local)->sin_addr, 1033 addr_str, sizeof(addr_str)), 1034 ntohs(((struct sockaddr_in *) sa_local)->sin_port)); 1035 break; 1036 } 1037 1038 sport->engine = engine; 1039 sport->fd = sockfd; 1040 sport->sp_flags |= SPORT_SERVER; 1041 1042 return add_to_event_loop(sport, eb); 1043} 1044 1045 1046int 1047sport_init_client (struct service_port *sport, struct lsquic_engine *engine, 1048 struct event_base *eb) 1049{ 1050 const struct sockaddr *sa_peer = (struct sockaddr *) &sport->sas; 1051 int saved_errno, s; 1052#ifndef WIN32 1053 int flags; 1054#endif 1055 SOCKET_TYPE sockfd; 1056 socklen_t socklen, peer_socklen; 1057 union { 1058 struct sockaddr_in sin; 1059 struct sockaddr_in6 sin6; 1060 } u; 1061 struct sockaddr *sa_local = (struct sockaddr *) &u; 1062 char addr_str[0x20]; 1063 1064 switch (sa_peer->sa_family) 1065 { 1066 case AF_INET: 1067 socklen = sizeof(struct sockaddr_in); 1068 u.sin.sin_family = AF_INET; 1069 u.sin.sin_addr.s_addr = INADDR_ANY; 1070 u.sin.sin_port = 0; 1071 break; 1072 case AF_INET6: 1073 socklen = sizeof(struct sockaddr_in6); 1074 memset(&u.sin6, 0, sizeof(u.sin6)); 1075 u.sin6.sin6_family = AF_INET6; 1076 break; 1077 default: 1078 errno = EINVAL; 1079 return -1; 1080 } 1081 1082#if WIN32 1083 getExtensionPtrs(); 1084#endif 1085 sockfd = socket(sa_peer->sa_family, SOCK_DGRAM, 0); 1086 if (-1 == sockfd) 1087 return -1; 1088 1089 if (0 != bind(sockfd, sa_local, socklen)) { 1090 saved_errno = errno; 1091 CLOSE_SOCKET(sockfd); 1092 errno = saved_errno; 1093 return -1; 1094 } 1095 1096 if (sport->sp_flags & SPORT_CONNECT) 1097 { 1098 peer_socklen = AF_INET == sa_peer->sa_family 1099 ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); 1100 if (0 != connect(sockfd, sa_peer, peer_socklen)) 1101 { 1102 saved_errno = errno; 1103 CLOSE_SOCKET(sockfd); 1104 errno = saved_errno; 1105 return -1; 1106 } 1107 } 1108 1109 /* Make socket non-blocking */ 1110#ifndef WIN32 1111 flags = fcntl(sockfd, F_GETFL); 1112 if (-1 == flags) { 1113 saved_errno = errno; 1114 CLOSE_SOCKET(sockfd); 1115 errno = saved_errno; 1116 return -1; 1117 } 1118 flags |= O_NONBLOCK; 1119 if (0 != fcntl(sockfd, F_SETFL, flags)) { 1120 saved_errno = errno; 1121 CLOSE_SOCKET(sockfd); 1122 errno = saved_errno; 1123 return -1; 1124 } 1125#else 1126 { 1127 u_long on = 1; 1128 ioctlsocket(sockfd, FIONBIO, &on); 1129 } 1130#endif 1131 1132#if LSQUIC_DONTFRAG_SUPPORTED 1133 if (!(sport->sp_flags & SPORT_FRAGMENT_OK)) 1134 { 1135 if (AF_INET == sa_local->sa_family) 1136 { 1137 int on; 1138#if __linux__ 1139 on = IP_PMTUDISC_DO; 1140 s = setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &on, 1141 sizeof(on)); 1142#elif WIN32 1143 on = 1; 1144 s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAGMENT, CHAR_CAST &on, sizeof(on)); 1145#else 1146 on = 1; 1147 s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, &on, sizeof(on)); 1148#endif 1149 if (0 != s) 1150 { 1151 saved_errno = errno; 1152 CLOSE_SOCKET(sockfd); 1153 errno = saved_errno; 1154 return -1; 1155 } 1156 } 1157 } 1158#endif 1159 1160#if ECN_SUPPORTED 1161 { 1162 int on = 1; 1163 if (AF_INET == sa_local->sa_family) 1164 s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS, 1165 CHAR_CAST &on, sizeof(on)); 1166 else 1167 s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS, 1168 CHAR_CAST &on, sizeof(on)); 1169 if (0 != s) 1170 { 1171 saved_errno = errno; 1172 close(sockfd); 1173 errno = saved_errno; 1174 return -1; 1175 } 1176 } 1177#endif 1178 1179 if (sport->sp_flags & SPORT_SET_SNDBUF) 1180 { 1181 s = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, 1182 CHAR_CAST &sport->sp_sndbuf, sizeof(sport->sp_sndbuf)); 1183 if (0 != s) 1184 { 1185 saved_errno = errno; 1186 CLOSE_SOCKET(sockfd); 1187 errno = saved_errno; 1188 return -1; 1189 } 1190 } 1191 1192 if (sport->sp_flags & SPORT_SET_RCVBUF) 1193 { 1194 s = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 1195 CHAR_CAST &sport->sp_rcvbuf, sizeof(sport->sp_rcvbuf)); 1196 if (0 != s) 1197 { 1198 saved_errno = errno; 1199 CLOSE_SOCKET(sockfd); 1200 errno = saved_errno; 1201 return -1; 1202 } 1203 } 1204 1205 if (0 != getsockname(sockfd, sa_local, &socklen)) 1206 { 1207 saved_errno = errno; 1208 CLOSE_SOCKET(sockfd); 1209 errno = saved_errno; 1210 return -1; 1211 } 1212 1213 sport->packs_in = allocate_packets_in(sockfd); 1214 if (!sport->packs_in) 1215 { 1216 saved_errno = errno; 1217 CLOSE_SOCKET(sockfd); 1218 errno = saved_errno; 1219 return -1; 1220 } 1221 1222 memcpy((void *) &sport->sp_local_addr, sa_local, 1223 sa_local->sa_family == AF_INET ? 1224 sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); 1225 switch (sa_local->sa_family) { 1226 case AF_INET: 1227 LSQ_DEBUG("local address: %s:%d", 1228 inet_ntop(AF_INET, &u.sin.sin_addr, addr_str, sizeof(addr_str)), 1229 ntohs(u.sin.sin_port)); 1230 break; 1231 } 1232 1233 sport->engine = engine; 1234 sport->fd = sockfd; 1235 1236 return add_to_event_loop(sport, eb); 1237} 1238 1239 1240/* Sometimes it is useful to impose an artificial limit for testing */ 1241static unsigned 1242packet_out_limit (void) 1243{ 1244 const char *env = getenv("LSQUIC_PACKET_OUT_LIMIT"); 1245 if (env) 1246 return atoi(env); 1247 else 1248 return 0; 1249} 1250 1251 1252enum ctl_what 1253{ 1254 CW_SENDADDR = 1 << 0, 1255#if ECN_SUPPORTED 1256 CW_ECN = 1 << 1, 1257#endif 1258}; 1259 1260static void 1261setup_control_msg ( 1262#ifndef WIN32 1263 struct msghdr 1264#else 1265 WSAMSG 1266#endif 1267 *msg, enum ctl_what cw, 1268 const struct lsquic_out_spec *spec, unsigned char *buf, size_t bufsz) 1269{ 1270 struct cmsghdr *cmsg; 1271 struct sockaddr_in *local_sa; 1272 struct sockaddr_in6 *local_sa6; 1273#if __linux__ || __APPLE__ || WIN32 1274 struct in_pktinfo info; 1275#endif 1276 struct in6_pktinfo info6; 1277 size_t ctl_len; 1278 1279#ifndef WIN32 1280 msg->msg_control = buf; 1281 msg->msg_controllen = bufsz; 1282#else 1283 msg->Control.buf = (char*)buf; 1284 msg->Control.len = bufsz; 1285#endif 1286 1287 /* Need to zero the buffer due to a bug(?) in CMSG_NXTHDR. See 1288 * https://stackoverflow.com/questions/27601849/cmsg-nxthdr-returns-null-even-though-there-are-more-cmsghdr-objects 1289 */ 1290 memset(buf, 0, bufsz); 1291 1292 ctl_len = 0; 1293 for (cmsg = CMSG_FIRSTHDR(msg); cw && cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) 1294 { 1295 if (cw & CW_SENDADDR) 1296 { 1297 if (AF_INET == spec->dest_sa->sa_family) 1298 { 1299 local_sa = (struct sockaddr_in *) spec->local_sa; 1300#if __linux__ || __APPLE__ 1301 memset(&info, 0, sizeof(info)); 1302 info.ipi_spec_dst = local_sa->sin_addr; 1303 cmsg->cmsg_level = IPPROTO_IP; 1304 cmsg->cmsg_type = IP_PKTINFO; 1305 cmsg->cmsg_len = CMSG_LEN(sizeof(info)); 1306 ctl_len += CMSG_SPACE(sizeof(info)); 1307 memcpy(CMSG_DATA(cmsg), &info, sizeof(info)); 1308#elif WIN32 1309 memset(&info, 0, sizeof(info)); 1310 info.ipi_addr = local_sa->sin_addr; 1311 cmsg->cmsg_level = IPPROTO_IP; 1312 cmsg->cmsg_type = IP_PKTINFO; 1313 cmsg->cmsg_len = CMSG_LEN(sizeof(info)); 1314 ctl_len += CMSG_SPACE(sizeof(info)); 1315 memcpy(WSA_CMSG_DATA(cmsg), &info, sizeof(info)); 1316#else 1317 cmsg->cmsg_level = IPPROTO_IP; 1318 cmsg->cmsg_type = IP_SENDSRCADDR; 1319 cmsg->cmsg_len = CMSG_LEN(sizeof(local_sa->sin_addr)); 1320 ctl_len += CMSG_SPACE(sizeof(local_sa->sin_addr)); 1321 memcpy(CMSG_DATA(cmsg), &local_sa->sin_addr, 1322 sizeof(local_sa->sin_addr)); 1323#endif 1324 } 1325 else 1326 { 1327 local_sa6 = (struct sockaddr_in6 *) spec->local_sa; 1328 memset(&info6, 0, sizeof(info6)); 1329 info6.ipi6_addr = local_sa6->sin6_addr; 1330 cmsg->cmsg_level = IPPROTO_IPV6; 1331 cmsg->cmsg_type = IPV6_PKTINFO; 1332 cmsg->cmsg_len = CMSG_LEN(sizeof(info6)); 1333#ifndef WIN32 1334 memcpy(CMSG_DATA(cmsg), &info6, sizeof(info6)); 1335#else 1336 memcpy(WSA_CMSG_DATA(cmsg), &info6, sizeof(info6)); 1337#endif 1338 ctl_len += CMSG_SPACE(sizeof(info6)); 1339 } 1340 cw &= ~CW_SENDADDR; 1341 } 1342#if ECN_SUPPORTED 1343 else if (cw & CW_ECN) 1344 { 1345 if (AF_INET == spec->dest_sa->sa_family) 1346 { 1347 const 1348#if defined(__FreeBSD__) 1349 unsigned char 1350#else 1351 int 1352#endif 1353 tos = spec->ecn; 1354 cmsg->cmsg_level = IPPROTO_IP; 1355 cmsg->cmsg_type = IP_TOS; 1356 cmsg->cmsg_len = CMSG_LEN(sizeof(tos)); 1357 memcpy(CMSG_DATA(cmsg), &tos, sizeof(tos)); 1358 ctl_len += CMSG_SPACE(sizeof(tos)); 1359 } 1360 else 1361 { 1362 const int tos = spec->ecn; 1363 cmsg->cmsg_level = IPPROTO_IPV6; 1364 cmsg->cmsg_type = IPV6_TCLASS; 1365 cmsg->cmsg_len = CMSG_LEN(sizeof(tos)); 1366 memcpy(CMSG_DATA(cmsg), &tos, sizeof(tos)); 1367 ctl_len += CMSG_SPACE(sizeof(tos)); 1368 } 1369 cw &= ~CW_ECN; 1370 } 1371#endif 1372 else 1373 assert(0); 1374 } 1375 1376#ifndef WIN32 1377 msg->msg_controllen = ctl_len; 1378#else 1379 msg->Control.len = ctl_len; 1380#endif 1381} 1382 1383 1384#if HAVE_SENDMMSG 1385static int 1386send_packets_using_sendmmsg (const struct lsquic_out_spec *specs, 1387 unsigned count) 1388{ 1389#ifndef NDEBUG 1390 { 1391 /* This only works for a single port! If the specs contain more 1392 * than one socket, this function does *NOT* work. We check it 1393 * here just in case: 1394 */ 1395 void *ctx; 1396 unsigned i; 1397 for (i = 1, ctx = specs[i].peer_ctx; 1398 i < count; 1399 ctx = specs[i].peer_ctx, ++i) 1400 assert(ctx == specs[i - 1].peer_ctx); 1401 } 1402#endif 1403 1404 const struct service_port *const sport = specs[0].peer_ctx; 1405 const int fd = sport->fd; 1406 enum ctl_what cw; 1407 unsigned i; 1408 int s, saved_errno; 1409 uintptr_t ancil_key, prev_ancil_key; 1410 struct mmsghdr mmsgs[1024]; 1411 union { 1412 /* cmsg(3) recommends union for proper alignment */ 1413 unsigned char buf[ CMSG_SPACE( 1414 MAX( 1415#if __linux__ 1416 sizeof(struct in_pktinfo) 1417#else 1418 sizeof(struct in_addr) 1419#endif 1420 , sizeof(struct in6_pktinfo)) 1421 ) 1422#if ECN_SUPPORTED 1423 + CMSG_SPACE(sizeof(int)) 1424#endif 1425 ]; 1426 struct cmsghdr cmsg; 1427 } ancil [ sizeof(mmsgs) / sizeof(mmsgs[0]) ]; 1428 1429 prev_ancil_key = 0; 1430 for (i = 0; i < count && i < sizeof(mmsgs) / sizeof(mmsgs[0]); ++i) 1431 { 1432 mmsgs[i].msg_hdr.msg_name = (void *) specs[i].dest_sa; 1433 mmsgs[i].msg_hdr.msg_namelen = (AF_INET == specs[i].dest_sa->sa_family ? 1434 sizeof(struct sockaddr_in) : 1435 sizeof(struct sockaddr_in6)), 1436 mmsgs[i].msg_hdr.msg_iov = specs[i].iov; 1437 mmsgs[i].msg_hdr.msg_iovlen = specs[i].iovlen; 1438 mmsgs[i].msg_hdr.msg_flags = 0; 1439 if ((sport->sp_flags & SPORT_SERVER) && specs[i].local_sa->sa_family) 1440 { 1441 cw = CW_SENDADDR; 1442 ancil_key = (uintptr_t) specs[i].local_sa; 1443 assert(0 == (ancil_key & 3)); 1444 } 1445 else 1446 { 1447 cw = 0; 1448 ancil_key = 0; 1449 } 1450#if ECN_SUPPORTED 1451 if (sport->sp_prog->prog_api.ea_settings->es_ecn && specs[i].ecn) 1452 { 1453 cw |= CW_ECN; 1454 ancil_key |= specs[i].ecn; 1455 } 1456#endif 1457 if (cw && prev_ancil_key == ancil_key) 1458 { 1459 /* Reuse previous ancillary message */ 1460 assert(i > 0); 1461#ifndef WIN32 1462 mmsgs[i].msg_hdr.msg_control = mmsgs[i - 1].msg_hdr.msg_control; 1463 mmsgs[i].msg_hdr.msg_controllen = mmsgs[i - 1].msg_hdr.msg_controllen; 1464#else 1465 mmsgs[i].msg_hdr.Control.buf = mmsgs[i - 1].msg_hdr.Control.buf; 1466 mmsgs[i].msg_hdr.Control.len = mmsgs[i - 1].msg_hdr.Control.len; 1467#endif 1468 } 1469 else if (cw) 1470 { 1471 prev_ancil_key = ancil_key; 1472 setup_control_msg(&mmsgs[i].msg_hdr, cw, &specs[i], ancil[i].buf, 1473 sizeof(ancil[i].buf)); 1474 } 1475 else 1476 { 1477 prev_ancil_key = 0; 1478#ifndef WIN32 1479 mmsgs[i].msg_hdr.msg_control = NULL; 1480 mmsgs[i].msg_hdr.msg_controllen = 0; 1481#else 1482 mmsgs[i].msg_hdr.Control.buf = NULL; 1483 mmsgs[i].msg_hdr.Control.len = 0; 1484#endif 1485 } 1486 } 1487 1488 s = sendmmsg(fd, mmsgs, count, 0); 1489 if (s < (int) count) 1490 { 1491 saved_errno = errno; 1492 prog_sport_cant_send(sport->sp_prog, sport->fd); 1493 if (s < 0) 1494 { 1495 LSQ_WARN("sendmmsg failed: %s", strerror(saved_errno)); 1496 errno = saved_errno; 1497 } 1498 else if (s > 0) 1499 errno = EAGAIN; 1500 else 1501 errno = saved_errno; 1502 } 1503 1504 return s; 1505} 1506 1507 1508#endif 1509 1510 1511#if LSQUIC_PREFERRED_ADDR 1512static const struct service_port * 1513find_sport (struct prog *prog, const struct sockaddr *local_sa) 1514{ 1515 const struct service_port *sport; 1516 const struct sockaddr *addr; 1517 size_t len; 1518 1519 TAILQ_FOREACH(sport, prog->prog_sports, next_sport) 1520 { 1521 addr = (struct sockaddr *) &sport->sp_local_addr; 1522 if (addr->sa_family == local_sa->sa_family) 1523 { 1524 len = addr->sa_family == AF_INET ? sizeof(struct sockaddr_in) 1525 : sizeof(struct sockaddr_in6); 1526 if (0 == memcmp(addr, local_sa, len)) 1527 return sport; 1528 } 1529 } 1530 1531 assert(0); 1532 return NULL; 1533} 1534 1535 1536#endif 1537 1538 1539static int 1540send_packets_one_by_one (const struct lsquic_out_spec *specs, unsigned count) 1541{ 1542 const struct service_port *sport; 1543 enum ctl_what cw; 1544 unsigned n; 1545 int s = 0; 1546#ifndef WIN32 1547 struct msghdr msg; 1548#else 1549 DWORD bytes; 1550 WSAMSG msg; 1551 LPWSABUF pWsaBuf = NULL; 1552#endif 1553 union { 1554 /* cmsg(3) recommends union for proper alignment */ 1555#if __linux__ || WIN32 1556# define SIZE1 sizeof(struct in_pktinfo) 1557#else 1558# define SIZE1 sizeof(struct in_addr) 1559#endif 1560 unsigned char buf[ 1561 CMSG_SPACE(MAX(SIZE1, sizeof(struct in6_pktinfo))) 1562#if ECN_SUPPORTED 1563 + CMSG_SPACE(sizeof(int)) 1564#endif 1565 ]; 1566 struct cmsghdr cmsg; 1567 } ancil; 1568 uintptr_t ancil_key, prev_ancil_key; 1569 1570 if (0 == count) 1571 return 0; 1572 1573 const unsigned orig_count = count; 1574 const unsigned out_limit = packet_out_limit(); 1575 if (out_limit && count > out_limit) 1576 count = out_limit; 1577#if LSQUIC_RANDOM_SEND_FAILURE 1578 { 1579 const char *freq_str = getenv("LSQUIC_RANDOM_SEND_FAILURE"); 1580 int freq; 1581 if (freq_str) 1582 freq = atoi(freq_str); 1583 else 1584 freq = 10; 1585 if (rand() % freq == 0) 1586 { 1587 assert(count > 0); 1588 sport = specs[0].peer_ctx; 1589 LSQ_NOTICE("sending \"randomly\" fails"); 1590 prog_sport_cant_send(sport->sp_prog, sport->fd); 1591 goto random_send_failure; 1592 } 1593 } 1594#endif 1595 1596 n = 0; 1597 prev_ancil_key = 0; 1598#ifdef WIN32 1599 #define MAX_OUT_BATCH_SIZE 1024 1600 pWsaBuf = malloc(sizeof(*pWsaBuf)*MAX_OUT_BATCH_SIZE*2); 1601 if (NULL == pWsaBuf) { 1602 return -1; 1603 } 1604#endif 1605 1606 do 1607 { 1608 sport = specs[n].peer_ctx; 1609#if LSQUIC_PREFERRED_ADDR 1610 if (sport->sp_prog->prog_flags & PROG_SEARCH_ADDRS) 1611 sport = find_sport(sport->sp_prog, specs[n].local_sa); 1612#endif 1613#ifndef WIN32 1614 msg.msg_name = (void *) specs[n].dest_sa; 1615 msg.msg_namelen = (AF_INET == specs[n].dest_sa->sa_family ? 1616 sizeof(struct sockaddr_in) : 1617 sizeof(struct sockaddr_in6)), 1618 msg.msg_iov = specs[n].iov; 1619 msg.msg_iovlen = specs[n].iovlen; 1620 msg.msg_flags = 0; 1621#else 1622 for (int i = 0; i < specs[n].iovlen; i++) 1623 { 1624 pWsaBuf[i].buf = specs[n].iov[i].iov_base; 1625 pWsaBuf[i].len = specs[n].iov[i].iov_len; 1626 } 1627 msg.name = (void *) specs[n].dest_sa; 1628 msg.namelen = (AF_INET == specs[n].dest_sa->sa_family ? 1629 sizeof(struct sockaddr_in) : 1630 sizeof(struct sockaddr_in6)); 1631 msg.dwBufferCount = specs[n].iovlen; 1632 msg.lpBuffers = pWsaBuf; 1633 msg.dwFlags = 0; 1634#endif 1635 if ((sport->sp_flags & SPORT_SERVER) && specs[n].local_sa->sa_family) 1636 { 1637 cw = CW_SENDADDR; 1638 ancil_key = (uintptr_t) specs[n].local_sa; 1639 assert(0 == (ancil_key & 3)); 1640 } 1641 else 1642 { 1643 cw = 0; 1644 ancil_key = 0; 1645 } 1646#if ECN_SUPPORTED 1647 if (sport->sp_prog->prog_api.ea_settings->es_ecn && specs[n].ecn) 1648 { 1649 cw |= CW_ECN; 1650 ancil_key |= specs[n].ecn; 1651 } 1652#endif 1653 if (cw && prev_ancil_key == ancil_key) 1654 { 1655 /* Reuse previous ancillary message */ 1656 ; 1657 } 1658 else if (cw) 1659 { 1660 prev_ancil_key = ancil_key; 1661 setup_control_msg(&msg, cw, &specs[n], ancil.buf, sizeof(ancil.buf)); 1662 } 1663 else 1664 { 1665 prev_ancil_key = 0; 1666#ifndef WIN32 1667 msg.msg_control = NULL; 1668 msg.msg_controllen = 0; 1669#else 1670 msg.Control.buf = NULL; 1671 msg.Control.len = 0; 1672#endif 1673 } 1674#ifndef WIN32 1675 s = sendmsg(sport->fd, &msg, 0); 1676#else 1677 s = pfnWSASendMsg(sport->fd, &msg, 0, &bytes, NULL, NULL); 1678#endif 1679 if (s < 0) 1680 { 1681#ifndef WIN32 1682 LSQ_INFO("sendto failed: %s", strerror(errno)); 1683#else 1684 LSQ_INFO("sendto failed: %s", WSAGetLastError()); 1685#endif 1686 break; 1687 } 1688 ++n; 1689 } 1690 while (n < count); 1691 1692 if (n < orig_count) 1693 prog_sport_cant_send(sport->sp_prog, sport->fd); 1694 1695#ifdef WIN32 1696 if (NULL != pWsaBuf) { 1697 free(pWsaBuf); 1698 pWsaBuf = NULL; 1699 } 1700#endif 1701 1702 if (n > 0) 1703 { 1704 if (n < orig_count && out_limit) 1705 errno = EAGAIN; 1706 return n; 1707 } 1708 else 1709 { 1710 assert(s < 0); 1711#if LSQUIC_RANDOM_SEND_FAILURE 1712 random_send_failure: 1713#endif 1714 return -1; 1715 } 1716} 1717 1718 1719int 1720sport_packets_out (void *ctx, const struct lsquic_out_spec *specs, 1721 unsigned count) 1722{ 1723#if HAVE_SENDMMSG 1724 const struct prog *prog = ctx; 1725 if (prog->prog_use_sendmmsg) 1726 return send_packets_using_sendmmsg(specs, count); 1727 else 1728#endif 1729 return send_packets_one_by_one(specs, count); 1730} 1731 1732 1733int 1734set_engine_option (struct lsquic_engine_settings *settings, 1735 int *version_cleared, const char *name) 1736{ 1737 int len; 1738 const char *val = strchr(name, '='); 1739 if (!val) 1740 return -1; 1741 len = val - name; 1742 ++val; 1743 1744 switch (len) 1745 { 1746 case 2: 1747 if (0 == strncmp(name, "ua", 2)) 1748 { 1749 settings->es_ua = val; 1750 return 0; 1751 } 1752 break; 1753 case 3: 1754 if (0 == strncmp(name, "ecn", 1)) 1755 { 1756 settings->es_ecn = atoi(val); 1757#if !ECN_SUPPORTED 1758 if (settings->es_ecn) 1759 { 1760 LSQ_ERROR("ECN is not supported on this platform"); 1761 break; 1762 } 1763#endif 1764 return 0; 1765 } 1766 break; 1767 case 4: 1768 if (0 == strncmp(name, "cfcw", 4)) 1769 { 1770 settings->es_cfcw = atoi(val); 1771 return 0; 1772 } 1773 if (0 == strncmp(name, "sfcw", 4)) 1774 { 1775 settings->es_sfcw = atoi(val); 1776 return 0; 1777 } 1778 if (0 == strncmp(name, "spin", 4)) 1779 { 1780 settings->es_spin = atoi(val); 1781 return 0; 1782 } 1783 break; 1784 case 7: 1785 if (0 == strncmp(name, "version", 7)) 1786 { 1787 if (!*version_cleared) 1788 { 1789 *version_cleared = 1; 1790 settings->es_versions = 0; 1791 } 1792 enum lsquic_version ver = lsquic_str2ver(val, strlen(val)); 1793 if ((unsigned) ver < N_LSQVER) 1794 { 1795 settings->es_versions |= 1 << ver; 1796 return 0; 1797 } 1798 ver = lsquic_alpn2ver(val, strlen(val)); 1799 if ((unsigned) ver < N_LSQVER) 1800 { 1801 settings->es_versions |= 1 << ver; 1802 return 0; 1803 } 1804 } 1805 else if (0 == strncmp(name, "rw_once", 7)) 1806 { 1807 settings->es_rw_once = atoi(val); 1808 return 0; 1809 } 1810 else if (0 == strncmp(name, "cc_algo", 7)) 1811 { 1812 settings->es_cc_algo = atoi(val); 1813 return 0; 1814 } 1815 else if (0 == strncmp(name, "ql_bits", 7)) 1816 { 1817 settings->es_ql_bits = atoi(val); 1818 return 0; 1819 } 1820 break; 1821 case 8: 1822 if (0 == strncmp(name, "max_cfcw", 8)) 1823 { 1824 settings->es_max_cfcw = atoi(val); 1825 return 0; 1826 } 1827 if (0 == strncmp(name, "max_sfcw", 8)) 1828 { 1829 settings->es_max_sfcw = atoi(val); 1830 return 0; 1831 } 1832 if (0 == strncmp(name, "scid_len", 8)) 1833 { 1834 settings->es_scid_len = atoi(val); 1835 return 0; 1836 } 1837 if (0 == strncmp(name, "dplpmtud", 8)) 1838 { 1839 settings->es_dplpmtud = atoi(val); 1840 return 0; 1841 } 1842 break; 1843 case 9: 1844 if (0 == strncmp(name, "send_prst", 9)) 1845 { 1846 settings->es_send_prst = atoi(val); 1847 return 0; 1848 } 1849 break; 1850 case 10: 1851 if (0 == strncmp(name, "honor_prst", 10)) 1852 { 1853 settings->es_honor_prst = atoi(val); 1854 return 0; 1855 } 1856 if (0 == strncmp(name, "timestamps", 10)) 1857 { 1858 settings->es_timestamps = atoi(val); 1859 return 0; 1860 } 1861 if (0 == strncmp(name, "max_plpmtu", 10)) 1862 { 1863 settings->es_max_plpmtu = atoi(val); 1864 return 0; 1865 } 1866 break; 1867 case 11: 1868 if (0 == strncmp(name, "ping_period", 11)) 1869 { 1870 settings->es_ping_period = atoi(val); 1871 return 0; 1872 } 1873 if (0 == strncmp(name, "base_plpmtu", 11)) 1874 { 1875 settings->es_base_plpmtu = atoi(val); 1876 return 0; 1877 } 1878 if (0 == strncmp(name, "ptpc_target", 11)) 1879 { 1880 settings->es_ptpc_target = atof(val); 1881 return 0; 1882 } 1883 break; 1884 case 12: 1885 if (0 == strncmp(name, "idle_conn_to", 12)) 1886 { 1887 settings->es_idle_conn_to = atoi(val); 1888 return 0; 1889 } 1890 if (0 == strncmp(name, "idle_timeout", 12)) 1891 { 1892 settings->es_idle_timeout = atoi(val); 1893 return 0; 1894 } 1895 if (0 == strncmp(name, "silent_close", 12)) 1896 { 1897 settings->es_silent_close = atoi(val); 1898 return 0; 1899 } 1900 if (0 == strncmp(name, "support_push", 12)) 1901 { 1902 settings->es_support_push = atoi(val); 1903 return 0; 1904 } 1905 if (0 == strncmp(name, "support_nstp", 12)) 1906 { 1907 settings->es_support_nstp = atoi(val); 1908 return 0; 1909 } 1910 if (0 == strncmp(name, "pace_packets", 12)) 1911 { 1912 settings->es_pace_packets = atoi(val); 1913 return 0; 1914 } 1915 if (0 == strncmp(name, "handshake_to", 12)) 1916 { 1917 settings->es_handshake_to = atoi(val); 1918 return 0; 1919 } 1920 if (0 == strncmp(name, "delayed_acks", 12)) 1921 { 1922 settings->es_delayed_acks = atoi(val); 1923 return 0; 1924 } 1925 break; 1926 case 13: 1927 if (0 == strncmp(name, "support_tcid0", 13)) 1928 { 1929 settings->es_support_tcid0 = atoi(val); 1930 return 0; 1931 } 1932 if (0 == strncmp(name, "init_max_data", 13)) 1933 { 1934 settings->es_init_max_data = atoi(val); 1935 return 0; 1936 } 1937 if (0 == strncmp(name, "scid_iss_rate", 13)) 1938 { 1939 settings->es_scid_iss_rate = atoi(val); 1940 return 0; 1941 } 1942 if (0 == strncmp(name, "ext_http_prio", 13)) 1943 { 1944 settings->es_ext_http_prio = atoi(val); 1945 return 0; 1946 } 1947 if (0 == strncmp(name, "ptpc_int_gain", 13)) 1948 { 1949 settings->es_ptpc_int_gain = atof(val); 1950 return 0; 1951 } 1952 if (0 == strncmp(name, "delay_onclose", 13)) 1953 { 1954 settings->es_delay_onclose = atoi(val); 1955 return 0; 1956 } 1957 break; 1958 case 14: 1959 if (0 == strncmp(name, "max_streams_in", 14)) 1960 { 1961 settings->es_max_streams_in = atoi(val); 1962 return 0; 1963 } 1964 if (0 == strncmp(name, "progress_check", 14)) 1965 { 1966 settings->es_progress_check = atoi(val); 1967 return 0; 1968 } 1969 if (0 == strncmp(name, "ptpc_prop_gain", 14)) 1970 { 1971 settings->es_ptpc_prop_gain = atof(val); 1972 return 0; 1973 } 1974 if (0 == strncmp(name, "max_batch_size", 14)) 1975 { 1976 settings->es_max_batch_size = atoi(val); 1977 return 0; 1978 } 1979 break; 1980 case 15: 1981 if (0 == strncmp(name, "allow_migration", 15)) 1982 { 1983 settings->es_allow_migration = atoi(val); 1984 return 0; 1985 } 1986 if (0 == strncmp(name, "grease_quic_bit", 15)) 1987 { 1988 settings->es_grease_quic_bit = atoi(val); 1989 return 0; 1990 } 1991 if (0 == strncmp(name, "ptpc_dyn_target", 15)) 1992 { 1993 settings->es_ptpc_dyn_target = atoi(val); 1994 return 0; 1995 } 1996 if (0 == strncmp(name, "ptpc_err_thresh", 15)) 1997 { 1998 settings->es_ptpc_err_thresh = atof(val); 1999 return 0; 2000 } 2001 break; 2002 case 16: 2003 if (0 == strncmp(name, "proc_time_thresh", 16)) 2004 { 2005 settings->es_proc_time_thresh = atoi(val); 2006 return 0; 2007 } 2008 if (0 == strncmp(name, "qpack_experiment", 16)) 2009 { 2010 settings->es_qpack_experiment = atoi(val); 2011 return 0; 2012 } 2013 if (0 == strncmp(name, "ptpc_periodicity", 16)) 2014 { 2015 settings->es_ptpc_periodicity = atoi(val); 2016 return 0; 2017 } 2018 if (0 == strncmp(name, "ptpc_max_packtol", 16)) 2019 { 2020 settings->es_ptpc_max_packtol = atoi(val); 2021 return 0; 2022 } 2023 if (0 == strncmp(name, "ptpc_err_divisor", 16)) 2024 { 2025 settings->es_ptpc_err_divisor = atof(val); 2026 return 0; 2027 } 2028 break; 2029 case 18: 2030 if (0 == strncmp(name, "qpack_enc_max_size", 18)) 2031 { 2032 settings->es_qpack_enc_max_size = atoi(val); 2033 return 0; 2034 } 2035 if (0 == strncmp(name, "qpack_dec_max_size", 18)) 2036 { 2037 settings->es_qpack_dec_max_size = atoi(val); 2038 return 0; 2039 } 2040 if (0 == strncmp(name, "noprogress_timeout", 18)) 2041 { 2042 settings->es_noprogress_timeout = atoi(val); 2043 return 0; 2044 } 2045 break; 2046 case 20: 2047 if (0 == strncmp(name, "max_header_list_size", 20)) 2048 { 2049 settings->es_max_header_list_size = atoi(val); 2050 return 0; 2051 } 2052 if (0 == strncmp(name, "init_max_streams_uni", 20)) 2053 { 2054 settings->es_init_max_streams_uni = atoi(val); 2055 return 0; 2056 } 2057 break; 2058 case 21: 2059 if (0 == strncmp(name, "qpack_enc_max_blocked", 21)) 2060 { 2061 settings->es_qpack_enc_max_blocked = atoi(val); 2062 return 0; 2063 } 2064 if (0 == strncmp(name, "qpack_dec_max_blocked", 21)) 2065 { 2066 settings->es_qpack_dec_max_blocked = atoi(val); 2067 return 0; 2068 } 2069 if (0 == strncmp(name, "init_max_streams_bidi", 21)) 2070 { 2071 settings->es_init_max_streams_bidi = atoi(val); 2072 return 0; 2073 } 2074 break; 2075 case 23: 2076 if (0 == strncmp(name, "max_udp_payload_size_rx", 23)) 2077 { 2078 settings->es_max_udp_payload_size_rx = atoi(val); 2079 return 0; 2080 } 2081 break; 2082 case 24: 2083 if (0 == strncmp(name, "init_max_stream_data_uni", 24)) 2084 { 2085 settings->es_init_max_stream_data_uni = atoi(val); 2086 return 0; 2087 } 2088 break; 2089 case 31: 2090 if (0 == strncmp(name, "init_max_stream_data_bidi_local", 31)) 2091 { 2092 settings->es_init_max_stream_data_bidi_local = atoi(val); 2093 return 0; 2094 } 2095 break; 2096 case 32: 2097 if (0 == strncmp(name, "init_max_stream_data_bidi_remote", 32)) 2098 { 2099 settings->es_init_max_stream_data_bidi_remote = atoi(val); 2100 return 0; 2101 } 2102 break; 2103 } 2104 2105 return -1; 2106} 2107 2108 2109/* So that largest allocation in PBA fits in 4KB */ 2110#define PBA_SIZE_MAX 0x1000 2111#define PBA_SIZE_THRESH (PBA_SIZE_MAX - sizeof(uintptr_t)) 2112 2113struct packout_buf 2114{ 2115 SLIST_ENTRY(packout_buf) next_free_pb; 2116}; 2117 2118 2119void 2120pba_init (struct packout_buf_allocator *pba, unsigned max) 2121{ 2122 SLIST_INIT(&pba->free_packout_bufs); 2123 pba->max = max; 2124 pba->n_out = 0; 2125} 2126 2127 2128void * 2129pba_allocate (void *packout_buf_allocator, void *peer_ctx, 2130 lsquic_conn_ctx_t *conn_ctx, unsigned short size, char is_ipv6) 2131{ 2132 struct packout_buf_allocator *const pba = packout_buf_allocator; 2133 struct packout_buf *pb; 2134 2135 if (pba->max && pba->n_out >= pba->max) 2136 { 2137 LSQ_DEBUG("# outstanding packout bufs reached the limit of %u, " 2138 "returning NULL", pba->max); 2139 return NULL; 2140 } 2141 2142#if LSQUIC_USE_POOLS 2143 pb = SLIST_FIRST(&pba->free_packout_bufs); 2144 if (pb && size <= PBA_SIZE_THRESH) 2145 SLIST_REMOVE_HEAD(&pba->free_packout_bufs, next_free_pb); 2146 else if (size <= PBA_SIZE_THRESH) 2147 pb = malloc(PBA_SIZE_MAX); 2148 else 2149 pb = malloc(sizeof(uintptr_t) + size); 2150#else 2151 pb = malloc(sizeof(uintptr_t) + size); 2152#endif 2153 2154 if (pb) 2155 { 2156 * (uintptr_t *) pb = size; 2157 ++pba->n_out; 2158 return (uintptr_t *) pb + 1; 2159 } 2160 else 2161 return NULL; 2162} 2163 2164 2165void 2166pba_release (void *packout_buf_allocator, void *peer_ctx, void *obj, char ipv6) 2167{ 2168 struct packout_buf_allocator *const pba = packout_buf_allocator; 2169 obj = (uintptr_t *) obj - 1; 2170#if LSQUIC_USE_POOLS 2171 if (* (uintptr_t *) obj <= PBA_SIZE_THRESH) 2172 { 2173 struct packout_buf *const pb = obj; 2174 SLIST_INSERT_HEAD(&pba->free_packout_bufs, pb, next_free_pb); 2175 } 2176 else 2177#endif 2178 free(obj); 2179 --pba->n_out; 2180} 2181 2182 2183void 2184pba_cleanup (struct packout_buf_allocator *pba) 2185{ 2186#if LSQUIC_USE_POOLS 2187 unsigned n = 0; 2188 struct packout_buf *pb; 2189#endif 2190 2191 if (pba->n_out) 2192 LSQ_WARN("%u packout bufs outstanding at deinit", pba->n_out); 2193 2194#if LSQUIC_USE_POOLS 2195 while ((pb = SLIST_FIRST(&pba->free_packout_bufs))) 2196 { 2197 SLIST_REMOVE_HEAD(&pba->free_packout_bufs, next_free_pb); 2198 free(pb); 2199 ++n; 2200 } 2201 2202 LSQ_INFO("pba deinitialized, freed %u packout bufs", n); 2203#endif 2204} 2205 2206 2207void 2208print_conn_info (const lsquic_conn_t *conn) 2209{ 2210 const char *cipher; 2211 2212 cipher = lsquic_conn_crypto_cipher(conn); 2213 2214 LSQ_INFO("Connection info: version: %u; cipher: %s; key size: %d, alg key size: %d", 2215 lsquic_conn_quic_version(conn), 2216 cipher ? cipher : "<null>", 2217 lsquic_conn_crypto_keysize(conn), 2218 lsquic_conn_crypto_alg_keysize(conn) 2219 ); 2220} 2221 2222 2223struct reader_ctx 2224{ 2225 size_t file_size; 2226 size_t nread; 2227 int fd; 2228}; 2229 2230 2231size_t 2232test_reader_size (void *void_ctx) 2233{ 2234 struct reader_ctx *const ctx = void_ctx; 2235 return ctx->file_size - ctx->nread; 2236} 2237 2238 2239size_t 2240test_reader_read (void *void_ctx, void *buf, size_t count) 2241{ 2242 struct reader_ctx *const ctx = void_ctx; 2243 ssize_t nread; 2244 2245 if (count > test_reader_size(ctx)) 2246 count = test_reader_size(ctx); 2247 2248#ifndef WIN32 2249 nread = read(ctx->fd, buf, count); 2250#else 2251 nread = _read(ctx->fd, buf, count); 2252#endif 2253 if (nread >= 0) 2254 { 2255 ctx->nread += nread; 2256 return nread; 2257 } 2258 else 2259 { 2260 LSQ_WARN("%s: error reading from file: %s", __func__, strerror(errno)); 2261 ctx->nread = ctx->file_size = 0; 2262 return 0; 2263 } 2264} 2265 2266 2267struct reader_ctx * 2268create_lsquic_reader_ctx (const char *filename) 2269{ 2270 int fd; 2271 struct stat st; 2272 2273#ifndef WIN32 2274 fd = open(filename, O_RDONLY); 2275#else 2276 fd = _open(filename, _O_RDONLY); 2277#endif 2278 if (fd < 0) 2279 { 2280 LSQ_ERROR("cannot open %s for reading: %s", filename, strerror(errno)); 2281 return NULL; 2282 } 2283 2284 if (0 != fstat(fd, &st)) 2285 { 2286 LSQ_ERROR("cannot fstat(%s) failed: %s", filename, strerror(errno)); 2287 (void) close(fd); 2288 return NULL; 2289 } 2290 struct reader_ctx *ctx = malloc(sizeof(*ctx)); 2291 ctx->file_size = st.st_size; 2292 ctx->nread = 0; 2293 ctx->fd = fd; 2294 return ctx; 2295} 2296 2297 2298void 2299destroy_lsquic_reader_ctx (struct reader_ctx *ctx) 2300{ 2301 (void) close(ctx->fd); 2302 free(ctx); 2303} 2304 2305 2306int 2307sport_set_token (struct service_port *sport, const char *token_str) 2308{ 2309 static const unsigned char c2b[0x100] = 2310 { 2311 [(int)'0'] = 0, 2312 [(int)'1'] = 1, 2313 [(int)'2'] = 2, 2314 [(int)'3'] = 3, 2315 [(int)'4'] = 4, 2316 [(int)'5'] = 5, 2317 [(int)'6'] = 6, 2318 [(int)'7'] = 7, 2319 [(int)'8'] = 8, 2320 [(int)'9'] = 9, 2321 [(int)'A'] = 0xA, 2322 [(int)'B'] = 0xB, 2323 [(int)'C'] = 0xC, 2324 [(int)'D'] = 0xD, 2325 [(int)'E'] = 0xE, 2326 [(int)'F'] = 0xF, 2327 [(int)'a'] = 0xA, 2328 [(int)'b'] = 0xB, 2329 [(int)'c'] = 0xC, 2330 [(int)'d'] = 0xD, 2331 [(int)'e'] = 0xE, 2332 [(int)'f'] = 0xF, 2333 }; 2334 unsigned char *token; 2335 int len, i; 2336 2337 len = strlen(token_str); 2338 token = malloc(len / 2); 2339 if (!token) 2340 return -1; 2341 for (i = 0; i < len / 2; ++i) 2342 token[i] = (c2b[ (int) token_str[i * 2] ] << 4) 2343 | c2b[ (int) token_str[i * 2 + 1] ]; 2344 2345 free(sport->sp_token_buf); 2346 sport->sp_token_buf = token; 2347 sport->sp_token_sz = len / 2; 2348 return 0; 2349} 2350 2351 2352int 2353header_set_ptr (struct lsxpack_header *hdr, struct header_buf *header_buf, 2354 const char *name, size_t name_len, 2355 const char *val, size_t val_len) 2356{ 2357 if (header_buf->off + name_len + val_len <= sizeof(header_buf->buf)) 2358 { 2359 memcpy(header_buf->buf + header_buf->off, name, name_len); 2360 memcpy(header_buf->buf + header_buf->off + name_len, val, val_len); 2361 lsxpack_header_set_offset2(hdr, header_buf->buf + header_buf->off, 2362 0, name_len, name_len, val_len); 2363 header_buf->off += name_len + val_len; 2364 return 0; 2365 } 2366 else 2367 return -1; 2368} 2369