Skip to content

Commit

Permalink
cleanups and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
dankmeme01 committed Dec 1, 2023
1 parent edd35dd commit 7a72fdd
Show file tree
Hide file tree
Showing 29 changed files with 195 additions and 148 deletions.
4 changes: 4 additions & 0 deletions server/game/src/data/bytebufferext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ impl<'a> FastByteBuffer<'a> {
}
}

pub fn new_with_length(src: &'a mut [u8], len: usize) -> Self {
Self { pos: 0, len, data: src }
}

pub fn write_u8(&mut self, val: u8) {
self.internal_write(&val.to_be_bytes());
}
Expand Down
12 changes: 5 additions & 7 deletions server/game/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
state::ServerState,
};

const MAX_PACKET_SIZE: usize = 16384;
const MAX_PACKET_SIZE: usize = 8192;

pub struct GameServerConfiguration {
pub http_client: reqwest::Client,
Expand Down Expand Up @@ -78,11 +78,8 @@ impl GameServer {
});
}

// we preallocate a buffer to avoid zeroing out MAX_PACKET_SIZE bytes on each packet
let mut buf = [0u8; MAX_PACKET_SIZE];

loop {
match self.recv_and_handle(&mut buf).await {
match self.recv_and_handle().await {
Ok(()) => {}
Err(err) => {
warn!("Failed to handle a packet: {err}");
Expand Down Expand Up @@ -182,8 +179,9 @@ impl GameServer {
Ok(())
}

async fn recv_and_handle(&'static self, buf: &mut [u8]) -> anyhow::Result<()> {
let (len, peer) = self.socket.recv_from(buf).await?;
async fn recv_and_handle(&'static self) -> anyhow::Result<()> {
let mut buf = [0u8; MAX_PACKET_SIZE];
let (len, peer) = self.socket.recv_from(&mut buf).await?;

let peer = match peer {
SocketAddr::V6(_) => bail!("rejecting request from ipv6 host"),
Expand Down
4 changes: 4 additions & 0 deletions server/game/src/server_thread/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub enum PacketHandlingError {
UnexpectedCentralResponse, // malformed response from the central server
ColorParseFailed(ColorParseError), // failed to parse a hex color into a Color3B struct
Ratelimited, // too many packets per second
DangerousAllocation(usize), // attempted to allocate a huge chunk of memory with alloca
}

pub type Result<T> = core::result::Result<T, PacketHandlingError>;
Expand Down Expand Up @@ -76,6 +77,9 @@ impl Display for PacketHandlingError {
Self::UnexpectedCentralResponse => f.write_str("got unexpected response from the central server"),
Self::ColorParseFailed(err) => f.write_fmt(format_args!("failed to parse a color: {err}")),
Self::Ratelimited => f.write_str("client is sending way too many packets per second"),
Self::DangerousAllocation(size) => f.write_fmt(format_args!(
"attempted to allocate {size} bytes on the stack - that has a potential for a stack overflow!"
)),
}
}
}
14 changes: 14 additions & 0 deletions server/game/src/server_thread/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ macro_rules! gs_needauth {
};
}

pub const MAX_ALLOCA_SIZE: usize = 100_000;

macro_rules! gs_alloca_check_size {
($size:expr) => {
if $size > crate::server_thread::handlers::MAX_ALLOCA_SIZE {
let err = crate::server_thread::error::PacketHandlingError::DangerousAllocation($size);
return Err(err);
}
};
}

/// hype af (variable size stack allocation)
macro_rules! gs_with_alloca {
($size:expr, $data:ident, $code:expr) => {
Expand All @@ -88,6 +99,8 @@ macro_rules! gs_inline_encode {
};

($self:ident, $size:expr, $data:ident, $rawdata:ident, $code:expr) => {
gs_alloca_check_size!($size);

let retval: Result<Option<Vec<u8>>> = {
gs_with_alloca!($size, $rawdata, {
let mut $data = FastByteBuffer::new($rawdata);
Expand All @@ -112,6 +125,7 @@ macro_rules! gs_inline_encode {
}
}

pub(crate) use gs_alloca_check_size;
pub(crate) use gs_disconnect;
pub(crate) use gs_handler;
pub(crate) use gs_handler_sync;
Expand Down
17 changes: 10 additions & 7 deletions server/game/src/server_thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ impl GameServerThread {
| PacketHandlingError::ColorParseFailed(_)
| PacketHandlingError::UnexpectedCentralResponse
| PacketHandlingError::SystemTimeError(_)
| PacketHandlingError::WebRequestError(_) => {
| PacketHandlingError::WebRequestError(_)
| PacketHandlingError::DangerousAllocation(_) => {
log::error!("[{} @ {}] err: {}", self.account_id.load(Ordering::Relaxed), self.peer, error);
}
// these can likely never happen unless network corruption or someone is pentesting, so ignore in release
Expand Down Expand Up @@ -168,12 +169,11 @@ impl GameServerThread {
}

/// fast packet sending with best-case zero heap allocation.
/// on average, this is 2-3x faster than `send_packet`, even worst case should be faster by a bit.
/// if the packet size isn't known at compile time, calculate it and use `send_packet_fast_rough`
async fn send_packet_fast<P: Packet + EncodableWithKnownSize>(&self, packet: &P) -> Result<()> {
// in theory, the size is known at compile time, however we still have to resort to using alloca
// because rust does not allow constant expressions with generic parameters.
// i.e. this would fail to compile: `let buffer = [0u8; PacketHeader::SIZE + P::ENCODED_SIZE];`
// in theory, the size is known at compile time, however for some reason,
// alloca manages to be significantly faster than a `[MaybeUninit<u8>; N]`.
// i have no idea why or how, but yeah.
self.send_packet_fast_rough(packet, P::ENCODED_SIZE).await
}

Expand All @@ -196,6 +196,8 @@ impl GameServerThread {
let mac_start = nonce_start + NONCE_SIZE;
let raw_data_start = mac_start + MAC_SIZE;

gs_alloca_check_size!(total_size);

let to_send: Result<Option<Vec<u8>>> = gs_with_alloca!(total_size, data, {
// write the header
let mut buf = FastByteBuffer::new(data);
Expand Down Expand Up @@ -295,7 +297,6 @@ impl GameServerThread {
.encrypt(&nonce, cltxtbuf.as_bytes())
.map_err(|_| PacketHandlingError::EncryptionError)?;

#[cfg(not(rust_analyzer))] // i am so sorry
buf.write_bytes(&nonce);
buf.write_bytes(&encrypted);

Expand Down Expand Up @@ -325,7 +326,7 @@ impl GameServerThread {
}

// check if we are sending too many packets
if !self.rate_limiter.lock().tick() {
if !self.rate_limiter.lock().try_tick() {
return Err(PacketHandlingError::Ratelimited);
}

Expand Down Expand Up @@ -359,13 +360,15 @@ impl GameServerThread {
return Err(PacketHandlingError::MalformedLoginAttempt);
}

// decrypt the packet in-place if encrypted
if header.encrypted {
if message.len() < PacketHeader::SIZE + NONCE_SIZE + MAC_SIZE {
return Err(PacketHandlingError::MalformedCiphertext);
}

let cbox = self.crypto_box.get();
if cbox.is_none() {
self.terminate();
return Err(PacketHandlingError::WrongCryptoBoxState);
}

Expand Down
17 changes: 9 additions & 8 deletions server/game/src/util/rate_limiter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,19 @@ impl SimpleRateLimiter {
}

/// Returns `true` if we are not ratelimited, `false` if we are.
pub fn tick(&mut self) -> bool {
let now = Instant::now();
if (now - self.last_refill) > self.period {
self.count = self.limit;
self.last_refill = now;
}

pub fn try_tick(&mut self) -> bool {
if self.count > 0 {
self.count -= 1;
true
} else {
false
let now = Instant::now();
if (now - self.last_refill) > self.period {
self.count = self.limit;
self.last_refill = now;
true
} else {
false
}
}
}
}
2 changes: 2 additions & 0 deletions src/audio/all.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@

#include "audio_frame.hpp"
#include "audio_manager.hpp"
#include "audio_sample_queue.hpp"
#include "audio_stream.hpp"
#include "opus_codec.hpp"
#include "voice_playback_manager.hpp"
1 change: 0 additions & 1 deletion src/audio/audio_frame.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#pragma once

#include <defs.hpp>

#if GLOBED_VOICE_SUPPORT
Expand Down
10 changes: 4 additions & 6 deletions src/audio/audio_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

#if GLOBED_VOICE_SUPPORT

#include <util/time.hpp>
#include <util/debugging.hpp>
#include <managers/error_queues.hpp>

// this is horrible i know yes
Expand Down Expand Up @@ -302,7 +300,7 @@ void GlobedAudioManager::audioThreadFunc() {
// if we are not recording right now, sleep
if (!recordActive) {
audioThreadSleeping = true;
std::this_thread::sleep_for(std::chrono::milliseconds(25));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
}

Expand All @@ -328,7 +326,7 @@ void GlobedAudioManager::audioThreadFunc() {
// if we are at the same position, do nothing
if (pos == recordLastPosition) {
this->getSystem()->update();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
std::this_thread::sleep_for(std::chrono::milliseconds(3));
continue;
}

Expand Down Expand Up @@ -372,7 +370,7 @@ void GlobedAudioManager::audioThreadFunc() {
this->getSystem()->update();

// TODO maybe do something with this i dunno
std::this_thread::sleep_for(std::chrono::milliseconds(5));
std::this_thread::sleep_for(std::chrono::milliseconds(3));
// std::this_thread::yield();
}
}
Expand Down Expand Up @@ -474,7 +472,7 @@ const char* GlobedAudioManager::fmodErrorString(FMOD_RESULT result) {
int idx = static_cast<int>(result);

if (idx < 0 || idx > 81) {
return "Invalid FMOD result was passed; there is no corresponding error message to return";
return "Invalid FMOD error code was passed; there is no corresponding error message to return";
}

return values[idx];
Expand Down
1 change: 1 addition & 0 deletions src/audio/audio_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class GlobedAudioManager {
// start recording the voice and call the callback once a full frame is ready.
// if `stopRecording()` is called at any point, the callback will be called with the remaining data.
// in that case it may have less than the full 10 frames.
// WARNING: the callback is called from the audio thread, not the GD/cocos thread.
void startRecording(std::function<void(const EncodedAudioFrame&)> callback);
// tell the audio thread to stop recording
void stopRecording();
Expand Down
6 changes: 5 additions & 1 deletion src/audio/audio_sample_queue.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "audio_sample_queue.hpp"

#if GLOBED_VOICE_SUPPORT

void AudioSampleQueue::writeData(DecodedOpusData data) {
this->writeData(data.ptr, data.length);
}
Expand Down Expand Up @@ -31,4 +33,6 @@ size_t AudioSampleQueue::size() const {

void AudioSampleQueue::clear() {
buf.clear();
}
}

#endif // GLOBED_VOICE_SUPPORT
3 changes: 0 additions & 3 deletions src/audio/audio_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
#include "audio_frame.hpp"
#include "audio_manager.hpp"

#include <util/time.hpp>
#include <util/debugging.hpp>

AudioStream::AudioStream() {
FMOD_CREATESOUNDEXINFO exinfo = {};

Expand Down
1 change: 0 additions & 1 deletion src/audio/voice_playback_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#include "audio_frame.hpp"
#include "audio_stream.hpp"
#include <chrono>

/*
* VoicePlaybackManager is responsible for playing voices of multiple people
Expand Down
3 changes: 2 additions & 1 deletion src/crypto/base_box.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <defs.hpp>
#include <util/data.hpp>
#include <string>

/*
* This class contains no crypto implementation and is here just for boilerplate code.
Expand Down Expand Up @@ -48,7 +49,7 @@ class BaseCryptoBox {
util::data::bytevector encrypt(const std::string& src);

/* Decryption */

// Decrypt `size` bytes from `data` into itself. Returns the length of the plaintext data.
size_t decryptInPlace(util::data::byte* data, size_t size);

Expand Down
1 change: 0 additions & 1 deletion src/crypto/box.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <util/data.hpp>

#include <sodium.h>
#include <string>


class CryptoBox : public BaseCryptoBox {
Expand Down
1 change: 0 additions & 1 deletion src/crypto/secret_box.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <util/data.hpp>

#include <sodium.h>
#include <string>

/*
* SecretBox - a class similar to CryptoBox, but instead of using public key cryptography,
Expand Down
18 changes: 4 additions & 14 deletions src/data/bytebuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,27 +132,17 @@ class ByteBuffer {
template<size_t BitCount>
BitBuffer<BitCount> readBits() {
constexpr size_t byteCount = util::data::bitsToBytes(BitCount);
boundsCheck(byteCount);
this->boundsCheck(byteCount);

auto value = read<BitBufferUnderlyingType<BitCount>>();
// I am not 100% sure about it, but it appears that byteswapping is unnecessary for BitBuffer.

// if constexpr (GLOBED_LITTLE_ENDIAN) {
// value = util::data::byteswap(value);
// }
auto value = this->read<BitBufferUnderlyingType<BitCount>>();

return BitBuffer<BitCount>(value);
}

// Write all bits from the given `BitBuffer` into the current `ByteBuffer`
template<size_t BitCount>
void writeBits(BitBuffer<BitCount> bitbuf) {
auto value = bitbuf.contents();
// if constexpr (GLOBED_LITTLE_ENDIAN) {
// value = util::data::byteswap(value);
// }

write(value);
this->write(bitbuf.contents());
}

/*
Expand Down Expand Up @@ -180,7 +170,7 @@ class ByteBuffer {
if (this->readBool()) {
value = this->readValue<T>();
}

return std::move(value);
}

Expand Down
2 changes: 1 addition & 1 deletion src/data/packets/client/misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

/*
* RawPacket is a special packet. It is not an actual specific packet and has no consistent representation.
* Example usage and explanation can be found in `ui/hooks/play_layer.hpp` in the audio callback function.
* Example usage and explanation can be found in `ui/hooks/play_layer.hpp` in the audio callback.
*/
class RawPacket : public Packet {
public:
Expand Down
1 change: 0 additions & 1 deletion src/defs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@

#include <defs/assert.hpp>
#include <defs/crash.hpp>
#include <defs/net.hpp>
#include <defs/platform.hpp>
#include <defs/util.hpp>
4 changes: 2 additions & 2 deletions src/defs/platform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
* platform macros
* GLOBED_WIN32, GLOBED_MAC, GLOBED_ANDROID - self descriptive
* GLOBED_UNIX - mac or android
* GLOBED_X86_32, GLOBED_X86_64, GLOBED_ARM32, GLOBED_ARM64 - only 1 of those 4 is defined, indicating if we are 32-bit or 64-bit
* GLOBED_X86, GLOBED_ARM - any x86 or arm
* GLOBED_X86_32, GLOBED_X86_64, GLOBED_ARM32, GLOBED_ARM64 - only 1 of those 4 is defined, indicating the specific architecture
* GLOBED_X86, GLOBED_ARM - both x86 and x86_64 or both arm and arm64
*
* GLOBED_PLATFORM_STRING_PLATFORM - string in format like "Mac", "Android", "Windows"
* GLOBED_PLATFORM_STRING_ARCH - string in format like "x86", "x64", "armv7", "arm64"
Expand Down
Loading

0 comments on commit 7a72fdd

Please sign in to comment.