mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-05 15:03:33 +08:00
network-reader tidying
This commit is contained in:
parent
816e9b993b
commit
6749e9ee5e
@ -3995,26 +3995,26 @@
|
|||||||
"assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e",
|
"assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e",
|
||||||
"assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34",
|
"assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34",
|
||||||
"ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a",
|
"ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a",
|
||||||
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b7/97/058ec9b0958eb0c16d4b73e46c77",
|
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/79/79/0a70bdd5f157f35fcf756a187db5",
|
||||||
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fc/87/a43180a273071e2297727dae55e0",
|
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d1/d8/96e209445da48374062ed2b2aa7e",
|
||||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ab/84/d648830f95c5adaa26e259267524",
|
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/aa/26758a2a412fd07628f1c1435c3f",
|
||||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a3/af/3c0f8a3884cd4896172790e49789",
|
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9f/98/acfca6199ed45238036a1f2f14f8",
|
||||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f1/53/567de5c38f219eea734d5d780cfe",
|
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/fa/64690be1890135b82a302c6fce22",
|
||||||
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0e/29/2b6acec2f043af8ffa28405518ba",
|
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/33/ae/00c76bb8d2048e9c110f698b8a20",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ec/e1/5b85a04e38545aa015c92819b1cc",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8a/91/3e25e98763c1a80bc2d3b49b6c24",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/6d/8440e0fccd5482c6cf06f5f8eb74",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b7/60/2ad75fe1d4c776e220ab49a985a3",
|
||||||
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/17/41/98b75e3c0dd041875081cb230c08",
|
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ab/82/bf728df59dbcde87f8514d26bf19",
|
||||||
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/df/6e/8992acdcf955eec1df42f97c6559",
|
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4f/fa/e5a5ba4ea3dff37c05e93ac99f30",
|
||||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/2e/a7985d25068b8c44bf64123131c2",
|
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/df/36/174625b380539106b67d5bf67373",
|
||||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/be/f1/e13ed7948ffd0da65cbe0528ea94",
|
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/20/fe/077a7249888f313bc1251c85001b",
|
||||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1d/b6/58b8b43dc5071445e0a9d666487a",
|
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f9/eb/5e6c3396ea7ea88aa35eea3313ff",
|
||||||
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c6/fe/fa0c92655a72b7c4eadb3d12ba32",
|
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/63/cc/7647e6afc47bc16cab506bfbc32f",
|
||||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e1/23/5572f9e4822e6798a0f1a249dd5a",
|
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/24/84/2f5eeb0c76bb594a60f9d1cbad96",
|
||||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/4f/609cd8f582a6e7f26772816a60c7",
|
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1f/fb/a7f13102bc81737fa5a624ddb96e",
|
||||||
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/db/f3/e9270a5d334a7f97f11cc151552a",
|
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3f/a5/dca6a30b4a2e0bdeab62f746d16f",
|
||||||
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ae/67/9c59c7e046c568adc89819afc445",
|
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/58/fb/6a1b9965d43820d72449f1771b43",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/60/9a/8e4789f6f0b4f394a00043ab8ec7",
|
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/4a/dd/3e69ddf532e414418ef2b1bed182",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/25/c6/2d9856f3b32b71c3b222786edadb",
|
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/8b/03/f80c40e0efbbdf73d372eb78c7b2",
|
||||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6a/91/ddafd190b867e23110b18ddce9ab",
|
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6a/91/ddafd190b867e23110b18ddce9ab",
|
||||||
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/07/5f/246e5ef83e81f516aa82033470c5",
|
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/07/5f/246e5ef83e81f516aa82033470c5",
|
||||||
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/18/04/ed17d0ac8813451038b4831dd3c1",
|
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/18/04/ed17d0ac8813451038b4831dd3c1",
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
### 1.7.7 (build 20702, api 7, 2022-08-23)
|
### 1.7.7 (build 20704, api 7, 2022-08-23)
|
||||||
- Added `ba.app.meta.load_exported_classes()` for loading classes discovered by the meta subsystem cleanly in a background thread.
|
- Added `ba.app.meta.load_exported_classes()` for loading classes discovered by the meta subsystem cleanly in a background thread.
|
||||||
- Improved logging of missing playlist game types.
|
- Improved logging of missing playlist game types.
|
||||||
- Some ba.Lstr functionality can now be used in background threads.
|
- Some ba.Lstr functionality can now be used in background threads.
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|
||||||
// These are set automatically via script; don't modify them here.
|
// These are set automatically via script; don't modify them here.
|
||||||
const int kAppBuildNumber = 20702;
|
const int kAppBuildNumber = 20704;
|
||||||
const char* kAppVersion = "1.7.7";
|
const char* kAppVersion = "1.7.7";
|
||||||
|
|
||||||
// Our standalone globals.
|
// Our standalone globals.
|
||||||
|
|||||||
@ -453,9 +453,9 @@ auto ConnectionSet::UDPConnectionPacket(const std::vector<uint8_t>& data_in,
|
|||||||
// Client is telling us (host) that it wants to disconnect.
|
// Client is telling us (host) that it wants to disconnect.
|
||||||
|
|
||||||
uint8_t client_id = data[1];
|
uint8_t client_id = data[1];
|
||||||
if (!VerifyClientAddr(client_id, addr)) {
|
// if (!VerifyClientAddr(client_id, addr)) {
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Wipe that client out (if it still exists).
|
// Wipe that client out (if it still exists).
|
||||||
PushClientDisconnectedCall(client_id);
|
PushClientDisconnectedCall(client_id);
|
||||||
|
|||||||
@ -84,6 +84,88 @@ void NetworkReader::PokeSelf() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto HandleJSONPing(const std::string& data_str) -> std::string {
|
||||||
|
cJSON* data = cJSON_Parse(data_str.c_str());
|
||||||
|
if (data == nullptr) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
cJSON_Delete(data);
|
||||||
|
|
||||||
|
// Ok lets include some basic info that might be pertinent to someone pinging
|
||||||
|
// us. Currently that includes our current/max connection count.
|
||||||
|
char buffer[256];
|
||||||
|
int party_size = 0;
|
||||||
|
int party_size_max = 10;
|
||||||
|
if (g_python != nullptr) {
|
||||||
|
party_size = g_game->public_party_size();
|
||||||
|
party_size_max = g_game->public_party_max_size();
|
||||||
|
}
|
||||||
|
snprintf(buffer, sizeof(buffer), R"({"b":%d,"ps":%d,"psmx":%d})",
|
||||||
|
kAppBuildNumber, party_size, party_size_max);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto HandleGameQuery(const char* buffer, size_t size,
|
||||||
|
struct sockaddr_storage* from) -> void {
|
||||||
|
if (size == 5) {
|
||||||
|
// If we're already in a party, don't advertise since they
|
||||||
|
// wouldn't be able to join us anyway.
|
||||||
|
if (g_game->connections()->has_connection_to_host()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull the query id from the packet.
|
||||||
|
uint32_t query_id;
|
||||||
|
memcpy(&query_id, buffer + 1, 4);
|
||||||
|
|
||||||
|
// Ship them a response packet containing the query id,
|
||||||
|
// our protocol version, our unique-session-id, and our
|
||||||
|
// player_spec.
|
||||||
|
char msg[400];
|
||||||
|
|
||||||
|
std::string usid = GetAppInstanceUUID();
|
||||||
|
std::string player_spec_string;
|
||||||
|
|
||||||
|
// If we're signed in, send our account spec.
|
||||||
|
// Otherwise just send a dummy made with our device name.
|
||||||
|
player_spec_string = PlayerSpec::GetAccountPlayerSpec().GetSpecString();
|
||||||
|
|
||||||
|
// This should always be the case (len needs to be 1 byte)
|
||||||
|
BA_PRECONDITION_FATAL(player_spec_string.size() < 256);
|
||||||
|
|
||||||
|
BA_PRECONDITION_FATAL(!usid.empty());
|
||||||
|
if (usid.size() > 100) {
|
||||||
|
Log("had to truncate session-id; shouldn't happen");
|
||||||
|
usid.resize(100);
|
||||||
|
}
|
||||||
|
if (usid.empty()) {
|
||||||
|
usid = "error";
|
||||||
|
}
|
||||||
|
|
||||||
|
msg[0] = BA_PACKET_GAME_QUERY_RESPONSE;
|
||||||
|
memcpy(msg + 1, &query_id, 4);
|
||||||
|
uint32_t protocol_version = kProtocolVersion;
|
||||||
|
memcpy(msg + 5, &protocol_version, 4);
|
||||||
|
msg[9] = static_cast<char>(usid.size());
|
||||||
|
msg[10] = static_cast<char>(player_spec_string.size());
|
||||||
|
|
||||||
|
memcpy(msg + 11, usid.c_str(), usid.size());
|
||||||
|
memcpy(msg + 11 + usid.size(), player_spec_string.c_str(),
|
||||||
|
player_spec_string.size());
|
||||||
|
size_t msg_len = 11 + player_spec_string.size() + usid.size();
|
||||||
|
BA_PRECONDITION_FATAL(msg_len <= sizeof(msg));
|
||||||
|
|
||||||
|
std::vector<uint8_t> msg_buffer(msg_len);
|
||||||
|
memcpy(msg_buffer.data(), msg, msg_len);
|
||||||
|
|
||||||
|
g_network_write_module->PushSendToCall(msg_buffer, SockAddr(*from));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log("Error: Got invalid game-query packet of len " + std::to_string(size)
|
||||||
|
+ "; expected 5.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto NetworkReader::RunThread() -> int {
|
auto NetworkReader::RunThread() -> int {
|
||||||
if (!HeadlessMode()) {
|
if (!HeadlessMode()) {
|
||||||
remote_server_ = std::make_unique<RemoteAppServer>();
|
remote_server_ = std::make_unique<RemoteAppServer>();
|
||||||
@ -96,139 +178,11 @@ auto NetworkReader::RunThread() -> int {
|
|||||||
std::unique_lock<std::mutex> lock(paused_mutex_);
|
std::unique_lock<std::mutex> lock(paused_mutex_);
|
||||||
paused_cv_.wait(lock, [this] { return (!paused_); });
|
paused_cv_.wait(lock, [this] { return (!paused_); });
|
||||||
}
|
}
|
||||||
{
|
|
||||||
// This needs to be locked during any socket-descriptor changes/writes.
|
|
||||||
std::lock_guard<std::mutex> lock(sd_mutex_);
|
|
||||||
|
|
||||||
int result;
|
OpenSockets();
|
||||||
int print_port_unavailable = false;
|
|
||||||
int initial_requested_port = port4_;
|
|
||||||
|
|
||||||
sd4_ = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (sd4_ < 0) {
|
|
||||||
Log("ERROR: Unable to open host socket; errno "
|
|
||||||
+ g_platform->GetSocketErrorString());
|
|
||||||
} else {
|
|
||||||
g_platform->SetSocketNonBlocking(sd4_);
|
|
||||||
|
|
||||||
// Bind to local server port.
|
|
||||||
struct sockaddr_in serv_addr {};
|
|
||||||
serv_addr.sin_family = AF_INET;
|
|
||||||
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // NOLINT
|
|
||||||
|
|
||||||
// Try our requested port for v4, then go with any available if that
|
|
||||||
// doesn't work.
|
|
||||||
serv_addr.sin_port = htons(port4_); // NOLINT
|
|
||||||
result = ::bind(sd4_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
|
||||||
if (result != 0) {
|
|
||||||
// If we're headless then we abort here; we're useless if we don't get
|
|
||||||
// the port we wanted.
|
|
||||||
if (HeadlessMode()) {
|
|
||||||
Log("FATAL ERROR: unable to bind to requested udp port "
|
|
||||||
+ std::to_string(port4_) + " (ipv4)");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Primary ipv4 bind failed; try on any port as a backup.
|
|
||||||
print_port_unavailable = true;
|
|
||||||
serv_addr.sin_port = htons(0); // NOLINT
|
|
||||||
result =
|
|
||||||
::bind(sd4_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
|
||||||
|
|
||||||
// Wuh oh; no ipv6 for us i guess.
|
|
||||||
if (result != 0) {
|
|
||||||
g_platform->CloseSocket(sd4_);
|
|
||||||
sd4_ = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See what v4 port we actually wound up with.
|
|
||||||
if (sd4_ != -1) {
|
|
||||||
struct sockaddr_in sa {};
|
|
||||||
socklen_t sa_len = sizeof(sa);
|
|
||||||
if (getsockname(sd4_, reinterpret_cast<sockaddr*>(&sa), &sa_len) == 0) {
|
|
||||||
port4_ = ntohs(sa.sin_port); // NOLINT
|
|
||||||
|
|
||||||
// Aim for a v6 port to match whatever we wound up with on the v4
|
|
||||||
// side.
|
|
||||||
port6_ = port4_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ok now lets try to create an ipv6 socket on the same port.
|
|
||||||
// (its actually possible to just create a v6 socket and let the OSs
|
|
||||||
// dual-stack support provide v4 connectivity too, but that's not
|
|
||||||
// available everywhere (win XP, etc) so let's do this for now.
|
|
||||||
sd6_ = socket(AF_INET6, SOCK_DGRAM, 0);
|
|
||||||
if (sd6_ < 0) {
|
|
||||||
Log("ERROR: Unable to open ipv6 socket: "
|
|
||||||
+ g_platform->GetSocketErrorString());
|
|
||||||
} else {
|
|
||||||
// Since we're explicitly creating both a v4 and v6 socket, tell the v6
|
|
||||||
// to *not* do both itself (not sure if this is necessary; on mac it
|
|
||||||
// still seems to come up.. but apparently that's not always the case).
|
|
||||||
int on = 1;
|
|
||||||
if (setsockopt(sd6_, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
||||||
reinterpret_cast<char*>(&on), sizeof(on))
|
|
||||||
== -1) {
|
|
||||||
Log("error setting socket as ipv6-only");
|
|
||||||
}
|
|
||||||
|
|
||||||
g_platform->SetSocketNonBlocking(sd6_);
|
|
||||||
struct sockaddr_in6 serv_addr {};
|
|
||||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
|
||||||
serv_addr.sin6_family = AF_INET6;
|
|
||||||
serv_addr.sin6_port = htons(port6_); // NOLINT
|
|
||||||
serv_addr.sin6_addr = in6addr_any;
|
|
||||||
result = ::bind(sd6_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
if (HeadlessMode()) {
|
|
||||||
Log("FATAL ERROR: unable to bind to requested udp port "
|
|
||||||
+ std::to_string(port6_) + " (ipv6)");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// Primary ipv6 bind failed; try backup.
|
|
||||||
|
|
||||||
// We don't care if our random backup ports don't match; only if our
|
|
||||||
// target port failed.
|
|
||||||
if (port6_ == initial_requested_port) {
|
|
||||||
print_port_unavailable = true;
|
|
||||||
}
|
|
||||||
serv_addr.sin6_port = htons(0); // NOLINT
|
|
||||||
result =
|
|
||||||
::bind(sd6_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
|
||||||
if (result != 0) {
|
|
||||||
// Wuh oh; no ipv6 for us i guess.
|
|
||||||
g_platform->CloseSocket(sd6_);
|
|
||||||
sd6_ = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See what v6 port we actually wound up with.
|
|
||||||
if (sd6_ != -1) {
|
|
||||||
struct sockaddr_in sa {};
|
|
||||||
socklen_t sa_len = sizeof(sa);
|
|
||||||
if (getsockname(sd6_, reinterpret_cast<sockaddr*>(&sa), &sa_len) == 0) {
|
|
||||||
port6_ = ntohs(sa.sin_port); // NOLINT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (print_port_unavailable) {
|
|
||||||
// FIXME - use translations here
|
|
||||||
ScreenMessage("Unable to bind udp port "
|
|
||||||
+ std::to_string(initial_requested_port)
|
|
||||||
+ "; some network functionality may fail.",
|
|
||||||
{1, 0.5f, 0});
|
|
||||||
Log("Unable to bind udp port " + std::to_string(initial_requested_port)
|
|
||||||
+ "; some network functionality may fail.",
|
|
||||||
true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char buffer[10000];
|
|
||||||
|
|
||||||
// Now just listen and forward messages along.
|
// Now just listen and forward messages along.
|
||||||
|
char buffer[10000];
|
||||||
while (true) {
|
while (true) {
|
||||||
struct sockaddr_storage from {};
|
struct sockaddr_storage from {};
|
||||||
socklen_t from_size = sizeof(from);
|
socklen_t from_size = sizeof(from);
|
||||||
@ -272,207 +226,140 @@ auto NetworkReader::RunThread() -> int {
|
|||||||
Log("Error on select: " + g_platform->GetSocketErrorString());
|
Log("Error on select: " + g_platform->GetSocketErrorString());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int* fds[2] = {&sd4_, &sd6_};
|
|
||||||
|
|
||||||
// Wait for any data on either of our sockets.
|
// Wait for any data on either of our sockets.
|
||||||
for (auto& fd : fds) {
|
for (int sd : {sd4_, sd6_}) {
|
||||||
int& sd(*fd);
|
if (sd == -1 || !(FD_ISSET(sd, &readset))) {
|
||||||
if (sd != -1) {
|
continue;
|
||||||
if (FD_ISSET(sd, &readset)) {
|
}
|
||||||
ssize_t rresult =
|
ssize_t rresult =
|
||||||
recvfrom(sd, buffer, sizeof(buffer), 0,
|
recvfrom(sd, buffer, sizeof(buffer), 0,
|
||||||
reinterpret_cast<sockaddr*>(&from), &from_size);
|
reinterpret_cast<sockaddr*>(&from), &from_size);
|
||||||
if (rresult == 0) {
|
if (rresult == 0) {
|
||||||
Log("ERROR: NetworkReader Recv got length 0; this shouldn't "
|
Log("ERROR: NetworkReader Recv got length 0; this shouldn't "
|
||||||
"happen");
|
"happen");
|
||||||
} else if (rresult == -1) {
|
} else if (rresult == -1) {
|
||||||
|
// This needs to be locked during any sd changes/writes.
|
||||||
|
std::lock_guard<std::mutex> lock(sd_mutex_);
|
||||||
|
|
||||||
|
// If either of our sockets goes down lets close *both* of
|
||||||
|
// them.
|
||||||
|
if (sd4_ != -1) {
|
||||||
|
g_platform->CloseSocket(sd4_);
|
||||||
|
sd4_ = -1;
|
||||||
|
}
|
||||||
|
if (sd6_ != -1) {
|
||||||
|
g_platform->CloseSocket(sd6_);
|
||||||
|
sd6_ = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(from_size >= 0);
|
||||||
|
auto rresult2{static_cast<size_t>(rresult)};
|
||||||
|
// If we get *any* data while paused, kill both our
|
||||||
|
// sockets (we ping ourself for this purpose).
|
||||||
|
if (paused_) {
|
||||||
|
// This needs to be locked during any sd changes/writes.
|
||||||
|
std::lock_guard<std::mutex> lock(sd_mutex_);
|
||||||
|
if (sd4_ != -1) {
|
||||||
|
g_platform->CloseSocket(sd4_);
|
||||||
|
sd4_ = -1;
|
||||||
|
}
|
||||||
|
if (sd6_ != -1) {
|
||||||
|
g_platform->CloseSocket(sd6_);
|
||||||
|
sd6_ = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (buffer[0]) {
|
||||||
|
case BA_PACKET_POKE:
|
||||||
|
break;
|
||||||
|
case BA_PACKET_SIMPLE_PING: {
|
||||||
// This needs to be locked during any sd changes/writes.
|
// This needs to be locked during any sd changes/writes.
|
||||||
std::lock_guard<std::mutex> lock(sd_mutex_);
|
std::lock_guard<std::mutex> lock(sd_mutex_);
|
||||||
|
char msg[1] = {BA_PACKET_SIMPLE_PONG};
|
||||||
// If either of our sockets goes down lets close *both* of
|
sendto(sd, msg, 1, 0, reinterpret_cast<sockaddr*>(&from),
|
||||||
// them.
|
from_size);
|
||||||
if (sd4_ != -1) {
|
break;
|
||||||
g_platform->CloseSocket(sd4_);
|
|
||||||
sd4_ = -1;
|
|
||||||
}
|
|
||||||
if (sd6_ != -1) {
|
|
||||||
g_platform->CloseSocket(sd6_);
|
|
||||||
sd6_ = -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(from_size >= 0);
|
|
||||||
auto rresult2 = static_cast<size_t>(rresult);
|
|
||||||
// If we get *any* data while paused, kill both our
|
|
||||||
// sockets (we ping ourself for this purpose).
|
|
||||||
if (paused_) {
|
|
||||||
// This needs to be locked during any sd changes/writes.
|
|
||||||
std::lock_guard<std::mutex> lock(sd_mutex_);
|
|
||||||
if (sd4_ != -1) {
|
|
||||||
g_platform->CloseSocket(sd4_);
|
|
||||||
sd4_ = -1;
|
|
||||||
}
|
|
||||||
if (sd6_ != -1) {
|
|
||||||
g_platform->CloseSocket(sd6_);
|
|
||||||
sd6_ = -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (buffer[0]) {
|
|
||||||
case BA_PACKET_POKE:
|
|
||||||
break;
|
|
||||||
case BA_PACKET_SIMPLE_PING: {
|
|
||||||
// This needs to be locked during any sd changes/writes.
|
|
||||||
std::lock_guard<std::mutex> lock(sd_mutex_);
|
|
||||||
char msg[1] = {BA_PACKET_SIMPLE_PONG};
|
|
||||||
sendto(sd, msg, 1, 0, reinterpret_cast<sockaddr*>(&from),
|
|
||||||
from_size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BA_PACKET_JSON_PING: {
|
|
||||||
if (rresult2 > 1) {
|
|
||||||
std::vector<char> s_buffer(rresult2);
|
|
||||||
memcpy(s_buffer.data(), buffer + 1, rresult2 - 1);
|
|
||||||
s_buffer[rresult2 - 1] = 0; // terminate string
|
|
||||||
std::string response = HandleJSONPing(s_buffer.data());
|
|
||||||
if (!response.empty()) {
|
|
||||||
std::vector<char> msg(1 + response.size());
|
|
||||||
msg[0] = BA_PACKET_JSON_PONG;
|
|
||||||
memcpy(msg.data() + 1, response.c_str(),
|
|
||||||
response.size());
|
|
||||||
std::lock_guard<std::mutex> lock(sd_mutex_);
|
|
||||||
sendto(sd, msg.data(),
|
|
||||||
static_cast_check_fit<socket_send_length_t>(
|
|
||||||
msg.size()),
|
|
||||||
0, reinterpret_cast<sockaddr*>(&from),
|
|
||||||
from_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BA_PACKET_JSON_PONG: {
|
|
||||||
if (rresult2 > 1) {
|
|
||||||
std::vector<char> s_buffer(rresult2);
|
|
||||||
memcpy(s_buffer.data(), buffer + 1, rresult2 - 1);
|
|
||||||
s_buffer[rresult2 - 1] = 0; // terminate string
|
|
||||||
cJSON* data = cJSON_Parse(s_buffer.data());
|
|
||||||
if (data != nullptr) {
|
|
||||||
cJSON_Delete(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BA_PACKET_REMOTE_PING:
|
|
||||||
case BA_PACKET_REMOTE_PONG:
|
|
||||||
case BA_PACKET_REMOTE_ID_REQUEST:
|
|
||||||
case BA_PACKET_REMOTE_ID_RESPONSE:
|
|
||||||
case BA_PACKET_REMOTE_DISCONNECT:
|
|
||||||
case BA_PACKET_REMOTE_STATE:
|
|
||||||
case BA_PACKET_REMOTE_STATE2:
|
|
||||||
case BA_PACKET_REMOTE_STATE_ACK:
|
|
||||||
case BA_PACKET_REMOTE_DISCONNECT_ACK:
|
|
||||||
case BA_PACKET_REMOTE_GAME_QUERY:
|
|
||||||
case BA_PACKET_REMOTE_GAME_RESPONSE:
|
|
||||||
// These packets are associated with the remote app; let the
|
|
||||||
// remote server handle them.
|
|
||||||
if (remote_server_) {
|
|
||||||
remote_server_->HandleData(
|
|
||||||
sd, reinterpret_cast<uint8_t*>(buffer), rresult2,
|
|
||||||
reinterpret_cast<sockaddr*>(&from),
|
|
||||||
static_cast<size_t>(from_size));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BA_PACKET_CLIENT_REQUEST:
|
|
||||||
case BA_PACKET_CLIENT_ACCEPT:
|
|
||||||
case BA_PACKET_CLIENT_DENY:
|
|
||||||
case BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY:
|
|
||||||
case BA_PACKET_CLIENT_DENY_VERSION_MISMATCH:
|
|
||||||
case BA_PACKET_CLIENT_DENY_PARTY_FULL:
|
|
||||||
case BA_PACKET_DISCONNECT_FROM_CLIENT_REQUEST:
|
|
||||||
case BA_PACKET_DISCONNECT_FROM_CLIENT_ACK:
|
|
||||||
case BA_PACKET_DISCONNECT_FROM_HOST_REQUEST:
|
|
||||||
case BA_PACKET_DISCONNECT_FROM_HOST_ACK:
|
|
||||||
case BA_PACKET_CLIENT_GAMEPACKET_COMPRESSED:
|
|
||||||
case BA_PACKET_HOST_GAMEPACKET_COMPRESSED: {
|
|
||||||
// These messages are associated with udp host/client
|
|
||||||
// connections.. pass them to the game thread to wrangle.
|
|
||||||
std::vector<uint8_t> msg_buffer(rresult2);
|
|
||||||
memcpy(&(msg_buffer[0]), buffer, rresult2);
|
|
||||||
g_game->connections()->PushUDPConnectionPacketCall(
|
|
||||||
msg_buffer, SockAddr(from));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BA_PACKET_GAME_QUERY: {
|
|
||||||
if (rresult2 == 5) {
|
|
||||||
// If we're already in a party, don't advertise since they
|
|
||||||
// wouldn't be able to join us anyway.
|
|
||||||
if (g_game->connections()->has_connection_to_host()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull the query id from the packet.
|
|
||||||
uint32_t query_id;
|
|
||||||
memcpy(&query_id, buffer + 1, 4);
|
|
||||||
|
|
||||||
// Ship them a response packet containing the query id,
|
|
||||||
// our protocol version, our unique-session-id, and our
|
|
||||||
// player_spec.
|
|
||||||
char msg[400];
|
|
||||||
|
|
||||||
std::string usid = GetAppInstanceUUID();
|
|
||||||
std::string player_spec_string;
|
|
||||||
|
|
||||||
// If we're signed in, send our account spec.
|
|
||||||
// Otherwise just send a dummy made with our device name.
|
|
||||||
player_spec_string =
|
|
||||||
PlayerSpec::GetAccountPlayerSpec().GetSpecString();
|
|
||||||
|
|
||||||
// This should always be the case (len needs to be 1 byte)
|
|
||||||
BA_PRECONDITION_FATAL(player_spec_string.size() < 256);
|
|
||||||
|
|
||||||
BA_PRECONDITION_FATAL(!usid.empty());
|
|
||||||
if (usid.size() > 100) {
|
|
||||||
Log("had to truncate session-id; shouldn't happen");
|
|
||||||
usid.resize(100);
|
|
||||||
}
|
|
||||||
if (usid.empty()) {
|
|
||||||
usid = "error";
|
|
||||||
}
|
|
||||||
|
|
||||||
msg[0] = BA_PACKET_GAME_QUERY_RESPONSE;
|
|
||||||
memcpy(msg + 1, &query_id, 4);
|
|
||||||
uint32_t protocol_version = kProtocolVersion;
|
|
||||||
memcpy(msg + 5, &protocol_version, 4);
|
|
||||||
msg[9] = static_cast<char>(usid.size());
|
|
||||||
msg[10] = static_cast<char>(player_spec_string.size());
|
|
||||||
|
|
||||||
memcpy(msg + 11, usid.c_str(), usid.size());
|
|
||||||
memcpy(msg + 11 + usid.size(), player_spec_string.c_str(),
|
|
||||||
player_spec_string.size());
|
|
||||||
size_t msg_len =
|
|
||||||
11 + player_spec_string.size() + usid.size();
|
|
||||||
BA_PRECONDITION_FATAL(msg_len <= sizeof(msg));
|
|
||||||
|
|
||||||
std::vector<uint8_t> msg_buffer(msg_len);
|
|
||||||
memcpy(msg_buffer.data(), msg, msg_len);
|
|
||||||
|
|
||||||
g_network_write_module->PushSendToCall(msg_buffer,
|
|
||||||
SockAddr(from));
|
|
||||||
break;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log("Error: Got invalid game-query packet of len "
|
|
||||||
+ std::to_string(rresult2) + "; expected 5.");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case BA_PACKET_JSON_PING: {
|
||||||
|
if (rresult2 > 1) {
|
||||||
|
std::vector<char> s_buffer(rresult2);
|
||||||
|
memcpy(s_buffer.data(), buffer + 1, rresult2 - 1);
|
||||||
|
s_buffer[rresult2 - 1] = 0; // terminate string
|
||||||
|
std::string response = HandleJSONPing(s_buffer.data());
|
||||||
|
if (!response.empty()) {
|
||||||
|
std::vector<char> msg(1 + response.size());
|
||||||
|
msg[0] = BA_PACKET_JSON_PONG;
|
||||||
|
memcpy(msg.data() + 1, response.c_str(), response.size());
|
||||||
|
std::lock_guard<std::mutex> lock(sd_mutex_);
|
||||||
|
sendto(
|
||||||
|
sd, msg.data(),
|
||||||
|
static_cast_check_fit<socket_send_length_t>(msg.size()),
|
||||||
|
0, reinterpret_cast<sockaddr*>(&from), from_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BA_PACKET_JSON_PONG: {
|
||||||
|
if (rresult2 > 1) {
|
||||||
|
std::vector<char> s_buffer(rresult2);
|
||||||
|
memcpy(s_buffer.data(), buffer + 1, rresult2 - 1);
|
||||||
|
s_buffer[rresult2 - 1] = 0; // terminate string
|
||||||
|
cJSON* data = cJSON_Parse(s_buffer.data());
|
||||||
|
if (data != nullptr) {
|
||||||
|
cJSON_Delete(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BA_PACKET_REMOTE_PING:
|
||||||
|
case BA_PACKET_REMOTE_PONG:
|
||||||
|
case BA_PACKET_REMOTE_ID_REQUEST:
|
||||||
|
case BA_PACKET_REMOTE_ID_RESPONSE:
|
||||||
|
case BA_PACKET_REMOTE_DISCONNECT:
|
||||||
|
case BA_PACKET_REMOTE_STATE:
|
||||||
|
case BA_PACKET_REMOTE_STATE2:
|
||||||
|
case BA_PACKET_REMOTE_STATE_ACK:
|
||||||
|
case BA_PACKET_REMOTE_DISCONNECT_ACK:
|
||||||
|
case BA_PACKET_REMOTE_GAME_QUERY:
|
||||||
|
case BA_PACKET_REMOTE_GAME_RESPONSE:
|
||||||
|
// These packets are associated with the remote app; let the
|
||||||
|
// remote server handle them.
|
||||||
|
if (remote_server_) {
|
||||||
|
remote_server_->HandleData(
|
||||||
|
sd, reinterpret_cast<uint8_t*>(buffer), rresult2,
|
||||||
|
reinterpret_cast<sockaddr*>(&from),
|
||||||
|
static_cast<size_t>(from_size));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BA_PACKET_CLIENT_REQUEST:
|
||||||
|
case BA_PACKET_CLIENT_ACCEPT:
|
||||||
|
case BA_PACKET_CLIENT_DENY:
|
||||||
|
case BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY:
|
||||||
|
case BA_PACKET_CLIENT_DENY_VERSION_MISMATCH:
|
||||||
|
case BA_PACKET_CLIENT_DENY_PARTY_FULL:
|
||||||
|
case BA_PACKET_DISCONNECT_FROM_CLIENT_REQUEST:
|
||||||
|
case BA_PACKET_DISCONNECT_FROM_CLIENT_ACK:
|
||||||
|
case BA_PACKET_DISCONNECT_FROM_HOST_REQUEST:
|
||||||
|
case BA_PACKET_DISCONNECT_FROM_HOST_ACK:
|
||||||
|
case BA_PACKET_CLIENT_GAMEPACKET_COMPRESSED:
|
||||||
|
case BA_PACKET_HOST_GAMEPACKET_COMPRESSED: {
|
||||||
|
// These messages are associated with udp host/client
|
||||||
|
// connections.. pass them to the game thread to wrangle.
|
||||||
|
std::vector<uint8_t> msg_buffer(rresult2);
|
||||||
|
memcpy(&(msg_buffer[0]), buffer, rresult2);
|
||||||
|
g_game->connections()->PushUDPConnectionPacketCall(
|
||||||
|
msg_buffer, SockAddr(from));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BA_PACKET_GAME_QUERY: {
|
||||||
|
HandleGameQuery(buffer, rresult2, &from);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -489,27 +376,135 @@ auto NetworkReader::RunThread() -> int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkReader::~NetworkReader() = default;
|
auto NetworkReader::OpenSockets() -> void {
|
||||||
|
// This needs to be locked during any socket-descriptor changes/writes.
|
||||||
|
std::lock_guard<std::mutex> lock(sd_mutex_);
|
||||||
|
|
||||||
auto NetworkReader::HandleJSONPing(const std::string& data_str) -> std::string {
|
int result;
|
||||||
cJSON* data = cJSON_Parse(data_str.c_str());
|
int print_port_unavailable = false;
|
||||||
if (data == nullptr) {
|
int initial_requested_port = port4_;
|
||||||
return "";
|
|
||||||
}
|
|
||||||
cJSON_Delete(data);
|
|
||||||
|
|
||||||
// Ok lets include some basic info that might be pertinent to someone pinging
|
sd4_ = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
// us. Currently that includes our current/max connection count.
|
if (sd4_ < 0) {
|
||||||
char buffer[256];
|
Log("ERROR: Unable to open host socket; errno "
|
||||||
int party_size = 0;
|
+ g_platform->GetSocketErrorString());
|
||||||
int party_size_max = 10;
|
} else {
|
||||||
if (g_python != nullptr) {
|
g_platform->SetSocketNonBlocking(sd4_);
|
||||||
party_size = g_game->public_party_size();
|
|
||||||
party_size_max = g_game->public_party_max_size();
|
// Bind to local server port.
|
||||||
|
struct sockaddr_in serv_addr {};
|
||||||
|
serv_addr.sin_family = AF_INET;
|
||||||
|
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // NOLINT
|
||||||
|
|
||||||
|
// Try our requested port for v4, then go with any available if that
|
||||||
|
// doesn't work.
|
||||||
|
serv_addr.sin_port = htons(port4_); // NOLINT
|
||||||
|
result = ::bind(sd4_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
||||||
|
if (result != 0) {
|
||||||
|
// If we're headless then we abort here; we're useless if we don't get
|
||||||
|
// the port we wanted.
|
||||||
|
if (HeadlessMode()) {
|
||||||
|
Log("FATAL ERROR: unable to bind to requested udp port "
|
||||||
|
+ std::to_string(port4_) + " (ipv4)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primary ipv4 bind failed; try on any port as a backup.
|
||||||
|
print_port_unavailable = true;
|
||||||
|
serv_addr.sin_port = htons(0); // NOLINT
|
||||||
|
result = ::bind(sd4_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
||||||
|
|
||||||
|
// Wuh oh; no ipv6 for us i guess.
|
||||||
|
if (result != 0) {
|
||||||
|
g_platform->CloseSocket(sd4_);
|
||||||
|
sd4_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See what v4 port we actually wound up with.
|
||||||
|
if (sd4_ != -1) {
|
||||||
|
struct sockaddr_in sa {};
|
||||||
|
socklen_t sa_len = sizeof(sa);
|
||||||
|
if (getsockname(sd4_, reinterpret_cast<sockaddr*>(&sa), &sa_len) == 0) {
|
||||||
|
port4_ = ntohs(sa.sin_port); // NOLINT
|
||||||
|
|
||||||
|
// Aim for a v6 port to match whatever we wound up with on the v4
|
||||||
|
// side.
|
||||||
|
port6_ = port4_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok now lets try to create an ipv6 socket on the same port.
|
||||||
|
// (its actually possible to just create a v6 socket and let the OSs
|
||||||
|
// dual-stack support provide v4 connectivity too, but that's not
|
||||||
|
// available everywhere (win XP, etc) so let's do this for now.
|
||||||
|
sd6_ = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||||
|
if (sd6_ < 0) {
|
||||||
|
Log("ERROR: Unable to open ipv6 socket: "
|
||||||
|
+ g_platform->GetSocketErrorString());
|
||||||
|
} else {
|
||||||
|
// Since we're explicitly creating both a v4 and v6 socket, tell the v6
|
||||||
|
// to *not* do both itself (not sure if this is necessary; on mac it
|
||||||
|
// still seems to come up.. but apparently that's not always the case).
|
||||||
|
int on = 1;
|
||||||
|
if (setsockopt(sd6_, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||||
|
reinterpret_cast<char*>(&on), sizeof(on))
|
||||||
|
== -1) {
|
||||||
|
Log("error setting socket as ipv6-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_platform->SetSocketNonBlocking(sd6_);
|
||||||
|
struct sockaddr_in6 serv_addr {};
|
||||||
|
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||||
|
serv_addr.sin6_family = AF_INET6;
|
||||||
|
serv_addr.sin6_port = htons(port6_); // NOLINT
|
||||||
|
serv_addr.sin6_addr = in6addr_any;
|
||||||
|
result = ::bind(sd6_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
if (HeadlessMode()) {
|
||||||
|
Log("FATAL ERROR: unable to bind to requested udp port "
|
||||||
|
+ std::to_string(port6_) + " (ipv6)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// Primary ipv6 bind failed; try backup.
|
||||||
|
|
||||||
|
// We don't care if our random backup ports don't match; only if our
|
||||||
|
// target port failed.
|
||||||
|
if (port6_ == initial_requested_port) {
|
||||||
|
print_port_unavailable = true;
|
||||||
|
}
|
||||||
|
serv_addr.sin6_port = htons(0); // NOLINT
|
||||||
|
result = ::bind(sd6_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
||||||
|
if (result != 0) {
|
||||||
|
// Wuh oh; no ipv6 for us i guess.
|
||||||
|
g_platform->CloseSocket(sd6_);
|
||||||
|
sd6_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See what v6 port we actually wound up with.
|
||||||
|
if (sd6_ != -1) {
|
||||||
|
struct sockaddr_in sa {};
|
||||||
|
socklen_t sa_len = sizeof(sa);
|
||||||
|
if (getsockname(sd6_, reinterpret_cast<sockaddr*>(&sa), &sa_len) == 0) {
|
||||||
|
port6_ = ntohs(sa.sin_port); // NOLINT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (print_port_unavailable) {
|
||||||
|
// FIXME - use translations here
|
||||||
|
ScreenMessage("Unable to bind udp port "
|
||||||
|
+ std::to_string(initial_requested_port)
|
||||||
|
+ "; some network functionality may fail.",
|
||||||
|
{1, 0.5f, 0});
|
||||||
|
Log("Unable to bind udp port " + std::to_string(initial_requested_port)
|
||||||
|
+ "; some network functionality may fail.",
|
||||||
|
true, false);
|
||||||
}
|
}
|
||||||
snprintf(buffer, sizeof(buffer), R"({"b":%d,"ps":%d,"psmx":%d})",
|
|
||||||
kAppBuildNumber, party_size, party_size_max);
|
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkReader::~NetworkReader() = default;
|
||||||
|
|
||||||
} // namespace ballistica
|
} // namespace ballistica
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class NetworkReader {
|
|||||||
auto sd6() const { return sd6_; }
|
auto sd6() const { return sd6_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto HandleJSONPing(const std::string& data) -> std::string;
|
auto OpenSockets() -> void;
|
||||||
auto PokeSelf() -> void;
|
auto PokeSelf() -> void;
|
||||||
auto RunThread() -> int;
|
auto RunThread() -> int;
|
||||||
static auto RunThreadStatic(void* self) -> int {
|
static auto RunThreadStatic(void* self) -> int {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user