| 447 | } |
| 448 | |
| 449 | bool send_batch(batched_send_info_t &send_info) { |
| 450 | auto sockfd = (int) send_info.native_socket; |
| 451 | struct msghdr msg = {}; |
| 452 | |
| 453 | // Convert the target address into a sockaddr |
| 454 | struct sockaddr_in taddr_v4 = {}; |
| 455 | struct sockaddr_in6 taddr_v6 = {}; |
| 456 | if (send_info.target_address.is_v6()) { |
| 457 | taddr_v6 = to_sockaddr(send_info.target_address.to_v6(), send_info.target_port); |
| 458 | |
| 459 | msg.msg_name = (struct sockaddr *) &taddr_v6; |
| 460 | msg.msg_namelen = sizeof(taddr_v6); |
| 461 | } else { |
| 462 | taddr_v4 = to_sockaddr(send_info.target_address.to_v4(), send_info.target_port); |
| 463 | |
| 464 | msg.msg_name = (struct sockaddr *) &taddr_v4; |
| 465 | msg.msg_namelen = sizeof(taddr_v4); |
| 466 | } |
| 467 | |
| 468 | union { |
| 469 | char buf[CMSG_SPACE(sizeof(uint16_t)) + std::max(CMSG_SPACE(sizeof(struct in_pktinfo)), CMSG_SPACE(sizeof(struct in6_pktinfo)))]; |
| 470 | struct cmsghdr alignment; |
| 471 | } cmbuf = {}; // Must be zeroed for CMSG_NXTHDR() |
| 472 | |
| 473 | socklen_t cmbuflen = 0; |
| 474 | |
| 475 | msg.msg_control = cmbuf.buf; |
| 476 | msg.msg_controllen = sizeof(cmbuf.buf); |
| 477 | |
| 478 | // The PKTINFO option will always be first, then we will conditionally |
| 479 | // append the UDP_SEGMENT option next if applicable. |
| 480 | auto pktinfo_cm = CMSG_FIRSTHDR(&msg); |
| 481 | if (send_info.source_address.is_v6()) { |
| 482 | struct in6_pktinfo pktInfo; |
| 483 | |
| 484 | struct sockaddr_in6 saddr_v6 = to_sockaddr(send_info.source_address.to_v6(), 0); |
| 485 | pktInfo.ipi6_addr = saddr_v6.sin6_addr; |
| 486 | pktInfo.ipi6_ifindex = 0; |
| 487 | |
| 488 | cmbuflen += CMSG_SPACE(sizeof(pktInfo)); |
| 489 | |
| 490 | pktinfo_cm->cmsg_level = IPPROTO_IPV6; |
| 491 | pktinfo_cm->cmsg_type = IPV6_PKTINFO; |
| 492 | pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo)); |
| 493 | memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo)); |
| 494 | } else { |
| 495 | struct in_pktinfo pktInfo; |
| 496 | |
| 497 | struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0); |
| 498 | pktInfo.ipi_spec_dst = saddr_v4.sin_addr; |
| 499 | pktInfo.ipi_ifindex = 0; |
| 500 | |
| 501 | cmbuflen += CMSG_SPACE(sizeof(pktInfo)); |
| 502 | |
| 503 | pktinfo_cm->cmsg_level = IPPROTO_IP; |
| 504 | pktinfo_cm->cmsg_type = IP_PKTINFO; |
| 505 | pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo)); |
| 506 | memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo)); |
no test coverage detected