-
Notifications
You must be signed in to change notification settings - Fork 1
/
inet.h
386 lines (331 loc) · 15.3 KB
/
inet.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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
//============================================================================
// Mini Spin-X Library
//
// Copyright (c) 2024, Jarkko Lempiainen
// All rights reserved.
//============================================================================
#ifndef PFC_CORE_INET_H
#define PFC_CORE_INET_H
//----------------------------------------------------------------------------
//============================================================================
// interface
//============================================================================
// external
#include "sxp_src/core/utils.h"
#include "sxp_src/core/functor.h"
#include "sxp_src/core/variant.h"
namespace pfc
{
// new
typedef stack_str64 ip_str;
union ipv4_address;
union ipv6_address;
struct inetv4_socket_address;
struct inetv6_socket_address;
class inet_system_base;
class inet_socket_base;
class inet_socket_local_base;
class inet_socket_remote_base;
class inet_input_stream;
class inet_output_stream;
class simple_inet_data_protocol_socket;
bool is_ipv4(const ipv6_address&);
ip_str ipv4_to_str(const ipv4_address&);
ip_str ipv6_to_str(const ipv6_address&);
ip_str ipv6_to_simple_str(const ipv6_address&);
PFC_INLINE bool is_valid(const ipv4_address&);
PFC_INLINE bool is_valid(const ipv6_address&);
owner_ptr<inet_system_base> create_default_inet_system(bool set_active_=false);
//----------------------------------------------------------------------------
//============================================================================
// ipv4_address
//============================================================================
union ipv4_address
{ PFC_MONO(ipv4_address) {PFC_VAR(dword);}
// construction
PFC_INLINE ipv4_address();
PFC_INLINE ipv4_address(uint8_t b0_, uint8_t b1_, uint8_t b2_, uint8_t b3_);
PFC_INLINE ipv4_address(const ipv6_address&);
//--------------------------------------------------------------------------
uint8_t bytes[4];
uint16_t words[2];
uint32_t dword;
};
PFC_SET_TYPE_TRAIT(ipv4_address, is_type_pod, true);
PFC_SET_TYPE_TRAIT(ipv4_address, is_type_pod_stream, true);
//----
PFC_INLINE bool operator==(const ipv4_address&, const ipv4_address&);
PFC_INLINE bool operator!=(const ipv4_address&, const ipv4_address&);
//----------------------------------------------------------------------------
//============================================================================
// ipv6_address
//============================================================================
union ipv6_address
{ PFC_MONO(ipv6_address) {PFC_AVAR(dwords, 4);}
// construction
PFC_INLINE ipv6_address();
PFC_INLINE ipv6_address(uint32_t d0_, uint32_t d1_, uint32_t d2_, uint32_t d3_);
PFC_INLINE ipv6_address(uint16_t d0_, uint16_t d1_, uint16_t d2_, uint16_t d3_,
uint16_t d4_, uint16_t d5_, uint16_t d6_, uint16_t d7_);
PFC_INLINE ipv6_address(const ipv4_address&);
//--------------------------------------------------------------------------
uint8_t bytes[16];
uint16_t words[8];
uint32_t dwords[4];
};
PFC_SET_TYPE_TRAIT(ipv6_address, is_type_pod, true);
PFC_SET_TYPE_TRAIT(ipv6_address, is_type_pod_stream, true);
//----
PFC_INLINE bool operator==(const ipv6_address&, const ipv6_address&);
PFC_INLINE bool operator!=(const ipv6_address&, const ipv6_address&);
//----------------------------------------------------------------------------
//============================================================================
// inetv4_socket_address
//============================================================================
struct inetv4_socket_address
{ PFC_MONO(inetv4_socket_address) {PFC_VAR2(ip, port);}
// construction
PFC_INLINE inetv4_socket_address();
PFC_INLINE inetv4_socket_address(const ipv4_address&, uint16_t port_);
//--------------------------------------------------------------------------
ipv4_address ip;
uint16_t port;
};
PFC_SET_TYPE_TRAIT(inetv4_socket_address, is_type_pod, true);
PFC_SET_TYPE_TRAIT(inetv4_socket_address, is_type_pod_stream, true);
//----
PFC_INLINE bool operator==(const inetv4_socket_address&, const inetv4_socket_address&);
PFC_INLINE bool operator!=(const inetv4_socket_address&, const inetv4_socket_address&);
//----------------------------------------------------------------------------
//============================================================================
// inetv6_socket_address
//============================================================================
struct inetv6_socket_address
{ PFC_MONO(inetv6_socket_address) {PFC_VAR2(ip, port);}
// construction
PFC_INLINE inetv6_socket_address();
PFC_INLINE inetv6_socket_address(const ipv6_address&, uint16_t port_);
//--------------------------------------------------------------------------
ipv6_address ip;
uint16_t port;
};
PFC_SET_TYPE_TRAIT(inetv6_socket_address, is_type_pod, true);
PFC_SET_TYPE_TRAIT(inetv6_socket_address, is_type_pod_stream, true);
//----
PFC_INLINE bool operator==(const inetv6_socket_address&, const inetv6_socket_address&);
PFC_INLINE bool operator!=(const inetv6_socket_address&, const inetv6_socket_address&);
//----------------------------------------------------------------------------
//============================================================================
// inet_system_base
//============================================================================
class inet_system_base
{
public:
// construction
inet_system_base(bool set_active_=false);
virtual ~inet_system_base()=0;
static PFC_INLINE void set_active(inet_system_base*);
static PFC_INLINE inet_system_base &active();
//--------------------------------------------------------------------------
// socket construction
virtual ipv6_address local_ipv6() const=0;
virtual ipv6_address dns_lookup_ipv6(const char *hostname_)=0;
virtual owner_ref<inet_socket_local_base> create_local_socket()=0;
owner_ref<inet_socket_local_base> create_local_socket(unsigned port_, unsigned max_backlog_=1, const ipv6_address *ip_=0);
virtual owner_ref<inet_socket_remote_base> create_remote_socket()=0;
owner_ptr<inet_socket_remote_base> create_remote_socket(const ipv6_address&, unsigned port_);
//--------------------------------------------------------------------------
private:
inet_system_base(const inet_system_base&); // not implemented
void operator=(const inet_system_base&); // not implemented
//--------------------------------------------------------------------------
static inet_system_base *s_active;
};
//----------------------------------------------------------------------------
//============================================================================
// inet_socket_base
//============================================================================
class inet_socket_base
{
public:
// construction
PFC_INLINE inet_socket_base();
virtual PFC_INLINE ~inet_socket_base();
virtual void disconnect()=0;
//--------------------------------------------------------------------------
// accessors
virtual usize_t bufsize_recv() const=0;
virtual usize_t bufsize_send() const=0;
//--------------------------------------------------------------------------
// data streaming
virtual usize_t read(void *buffer_, usize_t buffer_size_)=0;
virtual usize_t write(const void *data_, usize_t data_size_)=0;
//--------------------------------------------------------------------------
private:
inet_socket_base(const inet_socket_base&); // not implemented
void operator=(const inet_socket_base&); // not implemented
};
//----------------------------------------------------------------------------
//============================================================================
// inet_socket_local_base
//============================================================================
class inet_socket_local_base: public inet_socket_base
{
public:
// construction
PFC_INLINE inet_socket_local_base();
//--------------------------------------------------------------------------
// connection
virtual void bind(unsigned port_, unsigned max_backlog_=1, const ipv6_address *ip_=0)=0;
virtual bool wait_connection(float timeout_=-1)=0;
//--------------------------------------------------------------------------
private:
inet_socket_local_base(const inet_socket_local_base&); // not implemented
void operator=(const inet_socket_local_base&); // not implemented
};
//----------------------------------------------------------------------------
//============================================================================
// inet_socket_remote_base
//============================================================================
class inet_socket_remote_base: public inet_socket_base
{
public:
// construction
PFC_INLINE inet_socket_remote_base();
//--------------------------------------------------------------------------
// connection
virtual bool connect(const ipv6_address&, unsigned port_)=0;
//--------------------------------------------------------------------------
private:
inet_socket_remote_base(const inet_socket_remote_base&); // not implemented
void operator=(const inet_socket_remote_base&); // not implemented
};
//----------------------------------------------------------------------------
//============================================================================
// inet_input_stream
//============================================================================
class inet_input_stream: public bin_input_stream_base
{
public:
// construction
inet_input_stream(inet_socket_base&);
void set_timeout(unsigned min_bytes_per_sec_, udouble_t max_request_time_);
//--------------------------------------------------------------------------
// accessors and mutators
PFC_INLINE bool has_timeouted() const;
PFC_INLINE void reset_timeout();
//--------------------------------------------------------------------------
private:
inet_input_stream(const inet_input_stream&); // not implemented
void operator=(const inet_input_stream&); // not implemented
virtual usize_t update_buffer_impl(void*, usize_t num_bytes_, bool exact_);
virtual void rewind_impl();
virtual void rewind_impl(usize_t num_bytes_);
virtual void skip_impl();
virtual void seek_impl(usize_t abs_pos_);
//--------------------------------------------------------------------------
enum {buffer_size=1024};
inet_socket_base &m_socket;
bool m_has_timeouted;
udouble_t m_timeout_max_spb;
udouble_t m_timeout_max_request_time;
uint8_t m_buffer[buffer_size];
};
//----------------------------------------------------------------------------
//============================================================================
// inet_output_stream
//============================================================================
class inet_output_stream: public bin_output_stream_base
{
public:
// construction
inet_output_stream(inet_socket_base&);
virtual ~inet_output_stream();
void set_timeout(unsigned min_bytes_per_sec_, udouble_t max_request_time_);
//--------------------------------------------------------------------------
// accessors and mutators
PFC_INLINE bool has_timeouted() const;
PFC_INLINE void reset_timeout();
//--------------------------------------------------------------------------
private:
inet_output_stream(const inet_output_stream&); // not implemented
void operator=(const inet_output_stream&); // not implemented
virtual void flush_buffer_impl(const void*, usize_t num_bytes_);
usize_t write_data(const uint8_t*, usize_t num_bytes_);
//--------------------------------------------------------------------------
enum {buffer_size=1024};
inet_socket_base &m_socket;
bool m_has_timeouted;
udouble_t m_timeout_max_spb;
udouble_t m_timeout_max_request_time;
uint8_t m_buffer[buffer_size];
};
//----------------------------------------------------------------------------
//============================================================================
// simple_inet_data_protocol_socket
//============================================================================
// A simple and efficient data protocol socket for bidirectional type-safe
// communication over a local/remote internet sockets. The data is sent as
// binary with minimal type info to optimize the transfer.
// The socket sends periodical keep-alive signal if no data is otherwise sent,
// to signal the connection that the socket is alive. This signal is being sent
// by process_input_data() which should be called frequently (at least twice
// within the timeout threshold) to maintain the connection and to avoid the
// potential connection timeout.
// The socket also implements double windowed receiver-driven pacing to avoid
// receiver data congestion while avoiding socket data starvation. The socket
// sends a pacing signal to the receiver every ~N sent bytes (window size) and
// blocks writes to the socket if pacing ACK signal for the previous window
// hasn't been returned from the receiver.
class simple_inet_data_protocol_socket
{
public:
// construction and connecstion
simple_inet_data_protocol_socket(inet_socket_base&, udouble_t timeout_=1.0);
template<class T> void register_input_type_handler(const functor<void(const T&)>&, const char *alt_name_=0);
bool connect();
void disconnect();
PFC_INLINE bool is_alive() const;
PFC_INLINE void set_timeout(udouble_t timeout_);
PFC_INLINE void reset_timeout();
//--------------------------------------------------------------------------
// data writing and reading
template<class T> bool write(const T&, const char *alt_name_=0);
bool process_input_data();
//--------------------------------------------------------------------------
private:
simple_inet_data_protocol_socket(const simple_inet_data_protocol_socket&); // not implemented
void operator=(const simple_inet_data_protocol_socket&); // not implemented
struct data_reader_base;
template<class T> struct data_reader;
struct registered_local_type;
//--------------------------------------------------------------------------
//==========================================================================
// e_connection_state
//==========================================================================
enum e_connection_state
{
constate_unconnected, // hasn't been connected since construction
constate_connected, // is connected
constate_disconnected, // has been connected and then disconnected
};
//--------------------------------------------------------------------------
inet_socket_base &m_socket;
inet_input_stream m_stream_in;
inet_output_stream m_stream_out;
udouble_t m_timeout;
e_connection_state m_connection_state;
udouble_t m_last_keepalive_signal_recv;
udouble_t m_last_keepalive_signal_sent;
uint32_t m_pacing_window_size;
uint8_t m_pacing_id_recv;
uint8_t m_pacing_id_sent;
usize_t m_pacing_pos_next;
array<registered_local_type> m_registered_local_types;
map<heap_str, uint16_t> m_registered_remote_types;
};
//----------------------------------------------------------------------------
//============================================================================
#include "inet.inl"
} // namespace pfc
#endif