forked from facebookarchive/RakNet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTCPInterface.h
263 lines (209 loc) · 9.09 KB
/
TCPInterface.h
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
/// \file
/// \brief A simple TCP based server allowing sends and receives. Can be connected by any TCP client, including telnet.
///
#include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_TCPInterface==1
#ifndef __SIMPLE_TCP_SERVER
#define __SIMPLE_TCP_SERVER
#include "RakMemoryOverride.h"
#include "DS_List.h"
#include "RakNetTypes.h"
#include "Export.h"
#include "RakThread.h"
#include "DS_Queue.h"
#include "SimpleMutex.h"
#include "RakNetDefines.h"
#include "SocketIncludes.h"
#include "DS_ByteQueue.h"
#include "DS_ThreadsafeAllocatingQueue.h"
#include "LocklessTypes.h"
#include "PluginInterface2.h"
#if OPEN_SSL_CLIENT_SUPPORT==1
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif
namespace RakNet
{
/// Forward declarations
struct RemoteClient;
/// \internal
/// \brief As the name says, a simple multithreaded TCP server. Used by TelnetTransport
class RAK_DLL_EXPORT TCPInterface
{
public:
// GetInstance() and DestroyInstance(instance*)
STATIC_FACTORY_DECLARATIONS(TCPInterface)
TCPInterface();
virtual ~TCPInterface();
// TODO - add socketdescriptor
/// Starts the TCP server on the indicated port
/// \param[in] port Which port to listen on.
/// \param[in] maxIncomingConnections Max incoming connections we will accept
/// \param[in] maxConnections Max total connections, which should be >= maxIncomingConnections
/// \param[in] threadPriority Passed to the thread creation routine. Use THREAD_PRIORITY_NORMAL for Windows. For Linux based systems, you MUST pass something reasonable based on the thread priorities for your application.
/// \param[in] socketFamily IP version: For IPV4, use AF_INET (default). For IPV6, use AF_INET6. To autoselect, use AF_UNSPEC.
bool Start(unsigned short port, unsigned short maxIncomingConnections, unsigned short maxConnections=0, int _threadPriority=-99999, unsigned short socketFamily=AF_INET, const char *bindAddress=0);
/// Stops the TCP server
void Stop(void);
/// Connect to the specified host on the specified port
SystemAddress Connect(const char* host, unsigned short remotePort, bool block=true, unsigned short socketFamily=AF_INET, const char *bindAddress=0);
#if OPEN_SSL_CLIENT_SUPPORT==1
/// Start SSL on an existing connection, notified with HasCompletedConnectionAttempt
void StartSSLClient(SystemAddress systemAddress);
/// Was SSL started on this socket?
bool IsSSLActive(SystemAddress systemAddress);
#endif
/// Sends a byte stream
virtual void Send( const char *data, unsigned int length, const SystemAddress &systemAddress, bool broadcast );
// Sends a concatenated list of byte streams
virtual bool SendList( const char **data, const unsigned int *lengths, const int numParameters, const SystemAddress &systemAddress, bool broadcast );
// Get how many bytes are waiting to be sent. If too many, you may want to skip sending
unsigned int GetOutgoingDataBufferSize(SystemAddress systemAddress) const;
/// Returns if Receive() will return data
/// Do not use on PacketizedTCP
virtual bool ReceiveHasPackets( void );
/// Returns data received
virtual Packet* Receive( void );
/// Disconnects a player/address
void CloseConnection( SystemAddress systemAddress );
/// Deallocates a packet returned by Receive
void DeallocatePacket( Packet *packet );
/// Fills the array remoteSystems with the SystemAddress of all the systems we are connected to
/// \param[out] remoteSystems An array of SystemAddress structures to be filled with the SystemAddresss of the systems we are connected to. Pass 0 to remoteSystems to only get the number of systems we are connected to
/// \param[in, out] numberOfSystems As input, the size of remoteSystems array. As output, the number of elements put into the array
void GetConnectionList( SystemAddress *remoteSystems, unsigned short *numberOfSystems ) const;
/// Returns just the number of connections we have
unsigned short GetConnectionCount(void) const;
/// Has a previous call to connect succeeded?
/// \return UNASSIGNED_SYSTEM_ADDRESS = no. Anything else means yes.
SystemAddress HasCompletedConnectionAttempt(void);
/// Has a previous call to connect failed?
/// \return UNASSIGNED_SYSTEM_ADDRESS = no. Anything else means yes.
SystemAddress HasFailedConnectionAttempt(void);
/// Queued events of new incoming connections
SystemAddress HasNewIncomingConnection(void);
/// Queued events of lost connections
SystemAddress HasLostConnection(void);
/// Return an allocated but empty packet, for custom use
Packet* AllocatePacket(unsigned dataSize);
// Push a packet back to the queue
virtual void PushBackPacket( Packet *packet, bool pushAtHead );
/// Returns if Start() was called successfully
bool WasStarted(void) const;
void AttachPlugin( PluginInterface2 *plugin );
void DetachPlugin( PluginInterface2 *plugin );
protected:
Packet* ReceiveInt( void );
#if defined(WINDOWS_STORE_RT)
bool CreateListenSocket_WinStore8(unsigned short port, unsigned short maxIncomingConnections, unsigned short socketFamily, const char *hostAddress);
#else
bool CreateListenSocket(unsigned short port, unsigned short maxIncomingConnections, unsigned short socketFamily, const char *hostAddress);
#endif
// Plugins
DataStructures::List<PluginInterface2*> messageHandlerList;
RakNet::LocklessUint32_t isStarted, threadRunning;
__TCPSOCKET__ listenSocket;
DataStructures::Queue<Packet*> headPush, tailPush;
RemoteClient* remoteClients;
int remoteClientsLength;
// Assuming remoteClients is only used by one thread!
// DataStructures::List<RemoteClient*> remoteClients;
// Use this thread-safe queue to add to remoteClients
// DataStructures::Queue<RemoteClient*> remoteClientsInsertionQueue;
// SimpleMutex remoteClientsInsertionQueueMutex;
/*
struct OutgoingMessage
{
unsigned char* data;
SystemAddress systemAddress;
bool broadcast;
unsigned int length;
};
*/
// DataStructures::SingleProducerConsumer<OutgoingMessage> outgoingMessages;
// DataStructures::SingleProducerConsumer<Packet> incomingMessages;
// DataStructures::SingleProducerConsumer<SystemAddress> newIncomingConnections, lostConnections, requestedCloseConnections;
// DataStructures::SingleProducerConsumer<RemoteClient*> newRemoteClients;
// DataStructures::ThreadsafeAllocatingQueue<OutgoingMessage> outgoingMessages;
DataStructures::ThreadsafeAllocatingQueue<Packet> incomingMessages;
DataStructures::ThreadsafeAllocatingQueue<SystemAddress> newIncomingConnections, lostConnections, requestedCloseConnections;
DataStructures::ThreadsafeAllocatingQueue<RemoteClient*> newRemoteClients;
SimpleMutex completedConnectionAttemptMutex, failedConnectionAttemptMutex;
DataStructures::Queue<SystemAddress> completedConnectionAttempts, failedConnectionAttempts;
int threadPriority;
DataStructures::List<__TCPSOCKET__> blockingSocketList;
SimpleMutex blockingSocketListMutex;
friend RAK_THREAD_DECLARATION(UpdateTCPInterfaceLoop);
friend RAK_THREAD_DECLARATION(ConnectionAttemptLoop);
// void DeleteRemoteClient(RemoteClient *remoteClient, fd_set *exceptionFD);
// void InsertRemoteClient(RemoteClient* remoteClient);
__TCPSOCKET__ SocketConnect(const char* host, unsigned short remotePort, unsigned short socketFamily, const char *bindAddress);
struct ThisPtrPlusSysAddr
{
TCPInterface *tcpInterface;
SystemAddress systemAddress;
bool useSSL;
char bindAddress[64];
unsigned short socketFamily;
};
#if OPEN_SSL_CLIENT_SUPPORT==1
SSL_CTX* ctx;
SSL_METHOD *meth;
DataStructures::ThreadsafeAllocatingQueue<SystemAddress> startSSL;
DataStructures::List<SystemAddress> activeSSLConnections;
SimpleMutex sharedSslMutex;
#endif
};
/// Stores information about a remote client.
struct RemoteClient
{
RemoteClient() {
#if OPEN_SSL_CLIENT_SUPPORT==1
ssl=0;
#endif
isActive=false;
#if !defined(WINDOWS_STORE_RT)
socket=0;
#endif
}
__TCPSOCKET__ socket;
SystemAddress systemAddress;
DataStructures::ByteQueue outgoingData;
bool isActive;
SimpleMutex outgoingDataMutex;
SimpleMutex isActiveMutex;
#if OPEN_SSL_CLIENT_SUPPORT==1
SSL* ssl;
bool InitSSL(SSL_CTX* ctx, SSL_METHOD *meth);
void DisconnectSSL(void);
void FreeSSL(void);
int Send(const char *data, unsigned int length);
int Recv(char *data, const int dataSize);
#else
int Send(const char *data, unsigned int length);
int Recv(char *data, const int dataSize);
#endif
void Reset(void)
{
outgoingDataMutex.Lock();
outgoingData.Clear(_FILE_AND_LINE_);
outgoingDataMutex.Unlock();
}
void SetActive(bool a);
void SendOrBuffer(const char **data, const unsigned int *lengths, const int numParameters);
};
} // namespace RakNet
#endif
#endif // _RAKNET_SUPPORT_*