forked from facebookarchive/RakNet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChat Example Server.cpp
More file actions
326 lines (270 loc) · 10.2 KB
/
Copy pathChat Example Server.cpp
File metadata and controls
326 lines (270 loc) · 10.2 KB
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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/*
* 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.
*
*/
// ----------------------------------------------------------------------
// RakNet version 1.0
// Filename ChatExample.cpp
// Very basic chat engine example
// ----------------------------------------------------------------------
#include "MessageIdentifiers.h"
#include "RakPeerInterface.h"
#include "RakNetStatistics.h"
#include "RakNetTypes.h"
#include "BitStream.h"
#include "RakSleep.h"
#include "PacketLogger.h"
#include <assert.h>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include "Kbhit.h"
#include <stdio.h>
#include <string.h>
#include "Gets.h"
#if LIBCAT_SECURITY==1
#include "SecureHandshake.h" // Include header for secure handshake
#endif
#if defined(_CONSOLE_2)
#include "Console2SampleIncludes.h"
#endif
// We copy this from Multiplayer.cpp to keep things all in one file for this example
unsigned char GetPacketIdentifier(RakNet::Packet *p);
#ifdef _CONSOLE_2
_CONSOLE_2_SetSystemProcessParams
#endif
int main(void)
{
// Pointers to the interfaces of our server and client.
// Note we can easily have both in the same program
RakNet::RakPeerInterface *server=RakNet::RakPeerInterface::GetInstance();
RakNet::RakNetStatistics *rss;
server->SetIncomingPassword("Rumpelstiltskin", (int)strlen("Rumpelstiltskin"));
server->SetTimeoutTime(30000,RakNet::UNASSIGNED_SYSTEM_ADDRESS);
// RakNet::PacketLogger packetLogger;
// server->AttachPlugin(&packetLogger);
#if LIBCAT_SECURITY==1
cat::EasyHandshake handshake;
char public_key[cat::EasyHandshake::PUBLIC_KEY_BYTES];
char private_key[cat::EasyHandshake::PRIVATE_KEY_BYTES];
handshake.GenerateServerKey(public_key, private_key);
server->InitializeSecurity(public_key, private_key, false);
FILE *fp = fopen("publicKey.dat","wb");
fwrite(public_key,sizeof(public_key),1,fp);
fclose(fp);
#endif
// Holds packets
RakNet::Packet* p;
// GetPacketIdentifier returns this
unsigned char packetIdentifier;
// Record the first client that connects to us so we can pass it to the ping function
RakNet::SystemAddress clientID=RakNet::UNASSIGNED_SYSTEM_ADDRESS;
// Holds user data
char portstring[30];
printf("This is a sample implementation of a text based chat server.\n");
printf("Connect to the project 'Chat Example Client'.\n");
printf("Difficulty: Beginner\n\n");
// A server
puts("Enter the server port to listen on");
Gets(portstring,sizeof(portstring));
if (portstring[0]==0)
strcpy(portstring, "1234");
puts("Starting server.");
// Starting the server is very simple. 2 players allowed.
// 0 means we don't care about a connectionValidationInteger, and false
// for low priority threads
// I am creating two socketDesciptors, to create two sockets. One using IPV6 and the other IPV4
RakNet::SocketDescriptor socketDescriptors[2];
socketDescriptors[0].port=atoi(portstring);
socketDescriptors[0].socketFamily=AF_INET; // Test out IPV4
socketDescriptors[1].port=atoi(portstring);
socketDescriptors[1].socketFamily=AF_INET6; // Test out IPV6
bool b = server->Startup(4, socketDescriptors, 2 )==RakNet::RAKNET_STARTED;
server->SetMaximumIncomingConnections(4);
if (!b)
{
printf("Failed to start dual IPV4 and IPV6 ports. Trying IPV4 only.\n");
// Try again, but leave out IPV6
b = server->Startup(4, socketDescriptors, 1 )==RakNet::RAKNET_STARTED;
if (!b)
{
puts("Server failed to start. Terminating.");
exit(1);
}
}
server->SetOccasionalPing(true);
server->SetUnreliableTimeout(1000);
DataStructures::List< RakNet::RakNetSocket2* > sockets;
server->GetSockets(sockets);
printf("Socket addresses used by RakNet:\n");
for (unsigned int i=0; i < sockets.Size(); i++)
{
printf("%i. %s\n", i+1, sockets[i]->GetBoundAddress().ToString(true));
}
printf("\nMy IP addresses:\n");
for (unsigned int i=0; i < server->GetNumberOfAddresses(); i++)
{
RakNet::SystemAddress sa = server->GetInternalID(RakNet::UNASSIGNED_SYSTEM_ADDRESS, i);
printf("%i. %s (LAN=%i)\n", i+1, sa.ToString(false), sa.IsLANAddress());
}
printf("\nMy GUID is %s\n", server->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString());
puts("'quit' to quit. 'stat' to show stats. 'ping' to ping.\n'pingip' to ping an ip address\n'ban' to ban an IP from connecting.\n'kick to kick the first connected player.\nType to talk.");
char message[2048];
// Loop for input
while (1)
{
// This sleep keeps RakNet responsive
RakSleep(30);
if (kbhit())
{
// Notice what is not here: something to keep our network running. It's
// fine to block on gets or anything we want
// Because the network engine was painstakingly written using threads.
Gets(message,sizeof(message));
if (strcmp(message, "quit")==0)
{
puts("Quitting.");
break;
}
if (strcmp(message, "stat")==0)
{
rss=server->GetStatistics(server->GetSystemAddressFromIndex(0));
StatisticsToString(rss, message, 2);
printf("%s", message);
printf("Ping %i\n", server->GetAveragePing(server->GetSystemAddressFromIndex(0)));
continue;
}
if (strcmp(message, "ping")==0)
{
server->Ping(clientID);
continue;
}
if (strcmp(message, "pingip")==0)
{
printf("Enter IP: ");
Gets(message,sizeof(message));
printf("Enter port: ");
Gets(portstring,sizeof(portstring));
if (portstring[0]==0)
strcpy(portstring, "1234");
server->Ping(message, atoi(portstring), false);
continue;
}
if (strcmp(message, "kick")==0)
{
server->CloseConnection(clientID, true, 0);
continue;
}
if (strcmp(message, "getconnectionlist")==0)
{
RakNet::SystemAddress systems[10];
unsigned short numConnections=10;
server->GetConnectionList((RakNet::SystemAddress*) &systems, &numConnections);
for (int i=0; i < numConnections; i++)
{
printf("%i. %s\n", i+1, systems[i].ToString(true));
}
continue;
}
if (strcmp(message, "ban")==0)
{
printf("Enter IP to ban. You can use * as a wildcard\n");
Gets(message,sizeof(message));
server->AddToBanList(message);
printf("IP %s added to ban list.\n", message);
continue;
}
// Message now holds what we want to broadcast
char message2[2048];
// Append Server: to the message so clients know that it ORIGINATED from the server
// All messages to all clients come from the server either directly or by being
// relayed from other clients
message2[0]=0;
const static char prefix[] = "Server: ";
strncpy(message2, prefix, sizeof(message2));
strncat(message2, message, sizeof(message2) - strlen(prefix) - 1);
// message2 is the data to send
// strlen(message2)+1 is to send the null terminator
// HIGH_PRIORITY doesn't actually matter here because we don't use any other priority
// RELIABLE_ORDERED means make sure the message arrives in the right order
// We arbitrarily pick 0 for the ordering stream
// RakNet::UNASSIGNED_SYSTEM_ADDRESS means don't exclude anyone from the broadcast
// true means broadcast the message to everyone connected
server->Send(message2, (const int) strlen(message2)+1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true);
}
// Get a packet from either the server or the client
for (p=server->Receive(); p; server->DeallocatePacket(p), p=server->Receive())
{
// We got a packet, get the identifier with our handy function
packetIdentifier = GetPacketIdentifier(p);
// Check if this is a network message packet
switch (packetIdentifier)
{
case ID_DISCONNECTION_NOTIFICATION:
// Connection lost normally
printf("ID_DISCONNECTION_NOTIFICATION from %s\n", p->systemAddress.ToString(true));;
break;
case ID_NEW_INCOMING_CONNECTION:
// Somebody connected. We have their IP now
printf("ID_NEW_INCOMING_CONNECTION from %s with GUID %s\n", p->systemAddress.ToString(true), p->guid.ToString());
clientID=p->systemAddress; // Record the player ID of the client
printf("Remote internal IDs:\n");
for (int index=0; index < MAXIMUM_NUMBER_OF_INTERNAL_IDS; index++)
{
RakNet::SystemAddress internalId = server->GetInternalID(p->systemAddress, index);
if (internalId!=RakNet::UNASSIGNED_SYSTEM_ADDRESS)
{
printf("%i. %s\n", index+1, internalId.ToString(true));
}
}
break;
case ID_INCOMPATIBLE_PROTOCOL_VERSION:
printf("ID_INCOMPATIBLE_PROTOCOL_VERSION\n");
break;
case ID_CONNECTED_PING:
case ID_UNCONNECTED_PING:
printf("Ping from %s\n", p->systemAddress.ToString(true));
break;
case ID_CONNECTION_LOST:
// Couldn't deliver a reliable packet - i.e. the other system was abnormally
// terminated
printf("ID_CONNECTION_LOST from %s\n", p->systemAddress.ToString(true));;
break;
default:
// The server knows the static data of all clients, so we can prefix the message
// With the name data
printf("%s\n", p->data);
// Relay the message. We prefix the name for other clients. This demonstrates
// That messages can be changed on the server before being broadcast
// Sending is the same as before
sprintf(message, "%s", p->data);
server->Send(message, (const int) strlen(message)+1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, p->systemAddress, true);
break;
}
}
}
server->Shutdown(300);
// We're done with the network
RakNet::RakPeerInterface::DestroyInstance(server);
return 0;
}
// Copied from Multiplayer.cpp
// If the first byte is ID_TIMESTAMP, then we want the 5th byte
// Otherwise we want the 1st byte
unsigned char GetPacketIdentifier(RakNet::Packet *p)
{
if (p==0)
return 255;
if ((unsigned char)p->data[0] == ID_TIMESTAMP)
{
RakAssert(p->length > sizeof(RakNet::MessageID) + sizeof(RakNet::Time));
return (unsigned char) p->data[sizeof(RakNet::MessageID) + sizeof(RakNet::Time)];
}
else
return (unsigned char) p->data[0];
}