test_common.c revision fecdd104
1/* Copyright (c) 2017 - 2020 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 "test_common.h" 45#include "lsquic.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 WSABUF wsaBuf; 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 do 1599 { 1600 sport = specs[n].peer_ctx; 1601#if LSQUIC_PREFERRED_ADDR 1602 if (sport->sp_prog->prog_flags & PROG_SEARCH_ADDRS) 1603 sport = find_sport(sport->sp_prog, specs[n].local_sa); 1604#endif 1605#ifndef WIN32 1606 msg.msg_name = (void *) specs[n].dest_sa; 1607 msg.msg_namelen = (AF_INET == specs[n].dest_sa->sa_family ? 1608 sizeof(struct sockaddr_in) : 1609 sizeof(struct sockaddr_in6)), 1610 msg.msg_iov = specs[n].iov; 1611 msg.msg_iovlen = specs[n].iovlen; 1612 msg.msg_flags = 0; 1613#else 1614 wsaBuf.buf = specs[n].iov->iov_base; 1615 wsaBuf.len = specs[n].iov->iov_len; 1616 msg.name = (void *) specs[n].dest_sa; 1617 msg.namelen = (AF_INET == specs[n].dest_sa->sa_family ? 1618 sizeof(struct sockaddr_in) : 1619 sizeof(struct sockaddr_in6)); 1620 msg.dwBufferCount = 1; 1621 msg.lpBuffers = &wsaBuf; 1622 msg.dwFlags = 0; 1623#endif 1624 if ((sport->sp_flags & SPORT_SERVER) && specs[n].local_sa->sa_family) 1625 { 1626 cw = CW_SENDADDR; 1627 ancil_key = (uintptr_t) specs[n].local_sa; 1628 assert(0 == (ancil_key & 3)); 1629 } 1630 else 1631 { 1632 cw = 0; 1633 ancil_key = 0; 1634 } 1635#if ECN_SUPPORTED 1636 if (sport->sp_prog->prog_api.ea_settings->es_ecn && specs[n].ecn) 1637 { 1638 cw |= CW_ECN; 1639 ancil_key |= specs[n].ecn; 1640 } 1641#endif 1642 if (cw && prev_ancil_key == ancil_key) 1643 { 1644 /* Reuse previous ancillary message */ 1645 ; 1646 } 1647 else if (cw) 1648 { 1649 prev_ancil_key = ancil_key; 1650 setup_control_msg(&msg, cw, &specs[n], ancil.buf, sizeof(ancil.buf)); 1651 } 1652 else 1653 { 1654 prev_ancil_key = 0; 1655#ifndef WIN32 1656 msg.msg_control = NULL; 1657 msg.msg_controllen = 0; 1658#else 1659 msg.Control.buf = NULL; 1660 msg.Control.len = 0; 1661#endif 1662 } 1663#ifndef WIN32 1664 s = sendmsg(sport->fd, &msg, 0); 1665#else 1666 s = pfnWSASendMsg(sport->fd, &msg, 0, &bytes, NULL, NULL); 1667#endif 1668 if (s < 0) 1669 { 1670#ifndef WIN32 1671 LSQ_INFO("sendto failed: %s", strerror(errno)); 1672#else 1673 LSQ_INFO("sendto failed: %s", WSAGetLastError()); 1674#endif 1675 break; 1676 } 1677 ++n; 1678 } 1679 while (n < count); 1680 1681 if (n < orig_count) 1682 prog_sport_cant_send(sport->sp_prog, sport->fd); 1683 1684 if (n > 0) 1685 { 1686 if (n < orig_count && out_limit) 1687 errno = EAGAIN; 1688 return n; 1689 } 1690 else 1691 { 1692 assert(s < 0); 1693#if LSQUIC_RANDOM_SEND_FAILURE 1694 random_send_failure: 1695#endif 1696 return -1; 1697 } 1698} 1699 1700 1701int 1702sport_packets_out (void *ctx, const struct lsquic_out_spec *specs, 1703 unsigned count) 1704{ 1705#if HAVE_SENDMMSG 1706 const struct prog *prog = ctx; 1707 if (prog->prog_use_sendmmsg) 1708 return send_packets_using_sendmmsg(specs, count); 1709 else 1710#endif 1711 return send_packets_one_by_one(specs, count); 1712} 1713 1714 1715int 1716set_engine_option (struct lsquic_engine_settings *settings, 1717 int *version_cleared, const char *name) 1718{ 1719 int len; 1720 const char *val = strchr(name, '='); 1721 if (!val) 1722 return -1; 1723 len = val - name; 1724 ++val; 1725 1726 switch (len) 1727 { 1728 case 2: 1729 if (0 == strncmp(name, "ua", 2)) 1730 { 1731 settings->es_ua = val; 1732 return 0; 1733 } 1734 break; 1735 case 3: 1736 if (0 == strncmp(name, "ecn", 1)) 1737 { 1738 settings->es_ecn = atoi(val); 1739#if !ECN_SUPPORTED 1740 if (settings->es_ecn) 1741 { 1742 LSQ_ERROR("ECN is not supported on this platform"); 1743 break; 1744 } 1745#endif 1746 return 0; 1747 } 1748 break; 1749 case 4: 1750 if (0 == strncmp(name, "cfcw", 4)) 1751 { 1752 settings->es_cfcw = atoi(val); 1753 return 0; 1754 } 1755 if (0 == strncmp(name, "sfcw", 4)) 1756 { 1757 settings->es_sfcw = atoi(val); 1758 return 0; 1759 } 1760 if (0 == strncmp(name, "spin", 4)) 1761 { 1762 settings->es_spin = atoi(val); 1763 return 0; 1764 } 1765 break; 1766 case 7: 1767 if (0 == strncmp(name, "version", 7)) 1768 { 1769 if (!*version_cleared) 1770 { 1771 *version_cleared = 1; 1772 settings->es_versions = 0; 1773 } 1774 enum lsquic_version ver = lsquic_str2ver(val, strlen(val)); 1775 if ((unsigned) ver < N_LSQVER) 1776 { 1777 settings->es_versions |= 1 << ver; 1778 return 0; 1779 } 1780 ver = lsquic_alpn2ver(val, strlen(val)); 1781 if ((unsigned) ver < N_LSQVER) 1782 { 1783 settings->es_versions |= 1 << ver; 1784 return 0; 1785 } 1786 } 1787 else if (0 == strncmp(name, "rw_once", 7)) 1788 { 1789 settings->es_rw_once = atoi(val); 1790 return 0; 1791 } 1792 else if (0 == strncmp(name, "cc_algo", 7)) 1793 { 1794 settings->es_cc_algo = atoi(val); 1795 return 0; 1796 } 1797 else if (0 == strncmp(name, "ql_bits", 7)) 1798 { 1799 settings->es_ql_bits = atoi(val); 1800 return 0; 1801 } 1802 break; 1803 case 8: 1804 if (0 == strncmp(name, "max_cfcw", 8)) 1805 { 1806 settings->es_max_cfcw = atoi(val); 1807 return 0; 1808 } 1809 if (0 == strncmp(name, "max_sfcw", 8)) 1810 { 1811 settings->es_max_sfcw = atoi(val); 1812 return 0; 1813 } 1814 if (0 == strncmp(name, "scid_len", 8)) 1815 { 1816 settings->es_scid_len = atoi(val); 1817 return 0; 1818 } 1819 if (0 == strncmp(name, "dplpmtud", 8)) 1820 { 1821 settings->es_dplpmtud = atoi(val); 1822 return 0; 1823 } 1824 break; 1825 case 9: 1826 if (0 == strncmp(name, "send_prst", 9)) 1827 { 1828 settings->es_send_prst = atoi(val); 1829 return 0; 1830 } 1831 break; 1832 case 10: 1833 if (0 == strncmp(name, "honor_prst", 10)) 1834 { 1835 settings->es_honor_prst = atoi(val); 1836 return 0; 1837 } 1838 if (0 == strncmp(name, "timestamps", 10)) 1839 { 1840 settings->es_timestamps = atoi(val); 1841 return 0; 1842 } 1843 if (0 == strncmp(name, "max_plpmtu", 10)) 1844 { 1845 settings->es_max_plpmtu = atoi(val); 1846 return 0; 1847 } 1848 break; 1849 case 11: 1850 if (0 == strncmp(name, "ping_period", 11)) 1851 { 1852 settings->es_ping_period = atoi(val); 1853 return 0; 1854 } 1855 if (0 == strncmp(name, "base_plpmtu", 11)) 1856 { 1857 settings->es_base_plpmtu = atoi(val); 1858 return 0; 1859 } 1860 break; 1861 case 12: 1862 if (0 == strncmp(name, "idle_conn_to", 12)) 1863 { 1864 settings->es_idle_conn_to = atoi(val); 1865 return 0; 1866 } 1867 if (0 == strncmp(name, "idle_timeout", 12)) 1868 { 1869 settings->es_idle_timeout = atoi(val); 1870 return 0; 1871 } 1872 if (0 == strncmp(name, "silent_close", 12)) 1873 { 1874 settings->es_silent_close = atoi(val); 1875 return 0; 1876 } 1877 if (0 == strncmp(name, "support_push", 12)) 1878 { 1879 settings->es_support_push = atoi(val); 1880 return 0; 1881 } 1882 if (0 == strncmp(name, "support_nstp", 12)) 1883 { 1884 settings->es_support_nstp = atoi(val); 1885 return 0; 1886 } 1887 if (0 == strncmp(name, "pace_packets", 12)) 1888 { 1889 settings->es_pace_packets = atoi(val); 1890 return 0; 1891 } 1892 if (0 == strncmp(name, "handshake_to", 12)) 1893 { 1894 settings->es_handshake_to = atoi(val); 1895 return 0; 1896 } 1897 if (0 == strncmp(name, "delayed_acks", 12)) 1898 { 1899 settings->es_delayed_acks = atoi(val); 1900 return 0; 1901 } 1902 break; 1903 case 13: 1904 if (0 == strncmp(name, "support_tcid0", 13)) 1905 { 1906 settings->es_support_tcid0 = atoi(val); 1907 return 0; 1908 } 1909 if (0 == strncmp(name, "init_max_data", 13)) 1910 { 1911 settings->es_init_max_data = atoi(val); 1912 return 0; 1913 } 1914 if (0 == strncmp(name, "scid_iss_rate", 13)) 1915 { 1916 settings->es_scid_iss_rate = atoi(val); 1917 return 0; 1918 } 1919 break; 1920 case 14: 1921 if (0 == strncmp(name, "max_streams_in", 14)) 1922 { 1923 settings->es_max_streams_in = atoi(val); 1924 return 0; 1925 } 1926 if (0 == strncmp(name, "progress_check", 14)) 1927 { 1928 settings->es_progress_check = atoi(val); 1929 return 0; 1930 } 1931 break; 1932 case 15: 1933 if (0 == strncmp(name, "allow_migration", 15)) 1934 { 1935 settings->es_allow_migration = atoi(val); 1936 return 0; 1937 } 1938 if (0 == strncmp(name, "grease_quic_bit", 15)) 1939 { 1940 settings->es_grease_quic_bit = atoi(val); 1941 return 0; 1942 } 1943 break; 1944 case 16: 1945 if (0 == strncmp(name, "proc_time_thresh", 16)) 1946 { 1947 settings->es_proc_time_thresh = atoi(val); 1948 return 0; 1949 } 1950 break; 1951 case 18: 1952 if (0 == strncmp(name, "qpack_enc_max_size", 18)) 1953 { 1954 settings->es_qpack_enc_max_size = atoi(val); 1955 return 0; 1956 } 1957 if (0 == strncmp(name, "qpack_dec_max_size", 18)) 1958 { 1959 settings->es_qpack_dec_max_size = atoi(val); 1960 return 0; 1961 } 1962 if (0 == strncmp(name, "noprogress_timeout", 18)) 1963 { 1964 settings->es_noprogress_timeout = atoi(val); 1965 return 0; 1966 } 1967 break; 1968 case 20: 1969 if (0 == strncmp(name, "max_header_list_size", 20)) 1970 { 1971 settings->es_max_header_list_size = atoi(val); 1972 return 0; 1973 } 1974 if (0 == strncmp(name, "init_max_streams_uni", 20)) 1975 { 1976 settings->es_init_max_streams_uni = atoi(val); 1977 return 0; 1978 } 1979 break; 1980 case 21: 1981 if (0 == strncmp(name, "qpack_enc_max_blocked", 21)) 1982 { 1983 settings->es_qpack_enc_max_blocked = atoi(val); 1984 return 0; 1985 } 1986 if (0 == strncmp(name, "qpack_dec_max_blocked", 21)) 1987 { 1988 settings->es_qpack_dec_max_blocked = atoi(val); 1989 return 0; 1990 } 1991 break; 1992 case 23: 1993 if (0 == strncmp(name, "max_udp_payload_size_rx", 23)) 1994 { 1995 settings->es_max_udp_payload_size_rx = atoi(val); 1996 return 0; 1997 } 1998 break; 1999 case 24: 2000 if (0 == strncmp(name, "init_max_stream_data_uni", 24)) 2001 { 2002 settings->es_init_max_stream_data_uni = atoi(val); 2003 return 0; 2004 } 2005 break; 2006 case 31: 2007 if (0 == strncmp(name, "init_max_stream_data_bidi_local", 31)) 2008 { 2009 settings->es_init_max_stream_data_bidi_local = atoi(val); 2010 return 0; 2011 } 2012 break; 2013 case 32: 2014 if (0 == strncmp(name, "init_max_stream_data_bidi_remote", 32)) 2015 { 2016 settings->es_init_max_stream_data_bidi_remote = atoi(val); 2017 return 0; 2018 } 2019 break; 2020 } 2021 2022 return -1; 2023} 2024 2025 2026/* So that largest allocation in PBA fits in 4KB */ 2027#define PBA_SIZE_MAX 0x1000 2028#define PBA_SIZE_THRESH (PBA_SIZE_MAX - sizeof(uintptr_t)) 2029 2030struct packout_buf 2031{ 2032 SLIST_ENTRY(packout_buf) next_free_pb; 2033}; 2034 2035 2036void 2037pba_init (struct packout_buf_allocator *pba, unsigned max) 2038{ 2039 SLIST_INIT(&pba->free_packout_bufs); 2040 pba->max = max; 2041 pba->n_out = 0; 2042} 2043 2044 2045void * 2046pba_allocate (void *packout_buf_allocator, void *peer_ctx, void *conn_ctx, unsigned short size, 2047 char is_ipv6) 2048{ 2049 struct packout_buf_allocator *const pba = packout_buf_allocator; 2050 struct packout_buf *pb; 2051 2052 if (pba->max && pba->n_out >= pba->max) 2053 { 2054 LSQ_DEBUG("# outstanding packout bufs reached the limit of %u, " 2055 "returning NULL", pba->max); 2056 return NULL; 2057 } 2058 2059#if LSQUIC_USE_POOLS 2060 pb = SLIST_FIRST(&pba->free_packout_bufs); 2061 if (pb && size <= PBA_SIZE_THRESH) 2062 SLIST_REMOVE_HEAD(&pba->free_packout_bufs, next_free_pb); 2063 else if (size <= PBA_SIZE_THRESH) 2064 pb = malloc(PBA_SIZE_MAX); 2065 else 2066 pb = malloc(sizeof(uintptr_t) + size); 2067#else 2068 pb = malloc(sizeof(uintptr_t) + size); 2069#endif 2070 2071 if (pb) 2072 { 2073 * (uintptr_t *) pb = size; 2074 ++pba->n_out; 2075 return (uintptr_t *) pb + 1; 2076 } 2077 else 2078 return NULL; 2079} 2080 2081 2082void 2083pba_release (void *packout_buf_allocator, void *peer_ctx, void *obj, char ipv6) 2084{ 2085 struct packout_buf_allocator *const pba = packout_buf_allocator; 2086 obj = (uintptr_t *) obj - 1; 2087#if LSQUIC_USE_POOLS 2088 if (* (uintptr_t *) obj <= PBA_SIZE_THRESH) 2089 { 2090 struct packout_buf *const pb = obj; 2091 SLIST_INSERT_HEAD(&pba->free_packout_bufs, pb, next_free_pb); 2092 } 2093 else 2094#endif 2095 free(obj); 2096 --pba->n_out; 2097} 2098 2099 2100void 2101pba_cleanup (struct packout_buf_allocator *pba) 2102{ 2103#if LSQUIC_USE_POOLS 2104 unsigned n = 0; 2105 struct packout_buf *pb; 2106#endif 2107 2108 if (pba->n_out) 2109 LSQ_WARN("%u packout bufs outstanding at deinit", pba->n_out); 2110 2111#if LSQUIC_USE_POOLS 2112 while ((pb = SLIST_FIRST(&pba->free_packout_bufs))) 2113 { 2114 SLIST_REMOVE_HEAD(&pba->free_packout_bufs, next_free_pb); 2115 free(pb); 2116 ++n; 2117 } 2118 2119 LSQ_INFO("pba deinitialized, freed %u packout bufs", n); 2120#endif 2121} 2122 2123 2124void 2125print_conn_info (const lsquic_conn_t *conn) 2126{ 2127 const char *cipher; 2128 2129 cipher = lsquic_conn_crypto_cipher(conn); 2130 2131 LSQ_INFO("Connection info: version: %u; cipher: %s; key size: %d, alg key size: %d", 2132 lsquic_conn_quic_version(conn), 2133 cipher ? cipher : "<null>", 2134 lsquic_conn_crypto_keysize(conn), 2135 lsquic_conn_crypto_alg_keysize(conn) 2136 ); 2137} 2138 2139 2140struct reader_ctx 2141{ 2142 size_t file_size; 2143 size_t nread; 2144 int fd; 2145}; 2146 2147 2148size_t 2149test_reader_size (void *void_ctx) 2150{ 2151 struct reader_ctx *const ctx = void_ctx; 2152 return ctx->file_size - ctx->nread; 2153} 2154 2155 2156size_t 2157test_reader_read (void *void_ctx, void *buf, size_t count) 2158{ 2159 struct reader_ctx *const ctx = void_ctx; 2160 ssize_t nread; 2161 2162 if (count > test_reader_size(ctx)) 2163 count = test_reader_size(ctx); 2164 2165#ifndef WIN32 2166 nread = read(ctx->fd, buf, count); 2167#else 2168 nread = _read(ctx->fd, buf, count); 2169#endif 2170 if (nread >= 0) 2171 { 2172 ctx->nread += nread; 2173 return nread; 2174 } 2175 else 2176 { 2177 LSQ_WARN("%s: error reading from file: %s", __func__, strerror(errno)); 2178 ctx->nread = ctx->file_size = 0; 2179 return 0; 2180 } 2181} 2182 2183 2184struct reader_ctx * 2185create_lsquic_reader_ctx (const char *filename) 2186{ 2187 int fd; 2188 struct stat st; 2189 2190#ifndef WIN32 2191 fd = open(filename, O_RDONLY); 2192#else 2193 fd = _open(filename, _O_RDONLY); 2194#endif 2195 if (fd < 0) 2196 { 2197 LSQ_ERROR("cannot open %s for reading: %s", filename, strerror(errno)); 2198 return NULL; 2199 } 2200 2201 if (0 != fstat(fd, &st)) 2202 { 2203 LSQ_ERROR("cannot fstat(%s) failed: %s", filename, strerror(errno)); 2204 (void) close(fd); 2205 return NULL; 2206 } 2207 struct reader_ctx *ctx = malloc(sizeof(*ctx)); 2208 ctx->file_size = st.st_size; 2209 ctx->nread = 0; 2210 ctx->fd = fd; 2211 return ctx; 2212} 2213 2214 2215void 2216destroy_lsquic_reader_ctx (struct reader_ctx *ctx) 2217{ 2218 (void) close(ctx->fd); 2219 free(ctx); 2220} 2221 2222 2223int 2224sport_set_token (struct service_port *sport, const char *token_str) 2225{ 2226 static const unsigned char c2b[0x100] = 2227 { 2228 [(int)'0'] = 0, 2229 [(int)'1'] = 1, 2230 [(int)'2'] = 2, 2231 [(int)'3'] = 3, 2232 [(int)'4'] = 4, 2233 [(int)'5'] = 5, 2234 [(int)'6'] = 6, 2235 [(int)'7'] = 7, 2236 [(int)'8'] = 8, 2237 [(int)'9'] = 9, 2238 [(int)'A'] = 0xA, 2239 [(int)'B'] = 0xB, 2240 [(int)'C'] = 0xC, 2241 [(int)'D'] = 0xD, 2242 [(int)'E'] = 0xE, 2243 [(int)'F'] = 0xF, 2244 [(int)'a'] = 0xA, 2245 [(int)'b'] = 0xB, 2246 [(int)'c'] = 0xC, 2247 [(int)'d'] = 0xD, 2248 [(int)'e'] = 0xE, 2249 [(int)'f'] = 0xF, 2250 }; 2251 unsigned char *token; 2252 int len, i; 2253 2254 len = strlen(token_str); 2255 token = malloc(len / 2); 2256 if (!token) 2257 return -1; 2258 for (i = 0; i < len / 2; ++i) 2259 token[i] = (c2b[ (int) token_str[i * 2] ] << 4) 2260 | c2b[ (int) token_str[i * 2 + 1] ]; 2261 2262 free(sport->sp_token_buf); 2263 sport->sp_token_buf = token; 2264 sport->sp_token_sz = len / 2; 2265 return 0; 2266} 2267 2268 2269int 2270header_set_ptr (struct lsxpack_header *hdr, struct header_buf *header_buf, 2271 const char *name, size_t name_len, 2272 const char *val, size_t val_len) 2273{ 2274 if (header_buf->off + name_len + val_len <= sizeof(header_buf->buf)) 2275 { 2276 memcpy(header_buf->buf + header_buf->off, name, name_len); 2277 memcpy(header_buf->buf + header_buf->off + name_len, val, val_len); 2278 lsxpack_header_set_offset2(hdr, header_buf->buf + header_buf->off, 2279 0, name_len, name_len, val_len); 2280 header_buf->off += name_len + val_len; 2281 return 0; 2282 } 2283 else 2284 return -1; 2285} 2286