updates by buttocks by fixing uneven bytes recv
This commit is contained in:
		
							parent
							
								
									a29a884671
								
							
						
					
					
						commit
						2eb343d6e0
					
				
							
								
								
									
										105
									
								
								extension.cpp
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								extension.cpp
									
									
									
									
									
								
							@ -46,9 +46,16 @@
 | 
				
			|||||||
#include "CDetour/detours.h"
 | 
					#include "CDetour/detours.h"
 | 
				
			||||||
#include "extension.h"
 | 
					#include "extension.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// voice packets are sent over unreliable netchannel
 | 
				
			||||||
 | 
					//#define NET_MAX_DATAGRAM_PAYLOAD	4000	// = maximum unreliable payload size
 | 
				
			||||||
 | 
					// voice packetsize = 64 | netchannel overflows at >4000 bytes
 | 
				
			||||||
 | 
					// with 22050 samplerate and 512 frames per packet -> 23.22ms per packet
 | 
				
			||||||
 | 
					// SVC_VoiceData overhead = 5 bytes
 | 
				
			||||||
 | 
					// sensible limit of 8 packets per frame = 552 bytes -> 185.76ms of voice data per frame
 | 
				
			||||||
 | 
					#define NET_MAX_VOICE_BYTES_FRAME (8 * (5 + 64))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ConVar g_SmVoiceAddr("sm_voice_addr", "127.0.0.1", FCVAR_PROTECTED, "Voice server listen ip address.");
 | 
					ConVar g_SmVoiceAddr("sm_voice_addr", "127.0.0.1", FCVAR_PROTECTED, "Voice server listen ip address.");
 | 
				
			||||||
ConVar g_SmVoicePort("sm_voice_port", "27020", FCVAR_PROTECTED, "Voice server listen port.", true, 1025.0, true, 65535.0);
 | 
					ConVar g_SmVoicePort("sm_voice_port", "27020", FCVAR_PROTECTED, "Voice server listen port.", true, 1025.0, true, 65535.0);
 | 
				
			||||||
ConVar g_SmVoiceLogging("sm_voice_logging", "0", FCVAR_PROTECTED, "Log voice packets.");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @file extension.cpp
 | 
					 * @file extension.cpp
 | 
				
			||||||
@ -67,29 +74,6 @@ IServer *iserver = NULL;
 | 
				
			|||||||
double g_fLastVoiceData[SM_MAXPLAYERS + 1];
 | 
					double g_fLastVoiceData[SM_MAXPLAYERS + 1];
 | 
				
			||||||
