-
Notifications
You must be signed in to change notification settings - Fork 109
/
Socket.hpp
389 lines (337 loc) · 15.6 KB
/
Socket.hpp
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
387
388
389
#ifndef AREG_BASE_SOCKET_HPP
#define AREG_BASE_SOCKET_HPP
/************************************************************************
* This file is part of the AREG SDK core engine.
* AREG SDK is dual-licensed under Free open source (Apache version 2.0
* License) and Commercial (with various pricing models) licenses, depending
* on the nature of the project (commercial, research, academic or free).
* You should have received a copy of the AREG SDK license description in LICENSE.txt.
* If not, please contact to info[at]aregtech.com
*
* \copyright (c) 2017-2023 Aregtech UG. All rights reserved.
* \file areg/base/Socket.hpp
* \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit
* \author Artak Avetyan
* \brief AREG Platform base class of socket.
************************************************************************/
/************************************************************************
* Include files.
************************************************************************/
#include "areg/base/GEGlobal.h"
#include "areg/base/String.hpp"
#include "areg/base/NEMemory.hpp"
#include "areg/base/NESocket.hpp"
#include <memory>
/************************************************************************
* Dependencies
************************************************************************/
class RemoteMessage;
/**
* \brief Base class for client, server and accepted socket connections.
* The object cannot be directly instantiated. Instead, instantiate
* one of child classes.
* Current socket supports only TCP/IP connection. All other connection
* connection types and protocols are out of scope of this class and
* are not supported.
* The socket module will be automatically loaded in the process as
* soon as the first socket object is created and automatically released
* when last socket is destroyed.
**/
//////////////////////////////////////////////////////////////////////////
// Socket class declaration
//////////////////////////////////////////////////////////////////////////
class AREG_API Socket
{
//////////////////////////////////////////////////////////////////////////////
// Constructors / Destructor. Protected
//////////////////////////////////////////////////////////////////////////////
protected:
/**
* \brief Default constructor. Creates instance of object
* with invalid socket object. Before sending
* or receiving data, the socket should be created.
**/
Socket( void );
/**
* \brief Initialization constructor. Sets socket descriptor and socket address
* \param hSocket Socket descriptor to set
* \param sockAddress Socket address to set
**/
Socket( const SOCKETHANDLE hSocket, const NESocket::SocketAddress & sockAddress );
/**
* \brief Copy constructor.
* \param source The source to copy data.
**/
Socket( const Socket & source );
/**
* \brief Move constructor.
* \param source The source to copy data.
**/
Socket( Socket && source ) noexcept;
/**
* \brief Destructor. Invalidates socket object, decrease reference counter,
* and if reference counter is reaching zero, close socket.
**/
virtual ~Socket( void );
/**
* \brief Assigns socket data taken from given source.
* \param src The source of socket data.
**/
Socket & operator = ( const Socket & src );
/**
* \brief Moves socket data taken from given source.
* \param src The source of socket data.
**/
Socket & operator = ( Socket && src ) noexcept;
//////////////////////////////////////////////////////////////////////////
// Overrides
//////////////////////////////////////////////////////////////////////////
public:
/************************************************************************/
// Socket overrides
/************************************************************************/
/**
* \brief For client sockets, this method is creating new socket descriptor
* and connects to specified remote host and port number.
* For server sockets, this method is creating new socket descriptor
* and bind socket to specified host name and port number.
* The method should not do anything for accepted sockets.
* If object had before valid socket descriptor, it will be first closed,
* then create new.
*
* The method should be overwritten by child classes.
*
* \param hostName The name of host to connect or bind.
* \param portNr The valid port number to connect or bind.
* \return Returns true if operation succeeded.
**/
virtual bool createSocket( const char * hostName, unsigned short portNr ) = 0;
/**
* \brief For client sockets, this method is creating new socket descriptor
* and connects to host and port number. Both, remote host address
* and port number should be already set.
* For server sockets, this method is creating new socket descriptor
* and bind socket to specified host name and port number.
* Both, socket IP-address and port number should be already set.
* The method should not do anything for accepted sockets.
* If object had before valid socket descriptor, it will be first closed,
* then create new.
*
* The method should be overwritten by child classes.
*
* \return Returns true if operation succeeded.
**/
virtual bool createSocket( void ) = 0;
/**
* \brief Closes existing socket.
* Note: The call will invalidate socket of object, but the socket
* will be closed only if reference count to existing valid
* socket reaches zero.
**/
virtual void closeSocket( void );
/**
* \brief If socket is valid, sends data using existing socket connection and returns
* number sent of bytes. And returns negative number if either socket is invalid,
* or failed to send data to remote host.
* Note: The call is blocking and method will not return until all data are not sent
* or if data sending fails.
* \param buffer The buffer of data to send to remote target.
* \param length The length in bytes of data in buffer to send
* \return Returns number of bytes sent to remote target.
* Returns negative number if socket is not valid of failed to send.
**/
virtual int sendData( const unsigned char * buffer, int length ) const;
/**
* \brief If socket is valid, receives data using existing socket connection and returns
* number of received bytes in buffer, which is equal to specified length parameter.
* Returns negative number if either socket is invalid, or failed to receive data from remote host.
* Note: The call is blocking and method will not return until all data specified in length
* is not received or if receiving data fails.
* \param buffer The buffer to fill received data from remote target.
* \param length The length in bytes of allocated space in buffer.
* \return Returns number of bytes received from remote target.
* Returns negative number if socket is not valid of failed to receive data.
**/
virtual int receiveData( unsigned char * buffer, int length ) const;
//////////////////////////////////////////////////////////////////////////
// Attributes and operations
//////////////////////////////////////////////////////////////////////////
/**
* \brief Returns socket descriptor of object.
* If socket was created, the value is not equal to NESocket::InvalidSocketHandle
**/
inline SOCKETHANDLE getHandle( void ) const;
/**
* \brief Returns true if existing socket descriptor is valid.
* The function is not checking socket descriptor validation.
**/
inline bool isValid( void ) const;
/**
* \brief Checks and returns socket alive state.
* \return Returns true if socket is alive and is not closed.
**/
inline bool isAlive( void ) const;
/**
* \brief Checks and returns number of bytes remain to read from socket buffer.
* Returns negative value if socket is invalid.
* \return Returns number of bytes available to read from socket buffer.
**/
inline int pendingRead( void ) const;
/**
* \brief Sets socket in read-only more, i.e. no send message is possible anymore.
* \return Returns true if operation succeeds.
**/
inline bool disableSend( void ) const;
/**
* \brief Sets socket in write-only more, i.e. no receive message is possible anymore.
* \return Returns true if operation succeeds.
**/
inline bool disableReceive( void ) const;
/**
* \brief Return Socket Address object.
**/
inline const NESocket::SocketAddress & getAddress( void ) const;
/**
* \brief Sets socket address. The address should be either invalid
* or already resolved with IP-address.
* \param newAddress The new address to set.
**/
inline void setAddress( const NESocket::SocketAddress & newAddress );
/**
* \brief Sets Socket Address. If hostName is not IP-address, it will
* try to resolve first then set. The isServer parameter is needed
* to resolve address either for server or for client.
* For accepted sockets this call plays no role, because the
* the address automatically is resolved when accepting connection.
* \param hostName Host name or IP-address to set. If name is specified,
* first it will be resolved to get IP-address.
* \param portNr Valid port number of socket connection.
* \param isServer Flag, indicating whether name should be resolve for
* server or for client.
* \return Returns true if succeeded to resolve and set Socket Address.
**/
bool setAddress( const char * hostName, unsigned short portNr, bool isServer );
/**
* \brief Returns the packet size in bytes to send data.
**/
inline unsigned int getSendPacketSize(void) const;
/**
* \brief Returns the packet size in bytes to receive data.
**/
inline unsigned int getRecvPacketSize(void) const;
protected:
/************************************************************************/
// Socket protected overrides
/************************************************************************/
/**
* \brief Called when the lock counter reaches zero.
* By default, when lock counter is zero, the system automatically closes socket.
* Overwrite this method if other action should be taken.
* \param hSocket The Socket Handle to take close action.
* In the moment when it is called, the member socket handle is already invalidated.
**/
void closeSocketHandle( SOCKETHANDLE hSocket );
/**
* \brief Decreases lock counter and if it is zero, the calls method to close socket.
**/
void decreaseLock( void );
/**
* \brief Sets the socket packet size in bytes to send data. The packet cannot be smaller than NESocket::PACKET_MIN_SIZE
* and bigger than NESocket::PACKET_MAX_SIZE.
*
* \param sendSize The size of packet in bytes to set to send data.
* The function checks and normalizes size in range between
* NESocket::PACKET_MIN_SIZE and NESocket::PACKET_MAX_SIZE.
* \param force If true, it forces to update the packet size. Otherwise, the packet size
* is updated only if new size is bigger than the actual.
* \return Returns the actual size of packet in bytes to send data. If socket is not valid,
* return NESocket::PACKET_INVALID_SIZE.
**/
unsigned int setSendPacketSize(unsigned int sendSize, bool force = false) const;
/**
* \brief Sets the socket packet size in bytes to receive data. The packet cannot be smaller than NESocket::PACKET_MIN_SIZE
* and bigger than NESocket::PACKET_MAX_SIZE.
*
* \param recvSize The size of packet in bytes to set to receive data.
* The function checks and normalizes size in range between
* NESocket::PACKET_MIN_SIZE and NESocket::PACKET_MAX_SIZE.
* \param force If true, it forces to update the packet size. Otherwise, the packet size
* is update only if new size is bigger than the actual.
* \return Returns the actual size of packet in bytes to receive data. If socket is not valid,
* return NESocket::PACKET_INVALID_SIZE.
**/
unsigned int setRecvPacketSize(unsigned int recvSize, bool force = false) const;
//////////////////////////////////////////////////////////////////////////
// Member variables
//////////////////////////////////////////////////////////////////////////
protected:
#if defined(_MSC_VER) && (_MSC_VER > 1200)
#pragma warning(disable: 4251)
#endif // _MSC_VER
/**
* \brief Pointer to socket descriptor. Also used as reference counter
* to close socket automatically if there is no more socket object holds the socket.
**/
std::shared_ptr<SOCKETHANDLE> mSocket;
#if defined(_MSC_VER) && (_MSC_VER > 1200)
#pragma warning(default: 4251)
#endif // _MSC_VER
/**
* \brief The address of socket
**/
NESocket::SocketAddress mAddress;
/**
* \brief The size in bytes of packet to send data.
* Should be in range NESocket::PACKET_MIN_SIZE and NESocket::PACKET_MAX_SIZE.
**/
mutable unsigned int mSendSize;
/**
* \brief The size in bytes of packet to receive data.
* Should be in range NESocket::PACKET_MIN_SIZE and NESocket::PACKET_MAX_SIZE.
**/
mutable unsigned int mRecvSize;
};
//////////////////////////////////////////////////////////////////////////
// Socket class inline functions
//////////////////////////////////////////////////////////////////////////
inline SOCKETHANDLE Socket::getHandle( void ) const
{
return (mSocket.get() != nullptr ? *mSocket : NESocket::InvalidSocketHandle);
}
inline const NESocket::SocketAddress & Socket::getAddress( void ) const
{
return mAddress;
}
inline void Socket::setAddress( const NESocket::SocketAddress & newAddress )
{
mAddress = newAddress;
}
inline bool Socket::isValid( void ) const
{
return (mSocket.get() != nullptr) && NESocket::isSocketHandleValid(*mSocket);
}
inline bool Socket::isAlive(void) const
{
return (mSocket.get() != nullptr) && NESocket::isSocketAlive(*mSocket);
}
inline int Socket::pendingRead(void) const
{
return (mSocket.get() != nullptr) && NESocket::pendingRead(*mSocket);
}
inline bool Socket::disableSend( void ) const
{
return (mSocket.get() != nullptr) && NESocket::disableSend(*mSocket);
}
inline bool Socket::disableReceive( void ) const
{
return (mSocket.get() != nullptr) && NESocket::disableReceive(*mSocket);
}
inline unsigned int Socket::getSendPacketSize(void) const
{
return (isValid() ? mSendSize : NESocket::PACKET_INVALID_SIZE);
}
unsigned int Socket::getRecvPacketSize(void) const
{
return (isValid() ? mRecvSize : NESocket::PACKET_INVALID_SIZE);
}
#endif // AREG_BASE_SOCKET_HPP