CppServer  1.0.0.0
C++ Server Library
socket.cpp
Go to the documentation of this file.
1 
10 
11 #include "errors/fatal.h"
12 #include "string/format.h"
13 
14 #include <cassert>
15 
16 namespace CppServer {
17 namespace Nanomsg {
18 
19 Socket::Socket(Domain domain, Protocol protocol)
20  : _domain(domain),
21  _protocol(protocol),
22  _socket(-1),
23  _endpoint(-1)
24 {
25  Open();
26 }
27 
29 {
30  try
31  {
32  if (IsConnected())
33  Disconnect();
34  if (IsOpened())
35  Close();
36  }
37  catch (CppCommon::SystemException& ex)
38  {
39  fatality(CppCommon::SystemException(ex.string()));
40  }
41 }
42 
43 uint64_t Socket::established_connections() const noexcept
44 {
45  return nn_get_statistic(_socket, NN_STAT_ESTABLISHED_CONNECTIONS);
46 }
47 
48 uint64_t Socket::accepted_connections() const noexcept
49 {
50  return nn_get_statistic(_socket, NN_STAT_ACCEPTED_CONNECTIONS);
51 }
52 
53 uint64_t Socket::dropped_connections() const noexcept
54 {
55  return nn_get_statistic(_socket, NN_STAT_DROPPED_CONNECTIONS);
56 }
57 
58 uint64_t Socket::broken_connections() const noexcept
59 {
60  return nn_get_statistic(_socket, NN_STAT_BROKEN_CONNECTIONS);
61 }
62 
63 uint64_t Socket::connect_errors() const noexcept
64 {
65  return nn_get_statistic(_socket, NN_STAT_CONNECT_ERRORS);
66 }
67 
68 uint64_t Socket::bind_errors() const noexcept
69 {
70  return nn_get_statistic(_socket, NN_STAT_BIND_ERRORS);
71 }
72 
73 uint64_t Socket::accept_errors() const noexcept
74 {
75  return nn_get_statistic(_socket, NN_STAT_ACCEPT_ERRORS);
76 }
77 
78 uint64_t Socket::current_connections() const noexcept
79 {
80  return nn_get_statistic(_socket, NN_STAT_CURRENT_CONNECTIONS);
81 }
82 
83 uint64_t Socket::messages_sent() const noexcept
84 {
85  return nn_get_statistic(_socket, NN_STAT_MESSAGES_SENT);
86 }
87 
88 uint64_t Socket::messages_received() const noexcept
89 {
90  return nn_get_statistic(_socket, NN_STAT_MESSAGES_RECEIVED);
91 }
92 
93 uint64_t Socket::bytes_sent() const noexcept
94 {
95  return nn_get_statistic(_socket, NN_STAT_BYTES_SENT);
96 }
97 
98 uint64_t Socket::bytes_received() const noexcept
99 {
100  return nn_get_statistic(_socket, NN_STAT_BYTES_RECEIVED);
101 }
102 
104 {
105  if (IsOpened())
106  return false;
107 
108  _socket = nn_socket((int)_domain, (int)_protocol);
109  if (!IsOpened())
110  throwex CppCommon::SystemException("Failed to open a new nanomsg socket (domain={}, protocol={})! Nanomsg error: {}"_format(_domain, _protocol, nn_strerror(nn_errno())));
111  return true;
112 }
113 
115 {
116  if (!IsOpened())
117  return false;
118 
119  int result = nn_close(_socket);
120  if (result != 0)
121  throwex CppCommon::SystemException("Cannot close the nanomsg socket! Nanomsg error: {}"_format(nn_strerror(nn_errno())));
122  _socket = -1;
123  _endpoint = -1;
124  _address = "";
125  return true;
126 }
127 
129 {
130  if (IsOpened())
131  Close();
132 
133  return Open();
134 }
135 
136 bool Socket::SetSocketOption(int level, int option, const void* value, size_t size)
137 {
138  if (!IsOpened())
139  return false;
140 
141  int result = nn_setsockopt(_socket, level, option, value, size);
142  if (result != 0)
143  {
144  if (nn_errno() == ETERM)
145  return false;
146  else
147  throwex CppCommon::SystemException("Cannot set the nanomsg socket option! Nanomsg error: {}"_format(nn_strerror(nn_errno())));
148  }
149  return true;
150 }
151 
152 bool Socket::GetSocketOption(int level, int option, void* value, size_t* size)
153 {
154  if (!IsOpened())
155  return false;
156 
157  int result = nn_getsockopt(_socket, level, option, value, size);
158  if (result != 0)
159  {
160  if (nn_errno() == ETERM)
161  return false;
162  else
163  throwex CppCommon::SystemException("Cannot get the nanomsg socket option! Nanomsg error: {}"_format(nn_strerror(nn_errno())));
164  }
165  return true;
166 }
167 
168 bool Socket::Bind(const std::string& address)
169 {
170  if (!IsOpened())
171  return false;
172 
173  if (IsConnected())
174  return false;
175 
176  int result = nn_bind(_socket, address.c_str());
177  if (result < 0)
178  {
179  if (nn_errno() == ETERM)
180  return false;
181  else
182  throwex CppCommon::SystemException("Cannot bind the nanomsg socket to the given endpoint '{}'! Nanomsg error: {}"_format(address, nn_strerror(nn_errno())));
183  }
184  _endpoint = result;
185  _address = address;
186  return true;
187 }
188 
189 bool Socket::Connect(const std::string& address)
190 {
191  if (!IsOpened())
192  return false;
193 
194  if (IsConnected())
195  return false;
196 
197  int result = nn_connect(_socket, address.c_str());
198  if (result < 0)
199  {
200  if (nn_errno() == ETERM)
201  return false;
202  else
203  throwex CppCommon::SystemException("Cannot connect the nanomsg socket to the given endpoint '{}'! Nanomsg error: {}"_format(address, nn_strerror(nn_errno())));
204  }
205  _endpoint = result;
206  _address = address;
207  return true;
208 }
209 
210 bool Socket::Link(const std::string& address)
211 {
212  if (!IsOpened())
213  return false;
214 
215  int result = nn_connect(_socket, address.c_str());
216  if (result < 0)
217  {
218  if (nn_errno() == ETERM)
219  return false;
220  else
221  throwex CppCommon::SystemException("Cannot link the nanomsg socket to the given endpoint '{}'! Nanomsg error: {}"_format(address, nn_strerror(nn_errno())));
222  }
223  return true;
224 }
225 
227 {
228  if (!IsOpened())
229  return false;
230 
231  if (!IsConnected())
232  return false;
233 
234  int result = nn_shutdown(_socket, _endpoint);
235  if (result != 0)
236  {
237  if (nn_errno() == ETERM)
238  return false;
239  else
240  throwex CppCommon::SystemException("Cannot disconnect the nanomsg socket from the endpoint '{}'! Nanomsg error: {}"_format(_address, nn_strerror(nn_errno())));
241  }
242  _endpoint = -1;
243  _address = "";
244  return true;
245 }
246 
247 size_t Socket::Send(const void* buffer, size_t size)
248 {
249  assert((buffer != nullptr) && "Pointer to the buffer should not be equal to 'nullptr'!");
250  assert((size > 0) && "Buffer size should be greater than zero!");
251  if ((buffer == nullptr) || (size == 0))
252  return 0;
253 
254  if (!IsOpened())
255  return 0;
256 
257  if (!IsConnected())
258  return 0;
259 
260  int result = nn_send(_socket, buffer, size, 0);
261  if (result < 0)
262  {
263  if (nn_errno() == ETERM)
264  return 0;
265  else
266  throwex CppCommon::SystemException("Cannot send {} bytes to the nanomsg socket! Nanomsg error: {}"_format(size, nn_strerror(nn_errno())));
267  }
268  return size;
269 }
270 
271 size_t Socket::TrySend(const void* buffer, size_t size)
272 {
273  assert((buffer != nullptr) && "Pointer to the buffer should not be equal to 'nullptr'!");
274  assert((size > 0) && "Buffer size should be greater than zero!");
275  if ((buffer == nullptr) || (size == 0))
276  return 0;
277 
278  if (!IsOpened())
279  return 0;
280 
281  if (!IsConnected())
282  return 0;
283 
284  int result = nn_send(_socket, buffer, size, NN_DONTWAIT);
285  if (result < 0)
286  {
287  if (nn_errno() == EAGAIN)
288  return 0;
289  else if (nn_errno() == ETERM)
290  return 0;
291  else
292  throwex CppCommon::SystemException("Cannot send {} bytes to the nanomsg socket in non-blocking mode! Nanomsg error: {}"_format(size, nn_strerror(nn_errno())));
293  }
294  return size;
295 }
296 
297 size_t Socket::Receive(Message& message)
298 {
299  // Clear previous message
300  message.Clear();
301 
302  if (!IsOpened())
303  return 0;
304 
305  if (!IsConnected())
306  return 0;
307 
308  void* data = nullptr;
309  int result = nn_recv(_socket, &data, NN_MSG, 0);
310  if (result < 0)
311  {
312  if (nn_errno() == ETERM)
313  return 0;
314  else
315  throwex CppCommon::SystemException("Cannot receive a message from the nanomsg socket! Nanomsg error: {}"_format(nn_strerror(nn_errno())));
316  }
317 
318  message._buffer = (uint8_t*)data;
319  message._size = result;
320  return message.size();
321 }
322 
323 size_t Socket::TryReceive(Message& message)
324 {
325  // Clear previous message
326  message.Clear();
327 
328  if (!IsOpened())
329  return 0;
330 
331  if (!IsConnected())
332  return 0;
333 
334  void* data = nullptr;
335  int result = nn_recv(_socket, &data, NN_MSG, NN_DONTWAIT);
336  if (result < 0)
337  {
338  if (nn_errno() == EAGAIN)
339  return 0;
340  else if (nn_errno() == ETERM)
341  return 0;
342  else
343  throwex CppCommon::SystemException("Cannot receive a message from the nanomsg socket in non-blocking mode! Nanomsg error: {}"_format(nn_strerror(nn_errno())));
344  }
345 
346  message._buffer = (uint8_t*)data;
347  message._size = result;
348  return message.size();
349 }
350 
351 std::tuple<size_t, bool> Socket::ReceiveSurvey(Message& message)
352 {
353  // Clear previous message
354  message.Clear();
355 
356  if (!IsOpened())
357  return std::make_tuple(0, true);
358 
359  if (!IsConnected())
360  return std::make_tuple(0, true);
361 
362  void* data = nullptr;
363  int result = nn_recv(_socket, &data, NN_MSG, 0);
364  if (result < 0)
365  {
366  if (nn_errno() == ETIMEDOUT)
367  return std::make_tuple(0, true);
368  else if (nn_errno() == ETERM)
369  return std::make_tuple(0, true);
370  else
371  throwex CppCommon::SystemException("Cannot receive a survey respond from the nanomsg socket! Nanomsg error: {}"_format(nn_strerror(nn_errno())));
372  }
373 
374  message._buffer = (uint8_t*)data;
375  message._size = result;
376  return std::make_tuple(message.size(), false);
377 }
378 
379 std::tuple<size_t, bool> Socket::TryReceiveSurvey(Message& message)
380 {
381  // Clear previous message
382  message.Clear();
383 
384  if (!IsOpened())
385  return std::make_tuple(0, true);
386 
387  if (!IsConnected())
388  return std::make_tuple(0, true);
389 
390  void* data = nullptr;
391  int result = nn_recv(_socket, &data, NN_MSG, NN_DONTWAIT);
392  if (result < 0)
393  {
394  if (nn_errno() == EAGAIN)
395  return std::make_tuple(0, false);
396  else if (nn_errno() == ETIMEDOUT)
397  return std::make_tuple(0, true);
398  else if (nn_errno() == ETERM)
399  return std::make_tuple(0, true);
400  else
401  throwex CppCommon::SystemException("Cannot receive a survey respond from the nanomsg socket in non-blocking mode! Nanomsg error: {}"_format(nn_strerror(nn_errno())));
402  }
403 
404  message._buffer = (uint8_t*)data;
405  message._size = result;
406  return std::make_tuple(message.size(), false);
407 }
408 
410 {
411  nn_term();
412 }
413 
414 } // namespace Nanomsg
415 } // namespace CppServer
uint64_t established_connections() const noexcept
Get the number of connections successfully established that were initiated from this socket...
Definition: socket.cpp:43
uint64_t accept_errors() const noexcept
Get the number of errors encountered by this socket trying to accept a a connection from a remote pee...
Definition: socket.cpp:73
bool Reopen()
Reopen the socket.
Definition: socket.cpp:128
bool SetSocketOption(int level, int option, const void *value, size_t size)
Set the socket option.
Definition: socket.cpp:136
bool Close()
Close the socket.
Definition: socket.cpp:114
bool Link(const std::string &address)
Link the socket to the remote endpoint.
Definition: socket.cpp:210
static void Terminate()
Terminate all socket operations.
Definition: socket.cpp:409
uint64_t connect_errors() const noexcept
Get the number of errors encountered by this socket trying to connect to a remote peer...
Definition: socket.cpp:63
size_t TrySend(const void *buffer, size_t size)
Try to send data to the socket in non-blocking mode.
Definition: socket.cpp:271
Nanomsg message.
Definition: message.h:29
std::tuple< size_t, bool > ReceiveSurvey(Message &message)
Receive a respond to the survey from the socket in non-blocking mode.
Definition: socket.cpp:351
bool GetSocketOption(int level, int option, void *value, size_t *size)
Get the socket option.
Definition: socket.cpp:152
size_t size() const noexcept
Get the message size.
Definition: message.h:71
uint64_t broken_connections() const noexcept
Get the number of established connections that were closed by this socket, typically due to protocol ...
Definition: socket.cpp:58
C++ Server project definitions.
Definition: asio.h:24
Socket(Domain domain, Protocol protocol)
Initialize and open socket with a given domain and protocol.
Definition: socket.cpp:19
std::tuple< size_t, bool > TryReceiveSurvey(Message &message)
Try to receive a respond to the survey from the socket in non-blocking mode.
Definition: socket.cpp:379
uint64_t bind_errors() const noexcept
Get the number of errors encountered by this socket trying to bind to a local address.
Definition: socket.cpp:68
bool Bind(const std::string &address)
Bind the socket to the local endpoint.
Definition: socket.cpp:168
uint64_t current_connections() const noexcept
Get the number of connections currently estabalished to this socket.
Definition: socket.cpp:78
uint64_t messages_sent() const noexcept
Get the number messages sent by this socket.
Definition: socket.cpp:83
uint64_t bytes_sent() const noexcept
Get the number of bytes sent by this socket.
Definition: socket.cpp:93
bool IsConnected() const noexcept
Is socket connected?
Definition: socket.h:84
uint64_t messages_received() const noexcept
Get the number messages received by this socket.
Definition: socket.cpp:88
Protocol
Nanomsg protocol.
Definition: nanomsg.h:56
size_t Receive(Message &message)
Receive a message from the socket in non-blocking mode.
Definition: socket.cpp:297
uint64_t bytes_received() const noexcept
Get the number of bytes received by this socket.
Definition: socket.cpp:98
size_t Send(const void *buffer, size_t size)
Send data to the socket.
Definition: socket.cpp:247
void Clear()
Clear the message buffer.
Definition: message.cpp:60
Domain
Nanomsg domain.
Definition: nanomsg.h:41
uint64_t dropped_connections() const noexcept
Get the number of established connections that were dropped by this socket.
Definition: socket.cpp:53
Nanomsg socket definition.
uint64_t accepted_connections() const noexcept
Get the number of connections successfully established that were accepted by this socket...
Definition: socket.cpp:48
bool Open()
Open the socket.
Definition: socket.cpp:103
bool Connect(const std::string &address)
Connect the socket to the remote endpoint.
Definition: socket.cpp:189
bool IsOpened() const noexcept
Is socket opened?
Definition: socket.h:82
const std::string & address() const noexcept
Get the socket address.
Definition: socket.h:54
size_t TryReceive(Message &message)
Try to receive a message from the socket in non-blocking mode.
Definition: socket.cpp:323
bool Disconnect()
Disconnect the socket from the endpoint.
Definition: socket.cpp:226