* Send a packet over UDP * @param p the packet to send * @param recv the receiver (target) of the packet * @param all send the packet using all sockets that can send it * @param broadcast whether to send a broadcast message */
| 72 | * @param broadcast whether to send a broadcast message |
| 73 | */ |
| 74 | void NetworkUDPSocketHandler::SendPacket(Packet &p, NetworkAddress &recv, bool all, bool broadcast) |
| 75 | { |
| 76 | if (this->sockets.empty()) this->Listen(); |
| 77 | |
| 78 | for (auto &s : this->sockets) { |
| 79 | /* Make a local copy because if we resolve it we cannot |
| 80 | * easily unresolve it so we can resolve it later again. */ |
| 81 | NetworkAddress send(recv); |
| 82 | |
| 83 | /* Not the same type */ |
| 84 | if (!send.IsFamily(s.second.GetAddress()->ss_family)) continue; |
| 85 | |
| 86 | p.PrepareToSend(); |
| 87 | |
| 88 | if (broadcast) { |
| 89 | /* Enable broadcast */ |
| 90 | unsigned long val = 1; |
| 91 | if (setsockopt(s.first, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { |
| 92 | Debug(net, 1, "Setting broadcast mode failed: {}", NetworkError::GetLast().AsString()); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | /* Send the buffer */ |
| 97 | ssize_t res = p.TransferOut([&](std::span<const uint8_t> buffer) { |
| 98 | return sendto(s.first, reinterpret_cast<const char *>(buffer.data()), static_cast<int>(buffer.size()), 0, reinterpret_cast<const struct sockaddr *>(send.GetAddress()), send.GetAddressLength()); |
| 99 | }); |
| 100 | Debug(net, 7, "sendto({})", send.GetAddressAsString()); |
| 101 | |
| 102 | /* Check for any errors, but ignore it otherwise */ |
| 103 | if (res == -1) Debug(net, 1, "sendto({}) failed: {}", send.GetAddressAsString(), NetworkError::GetLast().AsString()); |
| 104 | |
| 105 | if (!all) break; |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | /** |
| 110 | * Receive a packet at UDP level |
no test coverage detected