mirror of https://github.com/OpenRCT2/OpenRCT2.git
Get and broadcast to all broadcast address
This commit is contained in:
parent
51117432f0
commit
59ddd7e1ea
|
@ -233,16 +233,16 @@ bool ServerList::WriteFavourites(const std::vector<ServerListEntry>& entries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<std::vector<ServerListEntry>> ServerList::FetchLocalServerListAsync()
|
std::future<std::vector<ServerListEntry>> ServerList::FetchLocalServerListAsync(const INetworkEndpoint& broadcastEndpoint)
|
||||||
{
|
{
|
||||||
return std::async([] {
|
auto broadcastAddress = broadcastEndpoint.GetHostname();
|
||||||
|
return std::async([broadcastAddress] {
|
||||||
constexpr auto RECV_DELAY_MS = 10;
|
constexpr auto RECV_DELAY_MS = 10;
|
||||||
constexpr auto RECV_WAIT_MS = 2000;
|
constexpr auto RECV_WAIT_MS = 2000;
|
||||||
|
|
||||||
auto broadcastAddress = "192.168.1.255";
|
|
||||||
|
|
||||||
std::string msg = "Are you an OpenRCT2 server?";
|
std::string msg = "Are you an OpenRCT2 server?";
|
||||||
auto udpSocket = CreateUdpSocket();
|
auto udpSocket = CreateUdpSocket();
|
||||||
|
|
||||||
log_verbose("Broadcasting %zu bytes to the LAN (%s)", msg.size(), broadcastAddress);
|
log_verbose("Broadcasting %zu bytes to the LAN (%s)", msg.size(), broadcastAddress);
|
||||||
auto len = udpSocket->SendData(broadcastAddress, NETWORK_LAN_BROADCAST_PORT, msg.data(), msg.size());
|
auto len = udpSocket->SendData(broadcastAddress, NETWORK_LAN_BROADCAST_PORT, msg.data(), msg.size());
|
||||||
if (len != msg.size())
|
if (len != msg.size())
|
||||||
|
@ -280,11 +280,42 @@ std::future<std::vector<ServerListEntry>> ServerList::FetchLocalServerListAsync(
|
||||||
}
|
}
|
||||||
platform_sleep(RECV_DELAY_MS);
|
platform_sleep(RECV_DELAY_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::future<std::vector<ServerListEntry>> ServerList::FetchLocalServerListAsync()
|
||||||
|
{
|
||||||
|
return std::async([&] {
|
||||||
|
// Get all possible LAN broadcast addresses
|
||||||
|
auto broadcastEndpoints = GetBroadcastAddresses();
|
||||||
|
|
||||||
|
// Spin off a fetch for each broadcast address
|
||||||
|
std::vector<std::future<std::vector<ServerListEntry>>> futures;
|
||||||
|
for (const auto& broadcastEndpoint : broadcastEndpoints)
|
||||||
|
{
|
||||||
|
auto f = FetchLocalServerListAsync(*broadcastEndpoint);
|
||||||
|
futures.push_back(std::move(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait and merge all results
|
||||||
|
std::vector<ServerListEntry> mergedEntries;
|
||||||
|
for (auto& f : futures)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto entries = std::move(f.get());
|
||||||
|
mergedEntries.insert(mergedEntries.begin(), entries.begin(), entries.end());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// Ignore any exceptions from a particular broadcast fetch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mergedEntries;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::future<std::vector<ServerListEntry>> ServerList::FetchOnlineServerListAsync()
|
std::future<std::vector<ServerListEntry>> ServerList::FetchOnlineServerListAsync()
|
||||||
{
|
{
|
||||||
#ifdef DISABLE_HTTP
|
#ifdef DISABLE_HTTP
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct json_t;
|
struct json_t;
|
||||||
|
struct INetworkEndpoint;
|
||||||
|
|
||||||
struct ServerListEntry
|
struct ServerListEntry
|
||||||
{
|
{
|
||||||
|
@ -45,6 +46,7 @@ private:
|
||||||
void Sort();
|
void Sort();
|
||||||
std::vector<ServerListEntry> ReadFavourites();
|
std::vector<ServerListEntry> ReadFavourites();
|
||||||
bool WriteFavourites(const std::vector<ServerListEntry>& entries);
|
bool WriteFavourites(const std::vector<ServerListEntry>& entries);
|
||||||
|
std::future<std::vector<ServerListEntry>> FetchLocalServerListAsync(const INetworkEndpoint& broadcastEndpoint);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ServerListEntry& GetServer(size_t index);
|
ServerListEntry& GetServer(size_t index);
|
||||||
|
|
|
@ -36,13 +36,15 @@
|
||||||
#endif
|
#endif
|
||||||
#define FLAG_NO_PIPE 0
|
#define FLAG_NO_PIPE 0
|
||||||
#else
|
#else
|
||||||
#include <cerrno>
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <cerrno>
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include "../common.h"
|
#include "../common.h"
|
||||||
using SOCKET = int32_t;
|
using SOCKET = int32_t;
|
||||||
#define SOCKET_ERROR -1
|
#define SOCKET_ERROR -1
|
||||||
|
@ -116,7 +118,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetHostname() override
|
std::string GetHostname() const override
|
||||||
{
|
{
|
||||||
char hostname[256];
|
char hostname[256];
|
||||||
int res = getnameinfo(&_address, _addressLen, hostname, sizeof(hostname), nullptr, 0, NI_NUMERICHOST);
|
int res = getnameinfo(&_address, _addressLen, hostname, sizeof(hostname), nullptr, 0, NI_NUMERICHOST);
|
||||||
|
@ -395,4 +397,99 @@ std::unique_ptr<IUdpSocket> CreateUdpSocket()
|
||||||
return std::make_unique<UdpSocket>();
|
return std::make_unique<UdpSocket>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ifdef _WIN32
|
||||||
|
std::vector<INTERFACE_INFO> GetNetworkInterfaces()
|
||||||
|
{
|
||||||
|
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock == -1)
|
||||||
|
{
|
||||||
|
printf("socket returned -1\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD len = 0;
|
||||||
|
size_t capacity = 2;
|
||||||
|
std::vector<INTERFACE_INFO> interfaces;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
interfaces.resize(capacity);
|
||||||
|
if (WSAIoctl(
|
||||||
|
sock, SIO_GET_INTERFACE_LIST, nullptr, 0, interfaces.data(), capacity * sizeof(INTERFACE_INFO), &len, nullptr,
|
||||||
|
nullptr)
|
||||||
|
== 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (WSAGetLastError() != WSAEFAULT)
|
||||||
|
{
|
||||||
|
closesocket(sock);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
capacity *= 2;
|
||||||
|
}
|
||||||
|
interfaces.resize(len / sizeof(INTERFACE_INFO));
|
||||||
|
interfaces.shrink_to_fit();
|
||||||
|
return interfaces;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<INetworkEndpoint>> GetBroadcastAddresses()
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<INetworkEndpoint>> baddresses;
|
||||||
|
# ifdef _WIN32
|
||||||
|
auto interfaces = GetNetworkInterfaces();
|
||||||
|
for (const auto& ifo : interfaces)
|
||||||
|
{
|
||||||
|
if (ifo.iiFlags & IFF_LOOPBACK)
|
||||||
|
continue;
|
||||||
|
if (!(ifo.iiFlags & IFF_BROADCAST))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// iiBroadcast is unusable, because it always seems to be set to 255.255.255.255.
|
||||||
|
sockaddr_storage address{};
|
||||||
|
memcpy(&address, &ifo.iiAddress.Address, sizeof(sockaddr));
|
||||||
|
((sockaddr_in*)&address)->sin_addr.s_addr = ifo.iiAddress.AddressIn.sin_addr.s_addr
|
||||||
|
| ~ifo.iiNetmask.AddressIn.sin_addr.s_addr;
|
||||||
|
baddresses.push_back(std::make_unique<NetworkEndpoint>(address, sizeof(sockaddr)));
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock == -1)
|
||||||
|
{
|
||||||
|
return baddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[4 * 1024]{};
|
||||||
|
ifconf ifconfx{};
|
||||||
|
ifconfx.ifc_len = sizeof(buf);
|
||||||
|
ifconfx.ifc_buf = buf;
|
||||||
|
if (ioctl(sock, SIOCGIFCONF, &ifconfx) == -1)
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
return baddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* buf_end = buf + ifconfx.ifc_len;
|
||||||
|
for (const char* p = buf; p < buf_end;)
|
||||||
|
{
|
||||||
|
auto req = (const ifreq*)p;
|
||||||
|
if (req->ifr_addr.sa_family == AF_INET)
|
||||||
|
{
|
||||||
|
ifreq r;
|
||||||
|
strcpy(r.ifr_name, req->ifr_name);
|
||||||
|
if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 && (r.ifr_flags & IFF_BROADCAST) && ioctl(sock, SIOCGIFBRDADDR, &r) != -1)
|
||||||
|
{
|
||||||
|
baddresses.push_back(std::make_unique<NetworkEndpoint>(&r.ifr_broadaddr, sizeof(sockaddr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p += sizeof(ifreq);
|
||||||
|
# if defined(AF_LINK) && !defined(SUNOS)
|
||||||
|
p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
close(sock);
|
||||||
|
# endif
|
||||||
|
return baddresses;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
enum SOCKET_STATUS
|
enum SOCKET_STATUS
|
||||||
{
|
{
|
||||||
|
@ -40,7 +41,7 @@ interface INetworkEndpoint
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string GetHostname() abstract;
|
virtual std::string GetHostname() const abstract;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,3 +70,4 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IUdpSocket> CreateUdpSocket();
|
std::unique_ptr<IUdpSocket> CreateUdpSocket();
|
||||||
|
std::vector<std::unique_ptr<INetworkEndpoint>> GetBroadcastAddresses();
|
||||||
|
|
Loading…
Reference in New Issue