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