-
-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathDipProtocol.h
353 lines (303 loc) · 10.4 KB
/
DipProtocol.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
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
//==============================================================================
//
// DipProtocol.h
//
// Copyright (C) 2019-2022 Greg Utas
//
// Diplomacy AI Client - Part of the DAIDE project (www.daide.org.uk).
//
// This file is part of the Robust Services Core (RSC).
//
// RSC is free software: you can redistribute it and/or modify it under the
// terms of the Lesser GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// RSC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the Lesser GNU General Public License
// along with RSC. If not, see <http://www.gnu.org/licenses/>.
//
#ifndef DIPPROTOCOL_H_INCLUDED
#define DIPPROTOCOL_H_INCLUDED
#include "InputHandler.h"
#include "IpBuffer.h"
#include "ObjectPool.h"
#include "TcpIpService.h"
#include <cstddef>
#include <cstdint>
#include <iosfwd>
#include "DipTypes.h"
#include "NbTypes.h"
#include "NwTypes.h"
#include "SysTypes.h"
using namespace NodeBase;
using namespace NetworkBase;
//------------------------------------------------------------------------------
namespace Diplomacy
{
// Header for all client-server messages.
//
enum MsgType : uint8_t
{
IM_MESSAGE, // Initial Message
RM_MESSAGE, // Representation Message
DM_MESSAGE, // Diplomacy Message
FM_MESSAGE, // Final Message
EM_MESSAGE, // Error Message
BM_MESSAGE // Bot Message
};
struct DipHeader
{
MsgType signal; // type of message
uint8_t spare; // ignored except in BM_MESSAGE (see below)
uint16_t length; // number of bytes of data that follow
// Displays the header in STREAM.
//
void Display(std::ostream& stream) const;
};
constexpr uint16_t DipHeaderSize = sizeof(DipHeader);
struct DipMessage
{
DipHeader header;
byte_t first_payload_byte; // for creating a pointer to the first byte
// Displays the message in STREAM.
//
void Display(std::ostream& stream) const;
};
//------------------------------------------------------------------------------
//
// The client sends an IM message to the server as soon as the connection
// is open. It is only sent once.
//
struct IM_Message
{
DipHeader header;
uint16_t version; // protocol version number
uint16_t magic_number; // to verify that client is using this protocol
// Displays the message in STREAM.
//
void Display(std::ostream& stream) const;
};
//------------------------------------------------------------------------------
//
// The server sends an RM message to the client immediately after it receives
// the IM. If the length is zero, then the powers and provinces are those on
// the standard map.
//
struct TokenName
{
token_t token; // power or province token
const char name[4]; // 3-letter null-terminated name (A-Z and 0-9 only)
};
struct RM_Message
{
const DipHeader header;
TokenName pairs[POWER_MAX + PROVINCE_MAX]; // power & province names
// Displays the message in STREAM.
//
void Display(std::ostream& stream) const;
};
//------------------------------------------------------------------------------
//
// All other messages between client and server, except for the last one,
// are DM messages. These messages contain tokens defined by the Diplomacy
// language (see Token.h). The message's raw length is always a multiple
// of 2, which corresponds to twice the number of tokens in the message.
//
struct DM_Message
{
DipHeader header;
token_t tokens[UINT16_MAX >> 1]; // from 0 to (header_.length_ >> 1) - 1
// Displays the message in STREAM.
//
void Display(std::ostream& stream) const;
};
//------------------------------------------------------------------------------
//
// The client or server sends an FM message immediately before closing the
// connection. The recipient then closes the connection without sending any
// further message.
//
struct FM_Message
{
DipHeader header; // no parameters (length = 0)
// Displays the message in STREAM.
//
void Display(std::ostream& stream) const;
};
//------------------------------------------------------------------------------
//
// The client or server sends an EM message immediately before closing the
// connection because of an error. The recipient then closes the connection
// without sending any further message. The only ProtocolError that BaseBot
// sends is GRACEFUL_CLOSE; it doesn't disconnect if the server violates the
// protocol.
//
typedef uint16_t ProtocolError;
constexpr ProtocolError GRACEFUL_CLOSE = 0x00;
constexpr ProtocolError IM_TIMEOUT = 0x01;
constexpr ProtocolError IM_EXPECTED = 0x02;
constexpr ProtocolError IM_WRONG_ENDIAN = 0x03;
constexpr ProtocolError IM_WRONG_MAGIC_NUMBER = 0x04;
constexpr ProtocolError IM_INCOMPATIBLE_VERSION = 0x05;
constexpr ProtocolError IM_REPEATED = 0x06;
constexpr ProtocolError IM_FROM_SERVER = 0x07;
constexpr ProtocolError INVALID_MESSAGE_TYPE = 0x08;
constexpr ProtocolError MESSAGE_TOO_SHORT = 0x09;
constexpr ProtocolError DM_BEFORE_RM = 0x0A;
constexpr ProtocolError RM_EXPECTED = 0x0B;
constexpr ProtocolError RM_REPEATED = 0x0C;
constexpr ProtocolError RM_FROM_CLIENT = 0x0D;
constexpr ProtocolError DM_INVALID_TOKEN = 0x0E;
constexpr ProtocolError SERVER_OFF = 0x20; // OFF message from server
constexpr ProtocolError SOCKET_FAILED = 0x21; // for internal use
struct EM_Message
{
DipHeader header;
ProtocolError error;
// Displays the message in STREAM.
//
void Display(std::ostream& stream) const;
};
//------------------------------------------------------------------------------
//
// This message is used to receive internal events. Anything that follows
// the header is bot-specific, and header.spare is used to specify the event
// that distinguishes various types of BM_Message.
//
constexpr BotEvent SOCKET_FAILURE_EVENT = 0;
constexpr BotEvent RECONNECT_EVENT = 1;
constexpr BotEvent FIRST_BOT_BM_EVENT = 2; // start of subclass events
struct BM_Message
{
DipHeader header;
byte_t first_payload_byte; // for creating a pointer to the first byte
// Displays the message in STREAM.
//
void Display(std::ostream& stream) const;
};
//------------------------------------------------------------------------------
//
// Diplomacy protocol over TCP.
//
class BotTcpService : public TcpIpService
{
friend class Singleton<BotTcpService>;
// Private because this is a singleton.
//
BotTcpService();
// Private because this is a singleton.
//
~BotTcpService() = default;
// Overridden to return the service's attributes.
//
c_string Name() const override { return "Diplomacy"; }
ipport_t Port() const override { return ClientIpPort; }
Faction GetFaction() const override { return PayloadFaction; }
bool Enabled() const override { return true; }
bool AcceptsConns() const override { return false; }
size_t MaxConns() const override { return 4; }
size_t MaxBacklog() const override { return 0; }
bool Keepalive() const override { return true; }
// Overridden to create the Diplomacy input handler.
//
InputHandler* CreateHandler(IpPort* port) const override;
// Overridden to create a CLI parameter that identifies the protocol.
//
CliText* CreateText() const override;
// Overridden to return the socket's buffer sizes.
//
void GetAppSocketSizes(size_t& rxSize, size_t& txSize) const override;
};
//------------------------------------------------------------------------------
//
// Input handler for messages that contain a Diplomacy header.
//
class DipInputHandler : public InputHandler
{
public:
// Registers the input handler with PORT.
//
explicit DipInputHandler(IpPort* port);
// Overridden to allocate a DipIpBuffer for a Diplomacy message that has
// received over TCP.
//
IpBuffer* AllocBuff(const byte_t* source, size_t size,
byte_t*& dest, size_t& rcvd, SysTcpSocket* socket) const override;
// Overridden to convert an outgoing message from host to network order.
//
byte_t* HostToNetwork(IpBuffer& buff,
byte_t* src, size_t size) const override;
// Overridden to convert an incoming message from network to host order.
//
void NetworkToHost(IpBuffer& buff,
byte_t* dest, const byte_t* src, size_t size) const override;
// Overridden to queue an incoming message for BotThread.
//
void ReceiveBuff
(IpBufferPtr& buff, size_t size, Faction faction) const override;
// Overridden to queue an incoming message for BotThread.
//
void SocketFailed(SysSocket* socket) const override;
};
//------------------------------------------------------------------------------
//
// IP buffer for sending and receiving Diplomacy messages.
//
class DipIpBuffer : public IpBuffer
{
public:
// Allocates a message for SIZE bytes that will travel in DIR. If DIR
// is MsgOutgoing, the size of the payload (currSize_) is set to SIZE.
//
DipIpBuffer(MsgDirection dir, size_t size);
// Copy constructor.
//
DipIpBuffer(const DipIpBuffer& that);
// Not subclassed.
//
~DipIpBuffer();
// Invoked after copying SIZE bytes into the message.
//
void BytesAdded(size_t size);
// Overridden to obtain a buffer from its object pool.
//
static void* operator new(size_t size);
// Overridden to track the number of bytes currently in the message.
//
bool AddBytes(const byte_t* source, size_t size, bool& moved) override;
// Overridden to return a copy of the buffer.
//
IpBuffer* Clone() const override;
// Overridden to display member variables.
//
void Display(std::ostream& stream,
const std::string& prefix, const Flags& options) const override;
// Overridden to return the number of bytes currently in the message.
//
size_t PayloadSize() const override { return currSize_; }
private:
// The number of bytes currently in the message.
//
size_t currSize_;
};
//------------------------------------------------------------------------------
//
// Pool for DipIpBuffer objects.
//
class DipIpBufferPool : public ObjectPool
{
friend class Singleton<DipIpBufferPool>;
// Private because this is a singleton.
//
DipIpBufferPool();
// Private because this is a singleton.
//
~DipIpBufferPool();
};
}
#endif