int g_aFrameVoiceBytes[SM_MAXPLAYERS + 1];
 | 
					int g_aFrameVoiceBytes[SM_MAXPLAYERS + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NET_MAX_VOICE_BYTES_FRAME 512
 | 
					 | 
				
			||||||
#define NET_MAX_VOICE_BYTES_FRAME_LOG 1024
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
// This is just the client_t->netchan.datagram buffer size (shouldn't ever need to be huge)
 | 
					 | 
				
			||||||
#define NET_MAX_VOICE_BYTES_FRAME    4000    // = maximum unreliable payload size
 | 
					 | 
				
			||||||
maybe try 1024 for starters
 | 
					 | 
				
			||||||
instead of 4096
 | 
					 | 
				
			||||||
voice data should never be that big
 | 
					 | 
				
			||||||
actually I can give you a fool-proof number
 | 
					 | 
				
			||||||
since I did tests for torchlight
 | 
					 | 
				
			||||||
the packetsize is hardcoded 64 bytes
 | 
					 | 
				
			||||||
torchlight sends max 5 frames at once to clients
 | 
					 | 
				
			||||||
there are 512 frames per packet
 | 
					 | 
				
			||||||
sample rate 22050
 | 
					 | 
				
			||||||
so one packet is 23.2ms
 | 
					 | 
				
			||||||
anyways, since torchlight only sends 5 packets at once, which is 5*64 = 320 bytes
 | 
					 | 
				
			||||||
make the limit > 384 (6 * 64)
 | 
					 | 
				
			||||||
I'm thinking the guy probably just sends a huge packet with max size 4000 or whatever to the server
 | 
					 | 
				
			||||||
and it puts it in the netchan, which seems to be 4000 max big
 | 
					 | 
				
			||||||
and then any other data in there overflows it
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DETOUR_DECL_STATIC4(SV_BroadcastVoiceData, void, IClient *, pClient, int, nBytes, char *, data, int64, xuid)
 | 
					DETOUR_DECL_STATIC4(SV_BroadcastVoiceData, void, IClient *, pClient, int, nBytes, char *, data, int64, xuid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if(g_Interface.OnBroadcastVoiceData(pClient, nBytes, data))
 | 
						if(g_Interface.OnBroadcastVoiceData(pClient, nBytes, data))
 | 
				
			||||||
@ -328,6 +312,12 @@ const sp_nativeinfo_t MyNatives[] =
 | 
				
			|||||||
	{ NULL, NULL }
 | 
						{ NULL, NULL }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ListenSocketAction(void *pData)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						CVoice *pThis = (CVoice *)pData;
 | 
				
			||||||
 | 
						pThis->ListenSocket();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CVoice::SDK_OnAllLoaded()
 | 
					void CVoice::SDK_OnAllLoaded()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	sharesys->AddNatives(myself, MyNatives);
 | 
						sharesys->AddNatives(myself, MyNatives);
 | 
				
			||||||
@ -366,9 +356,19 @@ void CVoice::SDK_OnAllLoaded()
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This doesn't seem to work right away ...
 | 
				
			||||||
	engine->ServerCommand("exec sourcemod/extension.Voice.cfg\n");
 | 
						engine->ServerCommand("exec sourcemod/extension.Voice.cfg\n");
 | 
				
			||||||
	engine->ServerExecute();
 | 
						engine->ServerExecute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ... delay starting listen server to next frame
 | 
				
			||||||
 | 
						smutils->AddFrameAction(ListenSocketAction, this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CVoice::ListenSocket()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if(m_PollFds > 0)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sockaddr_in bindAddr;
 | 
						sockaddr_in bindAddr;
 | 
				
			||||||
	memset(&bindAddr, 0, sizeof(bindAddr));
 | 
						memset(&bindAddr, 0, sizeof(bindAddr));
 | 
				
			||||||
	bindAddr.sin_family = AF_INET;
 | 
						bindAddr.sin_family = AF_INET;
 | 
				
			||||||
@ -439,37 +439,25 @@ void CVoice::OnGameFrame(bool simulating)
 | 
				
			|||||||
	memset(g_aFrameVoiceBytes, 0, sizeof(g_aFrameVoiceBytes));
 | 
						memset(g_aFrameVoiceBytes, 0, sizeof(g_aFrameVoiceBytes));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
bool CVoice::OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data)
 | 
					bool CVoice::OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int client = pClient->GetPlayerSlot() + 1;
 | 
						// Reject empty packets
 | 
				
			||||||
	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(nBytes < 1)
 | 
						if(nBytes < 1)
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		smutils->LogMessage(myself, "%s (%s): Empty voice packet", pPlayer->GetName(), pPlayer->GetSteam2Id(true), data);
 | 
					 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// this is to log all voice packet
 | 
						int client = pClient->GetPlayerSlot() + 1;
 | 
				
			||||||
	if (g_SmVoiceLogging.GetInt())
 | 
					
 | 
				
			||||||
		smutils->LogMessage(myself, "%s (%s): %s", pPlayer->GetName(), pPlayer->GetSteam2Id(true), data);
 | 
						// Reject voice packet if we'd send more than NET_MAX_VOICE_BYTES_FRAME voice bytes from this client in the current frame.
 | 
				
			||||||
 | 
						// 5 = SVC_VoiceData header/overhead
 | 
				
			||||||
 | 
						g_aFrameVoiceBytes[client] += 5 + nBytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(g_aFrameVoiceBytes[client] > NET_MAX_VOICE_BYTES_FRAME)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g_fLastVoiceData[client] = gpGlobals->curtime;
 | 
						g_fLastVoiceData[client] = gpGlobals->curtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Reject voice packet if we'd send more than NET_MAX_VOICE_BYTES_FRAME voice bytes from this client in the current frame.
 | 
					 | 
				
			||||||
	g_aFrameVoiceBytes[client] += nBytes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(g_aFrameVoiceBytes[client] > NET_MAX_VOICE_BYTES_FRAME)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if(g_aFrameVoiceBytes[client] > NET_MAX_VOICE_BYTES_FRAME_LOG)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			smutils->LogMessage(myself, "%s (%s) voice overflow! %d > %d\n", pPlayer->GetName(), pPlayer->GetSteam2Id(true), g_aFrameVoiceBytes[client], NET_MAX_VOICE_BYTES_FRAME);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
 }
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CVoice::HandleNetwork()
 | 
					void CVoice::HandleNetwork()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -503,6 +491,7 @@ void CVoice::HandleNetwork()
 | 
				
			|||||||
			m_aClients[Client].m_LastLength = 0;
 | 
								m_aClients[Client].m_LastLength = 0;
 | 
				
			||||||
			m_aClients[Client].m_LastValidData = 0.0;
 | 
								m_aClients[Client].m_LastValidData = 0.0;
 | 
				
			||||||
			m_aClients[Client].m_New = true;
 | 
								m_aClients[Client].m_New = true;
 | 
				
			||||||
 | 
								m_aClients[Client].m_UnEven = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			m_aPollFds[m_PollFds].fd = Socket;
 | 
								m_aPollFds[m_PollFds].fd = Socket;
 | 
				
			||||||
			m_aPollFds[m_PollFds].events = POLLIN | POLLHUP;
 | 
								m_aPollFds[m_PollFds].events = POLLIN | POLLHUP;
 | 
				
			||||||
@ -560,7 +549,16 @@ void CVoice::HandleNetwork()
 | 
				
			|||||||
		if(min(BytesAvailable, sizeof(aBuf)) > m_Buffer.CurrentFree() * sizeof(int16_t))
 | 
							if(min(BytesAvailable, sizeof(aBuf)) > m_Buffer.CurrentFree() * sizeof(int16_t))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ssize_t Bytes = recv(pClient->m_Socket, aBuf, sizeof(aBuf), 0);
 | 
							// Edge case: previously received data is uneven and last recv'd byte has to be prepended
 | 
				
			||||||
 | 
							int Shift = 0;
 | 
				
			||||||
 | 
							if(pClient->m_UnEven)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Shift = 1;
 | 
				
			||||||
 | 
								aBuf[0] = pClient->m_Remainder;
 | 
				
			||||||
 | 
								pClient->m_UnEven = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ssize_t Bytes = recv(pClient->m_Socket, &aBuf[Shift], sizeof(aBuf) - Shift, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(Bytes <= 0)
 | 
							if(Bytes <= 0)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -568,10 +566,21 @@ void CVoice::HandleNetwork()
 | 
				
			|||||||
			pClient->m_Socket = -1;
 | 
								pClient->m_Socket = -1;
 | 
				
			||||||
			m_aPollFds[PollFds].fd = -1;
 | 
								m_aPollFds[PollFds].fd = -1;
 | 
				
			||||||
			CompressPollFds = true;
 | 
								CompressPollFds = true;
 | 
				
			||||||
			smutils->LogMessage(myself, "Client %d disconnected!(1)\n", Client);
 | 
								//smutils->LogMessage(myself, "Client %d disconnected!(1)\n", Client);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Bytes += Shift;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Edge case: data received is uneven (can't be divided by two)
 | 
				
			||||||
 | 
							// store last byte, drop it here and prepend it right before the next recv
 | 
				
			||||||
 | 
							if(Bytes & 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								pClient->m_UnEven = true;
 | 
				
			||||||
 | 
								pClient->m_Remainder = aBuf[Bytes - 1];
 | 
				
			||||||
 | 
								Bytes -= 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Got data!
 | 
							// Got data!
 | 
				
			||||||
		OnDataReceived(pClient, (int16_t *)aBuf, Bytes / sizeof(int16_t));
 | 
							OnDataReceived(pClient, (int16_t *)aBuf, Bytes / sizeof(int16_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -139,6 +139,8 @@ public:
 | 
				
			|||||||
	void OnGameFrame(bool simulating);
 | 
						void OnGameFrame(bool simulating);
 | 
				
			||||||
	bool OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data);
 | 
						bool OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void ListenSocket();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	int m_ListenSocket;
 | 
						int m_ListenSocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -149,6 +151,8 @@ private:
 | 
				
			|||||||
		size_t m_LastLength;
 | 
							size_t m_LastLength;
 | 
				
			||||||
		double m_LastValidData;
 | 
							double m_LastValidData;
 | 
				
			||||||
		bool m_New;
 | 
							bool m_New;
 | 
				
			||||||
 | 
							bool m_UnEven;
 | 
				
			||||||
 | 
							unsigned char m_Remainder;
 | 
				
			||||||
	} m_aClients[MAX_CLIENTS];
 | 
						} m_aClients[MAX_CLIENTS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pollfd m_aPollFds[1 + MAX_CLIENTS];
 | 
						struct pollfd m_aPollFds[1 + MAX_CLIENTS];
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user