mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 08:09:26 +01:00
Merge pull request #12559 from sepalani/bba-refactor
BBA/HLE: Code refactoring
This commit is contained in:
commit
83b5124d40
@ -26,12 +26,7 @@ u64 GetTickCountStd()
|
|||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
|
return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace ExpansionInterface
|
|
||||||
{
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
std::vector<u8> BuildFINFrame(StackRef* ref)
|
std::vector<u8> BuildFINFrame(StackRef* ref)
|
||||||
{
|
{
|
||||||
const Common::TCPPacket result(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num,
|
const Common::TCPPacket result(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num,
|
||||||
@ -70,6 +65,8 @@ void SetIPIdentification(u8* ptr, std::size_t size, u16 value)
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace ExpansionInterface
|
||||||
|
{
|
||||||
bool CEXIETHERNET::BuiltInBBAInterface::Activate()
|
bool CEXIETHERNET::BuiltInBBAInterface::Activate()
|
||||||
{
|
{
|
||||||
if (IsActivated())
|
if (IsActivated())
|
||||||
@ -91,11 +88,7 @@ bool CEXIETHERNET::BuiltInBBAInterface::Activate()
|
|||||||
m_router_mac = Common::GenerateMacAddress(Common::MACConsumer::BBA);
|
m_router_mac = Common::GenerateMacAddress(Common::MACConsumer::BBA);
|
||||||
m_arp_table[m_router_ip] = m_router_mac;
|
m_arp_table[m_router_ip] = m_router_mac;
|
||||||
|
|
||||||
// clear all ref
|
m_network_ref.Clear();
|
||||||
for (auto& ref : network_ref)
|
|
||||||
{
|
|
||||||
ref.ip = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_upnp_httpd.listen(Common::SSDP_PORT, sf::IpAddress(ip));
|
m_upnp_httpd.listen(Common::SSDP_PORT, sf::IpAddress(ip));
|
||||||
m_upnp_httpd.setBlocking(false);
|
m_upnp_httpd.setBlocking(false);
|
||||||
@ -113,16 +106,7 @@ void CEXIETHERNET::BuiltInBBAInterface::Deactivate()
|
|||||||
m_read_thread_shutdown.Set();
|
m_read_thread_shutdown.Set();
|
||||||
m_active = false;
|
m_active = false;
|
||||||
|
|
||||||
// kill all active socket
|
m_network_ref.Clear();
|
||||||
for (auto& ref : network_ref)
|
|
||||||
{
|
|
||||||
if (ref.ip != 0)
|
|
||||||
{
|
|
||||||
ref.type == IPPROTO_TCP ? ref.tcp_socket.disconnect() : ref.udp_socket.unbind();
|
|
||||||
}
|
|
||||||
ref.ip = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_arp_table.clear();
|
m_arp_table.clear();
|
||||||
m_upnp_httpd.close();
|
m_upnp_httpd.close();
|
||||||
|
|
||||||
@ -144,6 +128,40 @@ void CEXIETHERNET::BuiltInBBAInterface::WriteToQueue(const std::vector<u8>& data
|
|||||||
m_queue_write = next_write_index;
|
m_queue_write = next_write_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEXIETHERNET::BuiltInBBAInterface::PollData(std::size_t* datasize)
|
||||||
|
{
|
||||||
|
for (auto& net_ref : m_network_ref)
|
||||||
|
{
|
||||||
|
if (net_ref.ip == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check for sleeping TCP data
|
||||||
|
if (net_ref.type == IPPROTO_TCP)
|
||||||
|
{
|
||||||
|
for (auto& tcp_buf : net_ref.tcp_buffers)
|
||||||
|
{
|
||||||
|
if (!tcp_buf.used || (GetTickCountStd() - tcp_buf.tick) <= 1000)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tcp_buf.tick = GetTickCountStd();
|
||||||
|
// Timed out packet, resend
|
||||||
|
if (((m_queue_write + 1) & 15) != m_queue_read)
|
||||||
|
WriteToQueue(tcp_buf.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for connection data
|
||||||
|
if (*datasize != 0)
|
||||||
|
continue;
|
||||||
|
const auto socket_data = TryGetDataFromSocket(&net_ref);
|
||||||
|
if (socket_data.has_value())
|
||||||
|
{
|
||||||
|
*datasize = socket_data->size();
|
||||||
|
std::memcpy(m_eth_ref->mRecvBuffer.get(), socket_data->data(), *datasize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CEXIETHERNET::BuiltInBBAInterface::HandleARP(const Common::ARPPacket& packet)
|
void CEXIETHERNET::BuiltInBBAInterface::HandleARP(const Common::ARPPacket& packet)
|
||||||
{
|
{
|
||||||
const auto& [hwdata, arpdata] = packet;
|
const auto& [hwdata, arpdata] = packet;
|
||||||
@ -203,36 +221,6 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleDHCP(const Common::UDPPacket& pack
|
|||||||
WriteToQueue(response.Build());
|
WriteToQueue(response.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
StackRef* CEXIETHERNET::BuiltInBBAInterface::GetAvailableSlot(u16 port)
|
|
||||||
{
|
|
||||||
if (port > 0) // existing connection?
|
|
||||||
{
|
|
||||||
for (auto& ref : network_ref)
|
|
||||||
{
|
|
||||||
if (ref.ip != 0 && ref.local == port)
|
|
||||||
return &ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto& ref : network_ref)
|
|
||||||
{
|
|
||||||
if (ref.ip == 0)
|
|
||||||
return &ref;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
StackRef* CEXIETHERNET::BuiltInBBAInterface::GetTCPSlot(u16 src_port, u16 dst_port, u32 ip)
|
|
||||||
{
|
|
||||||
for (auto& ref : network_ref)
|
|
||||||
{
|
|
||||||
if (ref.ip == ip && ref.remote == dst_port && ref.local == src_port)
|
|
||||||
{
|
|
||||||
return &ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::vector<u8>>
|
std::optional<std::vector<u8>>
|
||||||
CEXIETHERNET::BuiltInBBAInterface::TryGetDataFromSocket(StackRef* ref)
|
CEXIETHERNET::BuiltInBBAInterface::TryGetDataFromSocket(StackRef* ref)
|
||||||
{
|
{
|
||||||
@ -314,8 +302,8 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket&
|
|||||||
{
|
{
|
||||||
const auto& [hwdata, ip_header, tcp_header, ip_options, tcp_options, data] = packet;
|
const auto& [hwdata, ip_header, tcp_header, ip_options, tcp_options, data] = packet;
|
||||||
sf::IpAddress target;
|
sf::IpAddress target;
|
||||||
StackRef* ref = GetTCPSlot(tcp_header.source_port, tcp_header.destination_port,
|
StackRef* ref = m_network_ref.GetTCPSlot(tcp_header.source_port, tcp_header.destination_port,
|
||||||
Common::BitCast<u32>(ip_header.destination_addr));
|
Common::BitCast<u32>(ip_header.destination_addr));
|
||||||
const u16 flags = ntohs(tcp_header.properties) & 0xfff;
|
const u16 flags = ntohs(tcp_header.properties) & 0xfff;
|
||||||
if (flags & (TCP_FLAG_FIN | TCP_FLAG_RST))
|
if (flags & (TCP_FLAG_FIN | TCP_FLAG_RST))
|
||||||
{
|
{
|
||||||
@ -344,7 +332,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket&
|
|||||||
// new connection
|
// new connection
|
||||||
if (ref != nullptr)
|
if (ref != nullptr)
|
||||||
return;
|
return;
|
||||||
ref = GetAvailableSlot(0);
|
ref = m_network_ref.GetAvailableSlot(0);
|
||||||
|
|
||||||
ref->delay = GetTickCountStd();
|
ref->delay = GetTickCountStd();
|
||||||
ref->local = tcp_header.source_port;
|
ref->local = tcp_header.source_port;
|
||||||
@ -434,7 +422,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket&
|
|||||||
// and listen to it. We open it on our side manually.
|
// and listen to it. We open it on our side manually.
|
||||||
void CEXIETHERNET::BuiltInBBAInterface::InitUDPPort(u16 port)
|
void CEXIETHERNET::BuiltInBBAInterface::InitUDPPort(u16 port)
|
||||||
{
|
{
|
||||||
StackRef* ref = GetAvailableSlot(htons(port));
|
StackRef* ref = m_network_ref.GetAvailableSlot(htons(port));
|
||||||
if (ref == nullptr || ref->ip != 0)
|
if (ref == nullptr || ref->ip != 0)
|
||||||
return;
|
return;
|
||||||
ref->ip = m_router_ip; // change for ip
|
ref->ip = m_router_ip; // change for ip
|
||||||
@ -464,7 +452,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleUDPFrame(const Common::UDPPacket&
|
|||||||
m_router_ip : // dns request
|
m_router_ip : // dns request
|
||||||
Common::BitCast<u32>(ip_header.destination_addr);
|
Common::BitCast<u32>(ip_header.destination_addr);
|
||||||
|
|
||||||
StackRef* ref = GetAvailableSlot(udp_header.source_port);
|
StackRef* ref = m_network_ref.GetAvailableSlot(udp_header.source_port);
|
||||||
if (ref->ip == 0)
|
if (ref->ip == 0)
|
||||||
{
|
{
|
||||||
ref->ip = destination_addr; // change for ip
|
ref->ip = destination_addr; // change for ip
|
||||||
@ -509,7 +497,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleUDPFrame(const Common::UDPPacket&
|
|||||||
|
|
||||||
void CEXIETHERNET::BuiltInBBAInterface::HandleUPnPClient()
|
void CEXIETHERNET::BuiltInBBAInterface::HandleUPnPClient()
|
||||||
{
|
{
|
||||||
StackRef* ref = GetAvailableSlot(0);
|
StackRef* ref = m_network_ref.GetAvailableSlot(0);
|
||||||
if (ref == nullptr || m_upnp_httpd.accept(ref->tcp_socket) != sf::Socket::Done)
|
if (ref == nullptr || m_upnp_httpd.accept(ref->tcp_socket) != sf::Socket::Done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -701,41 +689,9 @@ void CEXIETHERNET::BuiltInBBAInterface::ReadThreadHandler(CEXIETHERNET::BuiltInB
|
|||||||
self->m_queue_read++;
|
self->m_queue_read++;
|
||||||
self->m_queue_read &= 15;
|
self->m_queue_read &= 15;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// test connections data
|
|
||||||
for (auto& net_ref : self->network_ref)
|
|
||||||
{
|
|
||||||
if (net_ref.ip == 0)
|
|
||||||
continue;
|
|
||||||
const auto socket_data = self->TryGetDataFromSocket(&net_ref);
|
|
||||||
if (socket_data.has_value())
|
|
||||||
{
|
|
||||||
datasize = socket_data->size();
|
|
||||||
std::memcpy(self->m_eth_ref->mRecvBuffer.get(), socket_data->data(), datasize);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// test and add any sleeping tcp data
|
// Check network stack references
|
||||||
for (auto& net_ref : self->network_ref)
|
self->PollData(&datasize);
|
||||||
{
|
|
||||||
if (net_ref.ip == 0 || net_ref.type != IPPROTO_TCP)
|
|
||||||
continue;
|
|
||||||
for (auto& tcp_buf : net_ref.tcp_buffers)
|
|
||||||
{
|
|
||||||
if (!tcp_buf.used || (GetTickCountStd() - tcp_buf.tick) <= 1000)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tcp_buf.tick = GetTickCountStd();
|
|
||||||
// timmed out packet, resend
|
|
||||||
if (((self->m_queue_write + 1) & 15) != self->m_queue_read)
|
|
||||||
{
|
|
||||||
self->WriteToQueue(tcp_buf.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for new UPnP client
|
// Check for new UPnP client
|
||||||
self->HandleUPnPClient();
|
self->HandleUPnPClient();
|
||||||
@ -778,14 +734,7 @@ void CEXIETHERNET::BuiltInBBAInterface::RecvStart()
|
|||||||
void CEXIETHERNET::BuiltInBBAInterface::RecvStop()
|
void CEXIETHERNET::BuiltInBBAInterface::RecvStop()
|
||||||
{
|
{
|
||||||
m_read_enabled.Clear();
|
m_read_enabled.Clear();
|
||||||
for (auto& net_ref : network_ref)
|
m_network_ref.Clear();
|
||||||
{
|
|
||||||
if (net_ref.ip != 0)
|
|
||||||
{
|
|
||||||
net_ref.type == IPPROTO_TCP ? net_ref.tcp_socket.disconnect() : net_ref.udp_socket.unbind();
|
|
||||||
}
|
|
||||||
net_ref.ip = 0;
|
|
||||||
}
|
|
||||||
m_queue_read = 0;
|
m_queue_read = 0;
|
||||||
m_queue_write = 0;
|
m_queue_write = 0;
|
||||||
}
|
}
|
||||||
@ -986,3 +935,45 @@ sf::Socket::Status BbaUdpSocket::Bind(u16 port, u32 net_ip)
|
|||||||
INFO_LOG_FMT(SP1, "SSDP multicast membership successful");
|
INFO_LOG_FMT(SP1, "SSDP multicast membership successful");
|
||||||
return sf::Socket::Status::Done;
|
return sf::Socket::Status::Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StackRef* NetworkRef::GetAvailableSlot(u16 port)
|
||||||
|
{
|
||||||
|
if (port > 0) // existing connection?
|
||||||
|
{
|
||||||
|
for (auto& ref : m_stacks)
|
||||||
|
{
|
||||||
|
if (ref.ip != 0 && ref.local == port)
|
||||||
|
return &ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& ref : m_stacks)
|
||||||
|
{
|
||||||
|
if (ref.ip == 0)
|
||||||
|
return &ref;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackRef* NetworkRef::GetTCPSlot(u16 src_port, u16 dst_port, u32 ip)
|
||||||
|
{
|
||||||
|
for (auto& ref : m_stacks)
|
||||||
|
{
|
||||||
|
if (ref.ip == ip && ref.remote == dst_port && ref.local == src_port)
|
||||||
|
{
|
||||||
|
return &ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkRef::Clear()
|
||||||
|
{
|
||||||
|
for (auto& ref : m_stacks)
|
||||||
|
{
|
||||||
|
if (ref.ip != 0)
|
||||||
|
{
|
||||||
|
ref.type == IPPROTO_TCP ? ref.tcp_socket.disconnect() : ref.udp_socket.unbind();
|
||||||
|
}
|
||||||
|
ref.ip = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -72,7 +72,7 @@ public:
|
|||||||
|
|
||||||
struct StackRef
|
struct StackRef
|
||||||
{
|
{
|
||||||
u32 ip;
|
u32 ip = 0;
|
||||||
u16 local;
|
u16 local;
|
||||||
u16 remote;
|
u16 remote;
|
||||||
u16 type;
|
u16 type;
|
||||||
@ -92,3 +92,26 @@ struct StackRef
|
|||||||
BbaTcpSocket tcp_socket;
|
BbaTcpSocket tcp_socket;
|
||||||
u64 poke_time;
|
u64 poke_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Max 10 at same time, I think most gc game had a
|
||||||
|
// limit of 8 in the GC framework
|
||||||
|
using StackRefs = std::array<StackRef, 10>;
|
||||||
|
|
||||||
|
class NetworkRef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StackRefs& data() { return m_stacks; }
|
||||||
|
const StackRefs& data() const { return m_stacks; }
|
||||||
|
auto begin() { return m_stacks.begin(); }
|
||||||
|
auto begin() const { return m_stacks.cbegin(); }
|
||||||
|
auto end() { return m_stacks.end(); }
|
||||||
|
auto end() const { return m_stacks.cend(); }
|
||||||
|
|
||||||
|
StackRef* GetAvailableSlot(u16 port);
|
||||||
|
StackRef* GetTCPSlot(u16 src_port, u16 dst_port, u32 ip);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
StackRefs m_stacks;
|
||||||
|
};
|
||||||
|
@ -456,16 +456,14 @@ private:
|
|||||||
sf::TcpListener m_upnp_httpd;
|
sf::TcpListener m_upnp_httpd;
|
||||||
#if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
|
#if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
|
||||||
defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__)
|
defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__)
|
||||||
std::array<StackRef, 10> network_ref{}; // max 10 at same time, i think most gc game had a
|
NetworkRef m_network_ref;
|
||||||
// limit of 8 in the gc framework
|
|
||||||
std::thread m_read_thread;
|
std::thread m_read_thread;
|
||||||
Common::Flag m_read_enabled;
|
Common::Flag m_read_enabled;
|
||||||
Common::Flag m_read_thread_shutdown;
|
Common::Flag m_read_thread_shutdown;
|
||||||
static void ReadThreadHandler(BuiltInBBAInterface* self);
|
static void ReadThreadHandler(BuiltInBBAInterface* self);
|
||||||
#endif
|
#endif
|
||||||
void WriteToQueue(const std::vector<u8>& data);
|
void WriteToQueue(const std::vector<u8>& data);
|
||||||
StackRef* GetAvailableSlot(u16 port);
|
void PollData(std::size_t* datasize);
|
||||||
StackRef* GetTCPSlot(u16 src_port, u16 dst_port, u32 ip);
|
|
||||||
std::optional<std::vector<u8>> TryGetDataFromSocket(StackRef* ref);
|
std::optional<std::vector<u8>> TryGetDataFromSocket(StackRef* ref);
|
||||||
|
|
||||||
void HandleARP(const Common::ARPPacket& packet);
|
void HandleARP(const Common::ARPPacket& packet);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user