summaryrefslogtreecommitdiff
path: root/public/gcsdk/gcsession.h
blob: e2ff636654b938421189e80dc3ec7865cacce4eb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CGCSession class
//
//=============================================================================

#ifndef GCSESSION_H
#define GCSESSION_H
#ifdef _WIN32
#pragma once
#endif

#include "scheduledfunction.h"
#include "framefunction.h"
#include "gcsdk/gc_sharedobjectcache.h"

namespace GCSDK
{

class CGCGSSession;

// Spew group for anything related to sessions
extern CGCEmitGroup g_EGSessions;

//-----------------------------------------------------------------------------
// Utility class to handle rate limiting based upon a steam ID and message using two console variables to control rate
//-----------------------------------------------------------------------------

//utility class to handle rate limiting based upon a steam ID
class CSteamIDRateLimit
{
public:
	CSteamIDRateLimit( const GCConVar& cvNumPerPeriod, const GCConVar* pcvPeriodS = NULL );
	~CSteamIDRateLimit();
	//given a steam ID, this will determine if it should be rate limited
	bool BIsRateLimited( CSteamID steamID, uint32 unMsgType );
	//frame function to clear the list after a period of time
	bool OnFrameFn( const CLimitTimer& timer );
private:
	//the last time we cleared our list
	RTime32									m_LastClear;
	//the frame function so we can detect when we need to clear
	CFrameFunction< CSteamIDRateLimit>		m_FrameFunction;
	//the map of messages we have tracked for each user
	CUtlHashMapLarge< CSteamID, uint32 >	m_Msgs;
	//the console variables that track the time window and the messages allowed
	const GCConVar&							m_cvNumPerPeriod;
	const GCConVar*							m_pcvPeriodS;
};

//------------------------------------------------------------------------------------------
// CMsgRateLimitTracker
//   A utility class to track when messages go over so that we can see users/msgs that are being spammed
//------------------------------------------------------------------------------------------
class CMsgRateLimitTracker
{
public:

	CMsgRateLimitTracker();

	//called to track a message that was rate limited
	void TrackRateLimitedMsg( const CSteamID steamID, MsgType_t eMsgType );

	//called to report the collected rate limiting stats
	void ReportMsgStats() const;
	void ReportTopUsers( uint32 nMinMsgs, uint32 nListTop ) const;
	void ReportUserStats() const;

	//called to clear all collected stats
	void ClearStats();

private:

	//the time we started collecting stats at
	RTime32		m_StartTime;

	//map detailing the number of messages of each type that have been dropped
	CUtlHashMapLarge< MsgType_t, uint32 >		m_MsgStats;
	CUtlHashMapLarge< CSteamID, uint32 >		m_UserStats;
};
extern CMsgRateLimitTracker g_RateLimitTracker;

//-----------------------------------------------------------------------------
// Purpose: Base class for sessions in the GC
//-----------------------------------------------------------------------------
class CGCSession
{
public:
	CGCSession( const CSteamID & steamID, CGCSharedObjectCache *pCache );
	virtual ~CGCSession();

	const CSteamID & GetSteamID() const { return m_steamID; }

	const CGCSharedObjectCache *GetSOCache() const { return m_pSOCache; }
	CGCSharedObjectCache *GetSOCache() { return m_pSOCache; }
	void RemoveSOCache() { m_pSOCache = NULL; }

	EOSType GetOSType() const { return m_osType; };
	bool IsTestSession() const { return m_bIsTestSession; }
	uint32 GetIPPublic() const { return m_unIPPublic; }
	bool IsSecure() const { return m_bIsSecure; }

	bool BIsShuttingDown() const { return m_bIsShuttingDown; }
	void SetIsShuttingDown( bool bIsShuttingDown ) { m_bIsShuttingDown = bIsShuttingDown; }

	virtual void Dump( bool bFull = true ) const = 0;

	bool BRateLimitMessage( MsgType_t unMsgType );

	CJobTime GetLastPingSendTime() const { return m_jtTimeSentPing; }
	CJobTime GetLastMessageReceiveTime() const { return m_jtLastMessageReceived; }
	void SendPing() const;

	virtual void MarkAccess() { }
	virtual void Run();
	virtual void YieldingSOCacheReloaded() {}
#ifdef DBGFLAG_VALIDATE
	virtual void Validate( CValidator &validator, const char *pchName );
#endif // DBGFLAG_VALIDATE

