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