Squashed 'external/toxcore/c-toxcore/' changes from c9cdae001..9ed2fa80d
9ed2fa80d fix(toxav): remove extra copy of video frame on encode de30cf3ad docs: Add new file kinds, that should be useful to all clients. d5b5e879d fix(DHT): Correct node skipping logic timed out nodes. 30e71fe97 refactor: Generate event dispatch functions and add tox_events_dispatch. 8fdbb0b50 style: Format parameter lists in event handlers. d00dee12b refactor: Add warning logs when losing chat invites. b144e8db1 feat: Add a way to look up a file number by ID. 849281ea0 feat: Add a way to fetch groups by chat ID. a2c177396 refactor: Harden event system and improve type safety. 8f5caa656 refactor: Add MessagePack string support to bin_pack. 34e8d5ad5 chore: Add GitHub CodeQL workflow and local Docker runner. f7b068010 refactor: Add nullability annotations to event headers. 788abe651 refactor(toxav): Use system allocator for mutexes. 2e4b423eb refactor: Use specific typedefs for public API arrays. 2baf34775 docs(toxav): update idle iteration interval see 679444751876fa3882a717772918ebdc8f083354 2f87ac67b feat: Add Event Loop abstraction (Ev). f8dfc38d8 test: Fix data race in ToxScenario virtual_clock. 38313921e test(TCP): Add regression test for TCP priority queue integrity. f94a50d9a refactor(toxav): Replace mutable_mutex with dynamically allocated mutex. ad054511e refactor: Internalize DHT structs and add debug helpers. 8b467cc96 fix: Prevent potential integer overflow in group chat handshake. 4962bdbb8 test: Improve TCP simulation and add tests 5f0227093 refactor: Allow nullable data in group chat handlers. e97b18ea9 chore: Improve Windows Docker support. b14943bbd refactor: Move Logger out of Messenger into Tox. dd3136250 cleanup: Apply nullability qualifiers to C++ codebase. 1849f70fc refactor: Extract low-level networking code to net and os_network. 8fec75421 refactor: Delete tox_random, align on rng and os_random. a03ae8051 refactor: Delete tox_memory, align on mem and os_memory. 4c88fed2c refactor: Use `std::` prefixes more consistently in C++ code. 72452f2ae test: Add some more tests for onion and shared key cache. d5a51b09a cleanup: Use tox_attributes.h in tox_private.h and install it. b6f5b9fc5 test: Add some benchmarks for various high level things. 8a8d02785 test(support): Introduce threaded Tox runner and simulation barrier d68d1d095 perf(toxav): optimize audio and video intermediate buffers by keeping them around REVERT: c9cdae001 fix(toxav): remove extra copy of video frame on encode git-subtree-dir: external/toxcore/c-toxcore git-subtree-split: 9ed2fa80d582c714d6bdde6a7648220a92cddff8
This commit is contained in:
@@ -7,6 +7,30 @@
|
||||
|
||||
namespace tox::test {
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, TcpFlags flags)
|
||||
{
|
||||
bool first = true;
|
||||
if (flags.value & 0x02) {
|
||||
os << (first ? "" : "|") << "SYN";
|
||||
first = false;
|
||||
}
|
||||
if (flags.value & 0x10) {
|
||||
os << (first ? "" : "|") << "ACK";
|
||||
first = false;
|
||||
}
|
||||
if (flags.value & 0x01) {
|
||||
os << (first ? "" : "|") << "FIN";
|
||||
first = false;
|
||||
}
|
||||
if (flags.value & 0x04) {
|
||||
os << (first ? "" : "|") << "RST";
|
||||
first = false;
|
||||
}
|
||||
if (first)
|
||||
os << "NONE";
|
||||
return os << "(" << static_cast<int>(flags.value) << ")";
|
||||
}
|
||||
|
||||
bool NetworkUniverse::IP_Port_Key::operator<(const IP_Port_Key &other) const
|
||||
{
|
||||
if (port != other.port)
|
||||
@@ -24,7 +48,7 @@ bool NetworkUniverse::IP_Port_Key::operator<(const IP_Port_Key &other) const
|
||||
NetworkUniverse::NetworkUniverse() { }
|
||||
NetworkUniverse::~NetworkUniverse() { }
|
||||
|
||||
bool NetworkUniverse::bind_udp(IP ip, uint16_t port, FakeUdpSocket *socket)
|
||||
bool NetworkUniverse::bind_udp(IP ip, uint16_t port, FakeUdpSocket *_Nonnull socket)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
IP_Port_Key key{ip, port};
|
||||
@@ -40,14 +64,14 @@ void NetworkUniverse::unbind_udp(IP ip, uint16_t port)
|
||||
udp_bindings_.erase({ip, port});
|
||||
}
|
||||
|
||||
bool NetworkUniverse::bind_tcp(IP ip, uint16_t port, FakeTcpSocket *socket)
|
||||
bool NetworkUniverse::bind_tcp(IP ip, uint16_t port, FakeTcpSocket *_Nonnull socket)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
tcp_bindings_.insert({{ip, port}, socket});
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkUniverse::unbind_tcp(IP ip, uint16_t port, FakeTcpSocket *socket)
|
||||
void NetworkUniverse::unbind_tcp(IP ip, uint16_t port, FakeTcpSocket *_Nonnull socket)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
auto range = tcp_bindings_.equal_range({ip, port});
|
||||
@@ -75,9 +99,64 @@ void NetworkUniverse::send_packet(Packet p)
|
||||
p.delivery_time += global_latency_ms_;
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
p.sequence_number = next_packet_id_++;
|
||||
|
||||
if (verbose_) {
|
||||
Ip_Ntoa from_str, to_str;
|
||||
net_ip_ntoa(&p.from.ip, &from_str);
|
||||
net_ip_ntoa(&p.to.ip, &to_str);
|
||||
std::cerr << "[NetworkUniverse] Enqueued packet #" << p.sequence_number << " from "
|
||||
<< from_str.buf << ":" << net_ntohs(p.from.port) << " to " << to_str.buf << ":"
|
||||
<< net_ntohs(p.to.port);
|
||||
if (p.is_tcp) {
|
||||
std::cerr << " (TCP Flags=" << TcpFlags{p.tcp_flags} << " Seq=" << p.seq
|
||||
<< " Ack=" << p.ack << ")";
|
||||
}
|
||||
std::cerr << " with size " << p.data.size() << std::endl;
|
||||
}
|
||||
|
||||
event_queue_.push(std::move(p));
|
||||
}
|
||||
|
||||
static bool is_ipv4_mapped(const IP &ip)
|
||||
{
|
||||
if (!net_family_is_ipv6(ip.family))
|
||||
return false;
|
||||
const uint8_t *b = ip.ip.v6.uint8;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
if (b[i] != 0)
|
||||
return false;
|
||||
if (b[10] != 0xFF || b[11] != 0xFF)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static IP extract_ipv4(const IP &ip)
|
||||
{
|
||||
IP ip4;
|
||||
ip_init(&ip4, false);
|
||||
const uint8_t *b = ip.ip.v6.uint8;
|
||||
std::memcpy(ip4.ip.v4.uint8, b + 12, 4);
|
||||
return ip4;
|
||||
}
|
||||
|
||||
bool is_loopback(const IP &ip)
|
||||
{
|
||||
if (net_family_is_ipv4(ip.family)) {
|
||||
return ip.ip.v4.uint32 == net_htonl(0x7F000001);
|
||||
}
|
||||
if (net_family_is_ipv6(ip.family)) {
|
||||
const uint8_t *b = ip.ip.v6.uint8;
|
||||
for (int i = 0; i < 15; ++i) {
|
||||
if (b[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return b[15] == 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkUniverse::process_events(uint64_t current_time_ms)
|
||||
{
|
||||
while (true) {
|
||||
@@ -88,19 +167,101 @@ void NetworkUniverse::process_events(uint64_t current_time_ms)
|
||||
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
if (!event_queue_.empty()) {
|
||||
const Packet &top = event_queue_.top();
|
||||
if (verbose_) {
|
||||
std::cerr << "[NetworkUniverse] Peek packet: time=" << top.delivery_time
|
||||
<< " current=" << current_time_ms << " tcp=" << top.is_tcp
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!event_queue_.empty() && event_queue_.top().delivery_time <= current_time_ms) {
|
||||
p = event_queue_.top();
|
||||
event_queue_.pop();
|
||||
has_packet = true;
|
||||
|
||||
if (verbose_) {
|
||||
Ip_Ntoa from_str, to_str;
|
||||
net_ip_ntoa(&p.from.ip, &from_str);
|
||||
net_ip_ntoa(&p.to.ip, &to_str);
|
||||
std::cerr << "[NetworkUniverse] Processing packet #" << p.sequence_number
|
||||
<< " from " << from_str.buf << ":" << net_ntohs(p.from.port) << " to "
|
||||
<< to_str.buf << ":" << net_ntohs(p.to.port)
|
||||
<< " (TCP=" << (p.is_tcp ? "true" : "false");
|
||||
if (p.is_tcp) {
|
||||
std::cerr << " Flags=" << TcpFlags{p.tcp_flags} << " Seq=" << p.seq
|
||||
<< " Ack=" << p.ack;
|
||||
}
|
||||
std::cerr << " Size=" << p.data.size() << ")" << std::endl;
|
||||
}
|
||||
|
||||
IP target_ip = p.to.ip;
|
||||
|
||||
if (p.is_tcp) {
|
||||
auto range = tcp_bindings_.equal_range({p.to.ip, net_ntohs(p.to.port)});
|
||||
if (is_loopback(target_ip)
|
||||
&& tcp_bindings_.count({target_ip, net_ntohs(p.to.port)}) == 0) {
|
||||
if (verbose_) {
|
||||
std::cerr << "[NetworkUniverse] Loopback packet to "
|
||||
<< static_cast<int>(target_ip.ip.v4.uint8[3])
|
||||
<< " redirected to "
|
||||
<< static_cast<int>(p.from.ip.ip.v4.uint8[3]) << std::endl;
|
||||
}
|
||||
target_ip = p.from.ip;
|
||||
}
|
||||
|
||||
auto range = tcp_bindings_.equal_range({target_ip, net_ntohs(p.to.port)});
|
||||
FakeTcpSocket *listen_match = nullptr;
|
||||
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
tcp_targets.push_back(it->second);
|
||||
FakeTcpSocket *s = it->second;
|
||||
if (s->state() == FakeTcpSocket::LISTEN) {
|
||||
listen_match = s;
|
||||
} else {
|
||||
const IP_Port &remote = s->remote_addr();
|
||||
if (net_ntohs(p.from.port) == net_ntohs(remote.port)) {
|
||||
if (ip_equal(&p.from.ip, &remote.ip)
|
||||
|| (is_loopback(p.from.ip) && ip_equal(&remote.ip, &target_ip))
|
||||
|| (is_loopback(remote.ip)
|
||||
&& ip_equal(&p.from.ip, &target_ip))) {
|
||||
tcp_targets.push_back(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (listen_match && (p.tcp_flags & 0x02)) {
|
||||
tcp_targets.push_back(listen_match);
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
std::cerr << "[NetworkUniverse] Routing TCP to "
|
||||
<< static_cast<int>(target_ip.ip.v4.uint8[0]) << "."
|
||||
<< static_cast<int>(target_ip.ip.v4.uint8[3]) << ":"
|
||||
<< net_ntohs(p.to.port)
|
||||
<< ". Targets found: " << tcp_targets.size() << std::endl;
|
||||
}
|
||||
if (tcp_targets.empty()) {
|
||||
if (verbose_) {
|
||||
std::cerr << "[NetworkUniverse] WARNING: No TCP targets for "
|
||||
<< static_cast<int>(target_ip.ip.v4.uint8[0]) << "."
|
||||
<< static_cast<int>(target_ip.ip.v4.uint8[3]) << ":"
|
||||
<< net_ntohs(p.to.port) << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (udp_bindings_.count({p.to.ip, net_ntohs(p.to.port)})) {
|
||||
udp_target = udp_bindings_[{p.to.ip, net_ntohs(p.to.port)}];
|
||||
if (is_loopback(target_ip)
|
||||
&& udp_bindings_.count({target_ip, net_ntohs(p.to.port)}) == 0) {
|
||||
target_ip = p.from.ip;
|
||||
}
|
||||
|
||||
if (udp_bindings_.count({target_ip, net_ntohs(p.to.port)})) {
|
||||
udp_target = udp_bindings_[{target_ip, net_ntohs(p.to.port)}];
|
||||
} else if (is_ipv4_mapped(target_ip)) {
|
||||
IP ip4 = extract_ipv4(target_ip);
|
||||
if (udp_bindings_.count({ip4, net_ntohs(p.to.port)})) {
|
||||
udp_target = udp_bindings_[{ip4, net_ntohs(p.to.port)}];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +273,9 @@ void NetworkUniverse::process_events(uint64_t current_time_ms)
|
||||
|
||||
if (p.is_tcp) {
|
||||
for (auto *it : tcp_targets) {
|
||||
it->handle_packet(p);
|
||||
if (it->handle_packet(p)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (udp_target) {
|
||||
@@ -136,7 +299,7 @@ uint16_t NetworkUniverse::find_free_port(IP ip, uint16_t start)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
for (uint16_t port = start; port < 65535; ++port) {
|
||||
if (!udp_bindings_.count({ip, port}))
|
||||
if (!udp_bindings_.count({ip, port}) && !tcp_bindings_.count({ip, port}))
|
||||
return port;
|
||||
}
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user