	// Geolocation
	bool HasGeoLocation() const { return m_haveGeoLocation; }
	bool GetGeoLocation( float &latitude, float &longittude ) const;
	virtual void SetGeoLocation( float latitude, float longittude );

	//track whether or not this session has been initialized or not
	bool	BIsInitialized() const			{ return m_bInitialized; }
	void	SetInitialized( bool b )		{ m_bInitialized = b; }

private:
	CSteamID m_steamID;
	CGCSharedObjectCache *m_pSOCache;

	// Tracks how many messages we've gotten this second so we can block attacks
	RTime32 m_rtLastMessageReceived;
	uint32 m_unMessagesRecievedThisSecond;
	CJobTime m_jtLastMessageReceived;

	// This is mutable because we update it when we send pings, but sending a
	// ping to a user/server isn't really a session changing event, so we don't
	// want to require locking the session to ping it and update its last
	// sent ping time.
	mutable CJobTime m_jtTimeSentPing;

	EOSType m_osType : 16;
	bool m_bIsShuttingDown : 1;
	bool m_bIsTestSession : 1;
	bool m_bIsSecure : 1;
	bool m_bInitialized : 1;
protected:
	bool m_haveGeoLocation : 1;

	float m_flLatitude;
	float m_flLongitude;

	uint32 m_unIPPublic;

	friend class CGCBase;
};


//-----------------------------------------------------------------------------
// Purpose: Base class for user sessions in the GC
//-----------------------------------------------------------------------------
class CGCUserSession : public CGCSession
{
public:
	CGCUserSession( const CSteamID & steamID, CGCSharedObjectCache *pCache ) : CGCSession( steamID, pCache ) { }
	virtual ~CGCUserSession();

	virtual bool BInit();

	const CSteamID &GetSteamIDGS() const { return m_steamIDGS; }
	const CSteamID &GetSteamIDGSPrev() const { return m_steamIDGSPrev; }

	virtual bool BSetServer( const CSteamID &steamIDGS );
	virtual bool BLeaveServer();
	virtual void Dump( bool bFull = true ) const;

private:
	CSteamID m_steamIDGS;
	CSteamID m_steamIDGSPrev;
};


//-----------------------------------------------------------------------------
// Purpose: Base class for gameserver sessions in the GC
//-----------------------------------------------------------------------------
class CGCGSSession : public CGCSession
{
public:

	CGCGSSession( const CSteamID & steamID, CGCSharedObjectCache *pCache, uint32 unServerAddr, uint16 usServerPort ) ;
	virtual ~CGCGSSession();

	uint32 GetAddr() const { return m_unServerAddr; }
	uint16 GetPort() const { return m_usServerPort; }
	void SetIPAndPort( uint32 unServerAddr, uint16 usServerPort );
	int GetUserCount() const { return m_vecUsers.Count(); }
	CSteamID GetUserID( int nIndex ) const { return m_vecUsers[nIndex]; }

	// Manages users on the server. It is very important that these are not
	// virtual and not yielding. For custom behavior override the Pre*() hooks below
	bool BAddUser( const CSteamID &steamIDUser );
	bool BRemoveUser( const CSteamID &steamIDUser );
	void RemoveAllUsers();

	virtual void Dump( bool bFull = true ) const;

protected:
	// Hooks to trigger custom behavior when users are added and removed. It is
	// very important that these do not yield. If you need to yield, start a job instead
	virtual void PreAddUser( const CSteamID &steamIDUser ) {}
	virtual void PostAddUser( const CSteamID &steamIDUser ) {}
	virtual void PreRemoveUser( const CSteamID &steamIDUser ) {}
	virtual void PostRemoveUser( const CSteamID &steamIDUser ) {}
	virtual void PreRemoveAllUsers() {}
	virtual void PostRemoveAllUsers() {}

public:
	float m_lastUpdateTime; // Last time we received a message from the server

#ifdef DBGFLAG_VALIDATE
	virtual void Validate( CValidator &validator, const char *pchName );
#endif // DBGFLAG_VALIDATE
protected:
	CUtlVector<CSteamID> m_vecUsers;

	// These are the address of the server as connected to Steam
	uint32 m_unServerAddr;
	uint16 m_usServerPort;
};

} // namespace GCSDK

#endif // GCSESSION_H