1 /// \file
2 /// \brief Contains code to call sqlite3_exec over a network that does not support shared file handles.
3 ///
4 /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
5 ///
6 /// Raknet is available under the terms of the GPLv3 license, see /usr/local/share/licenses/raknet-3.9.2_10,1/GPLv3.
7 
8 
9 #ifndef ___SQLITE_3_SERVER_PLUGIN_H
10 #define ___SQLITE_3_SERVER_PLUGIN_H
11 
12 /// \brief Control if SQLite3 statements execute in a thread
13 /// \details sqlite3_exec is blocking and will therefore block other operations in the same program<BR>
14 /// If defined, sqlite3_exec executes in a thread so that doesn't happen<BR>
15 /// If the only thing this system is doing is running SQLite, then you'll get marginally better performance by commenting it out.
16 /// \ingroup SQL_LITE_3_PLUGIN
17 #define SQLite3_STATEMENT_EXECUTE_THREADED
18 
19 #include "RakNetTypes.h"
20 #include "Export.h"
21 #include "PluginInterface2.h"
22 #include "PacketPriority.h"
23 #include "SocketIncludes.h"
24 #include "DS_Multilist.h"
25 #include "RakString.h"
26 #include "sqlite3.h"
27 #include "SQLite3PluginCommon.h"
28 
29 #ifdef SQLite3_STATEMENT_EXECUTE_THREADED
30 #include "ThreadPool.h"
31 #endif
32 
33 class RakPeerInterface;
34 
35 namespace RakNet
36 {
37 
38 /// \brief Exec SQLLite commands over the network
39 /// \details SQLite version 3 supports remote calls via networked file handles, but not over the regular internet<BR>
40 /// This plugin will serialize calls to and results from sqlite3_exec<BR>
41 /// That's all it does - any remote system can execute SQL queries.<BR>
42 /// Intended as a starting platform to derive from for more advanced functionality (security over who can query, etc).<BR>
43 /// Compatible as a plugin with both RakPeerInterface and PacketizedTCP
44 /// \ingroup SQL_LITE_3_PLUGIN
45 class RAK_DLL_EXPORT SQLite3ServerPlugin : public PluginInterface2
46 {
47 public:
48 	SQLite3ServerPlugin();
49 	virtual ~SQLite3ServerPlugin();
50 
51 	/// Associate identifier with dbHandle, so when we get calls to operate on identifier, we use dbhandle
52 	/// If SQLite3_STATEMENT_EXECUTE_THREADED is defined, will start the execution thread the first time a dbHandle is added.
53 	/// \return true on success, false on dbIdentifier empty, or already in use
54 	virtual bool AddDBHandle(RakNet::RakString dbIdentifier, sqlite3 *dbHandle, bool dbAutoCreated=false);
55 
56 	/// Stop using a dbHandle, lookup either by identifier or by pointer.
57 	/// If SQLite3_STATEMENT_EXECUTE_THREADED is defined, do not call this while processing commands, since the commands run in a thread and might be using the dbHandle
58 	/// Call before closing the handle or else SQLite3Plugin won't know that it was closed, and will continue using it
59 	void RemoveDBHandle(RakNet::RakString dbIdentifier, bool alsoCloseConnection=false);
60 	void RemoveDBHandle(sqlite3 *dbHandle, bool alsoCloseConnection=false);
61 
62 	/// \internal For plugin handling
63 	virtual PluginReceiveResult OnReceive(Packet *packet);
64 	virtual void OnAttach(void);
65 	virtual void OnDetach(void);
66 
67 	/// \internal
68 	struct NamedDBHandle
69 	{
70 		RakNet::RakString dbIdentifier;
71 		sqlite3 *dbHandle;
72 		bool dbAutoCreated;
73 		RakNetTimeMS whenCreated;
74 	};
75 
76 #ifdef SQLite3_STATEMENT_EXECUTE_THREADED
77 	virtual void Update(void);
78 	/// \internal
79 	struct SQLExecThreadInput
80 	{
SQLExecThreadInputSQLExecThreadInput81 		SQLExecThreadInput() {data=0; packet=0;}
82 		char *data;
83 		unsigned int length;
84 		SystemAddress sender;
85 		RakNetTimeMS whenMessageArrived;
86 		sqlite3 *dbHandle;
87 		Packet *packet;
88 	};
89 
90 	/// \internal
91 	struct SQLExecThreadOutput
92 	{
SQLExecThreadOutputSQLExecThreadOutput93 		SQLExecThreadOutput() {data=0; packet=0;}
94 		char *data;
95 		unsigned int length;
96 		SystemAddress sender;
97 		Packet *packet;
98 	};
99 #endif // SQLite3_STATEMENT_EXECUTE_THREADED
100 
101 protected:
102 	virtual void StopThreads(void);
103 
104 	// List of databases added with AddDBHandle()
105 	DataStructures::Multilist<ML_ORDERED_LIST, NamedDBHandle, RakNet::RakString> dbHandles;
106 
107 #ifdef SQLite3_STATEMENT_EXECUTE_THREADED
108 	// The point of the sqlThreadPool is so that SQL queries, which are blocking, happen in the thread and don't slow down the rest of the application
109 	// The sqlThreadPool has a queue for incoming processing requests.  As systems disconnect their pending requests are removed from the list.
110 	ThreadPool<SQLExecThreadInput, SQLExecThreadOutput> sqlThreadPool;
111 #endif
112 };
113 
114 };
115 
116 extern bool operator<( const DataStructures::MLKeyRef<RakNet::RakString> &inputKey, const RakNet::SQLite3ServerPlugin::NamedDBHandle &cls );
117 extern bool operator>( const DataStructures::MLKeyRef<RakNet::RakString> &inputKey, const RakNet::SQLite3ServerPlugin::NamedDBHandle &cls );
118 extern bool operator==( const DataStructures::MLKeyRef<RakNet::RakString> &inputKey, const RakNet::SQLite3ServerPlugin::NamedDBHandle &cls );
119 
120 #endif
121