DDS  ver. 3.6
INet.h
Go to the documentation of this file.
1 // Copyright 2014 GSI, Inc. All rights reserved.
2 //
3 // helpers for Socket and Network operations.
4 //
5 #ifndef _DDS_INET_H_
6 #define _DDS_INET_H_
7 
8 // API
9 #include <arpa/inet.h>
10 #include <fcntl.h>
11 #include <netdb.h>
12 #include <netinet/in.h>
13 #include <sys/socket.h>
14 // STD
15 #include <algorithm>
16 #include <iterator>
17 #include <stdexcept>
18 #include <unistd.h>
19 // Misc
20 #include "ErrorCode.h"
21 #include "MiscUtils.h"
22 #include "def.h"
23 // BOOST
24 #include <boost/uuid/uuid.hpp>
25 #include <boost/uuid/uuid_io.hpp>
26 
28 #define INVALID_SOCKET -1
29 
30 namespace dds::misc
31 {
37  namespace INet
38  {
44  typedef int Socket_t;
45 
46  // Forward declaration
47  inline std::string socket_error_string(Socket_t _socket, const char* _strMsg = NULL);
48 
54  class smart_socket : public NONCopyable
55  {
56  // TODO: Implement reference count
57  public:
59  : m_Socket(INVALID_SOCKET)
60  {
61  }
62  smart_socket(int _Socket)
63  : m_Socket(_Socket)
64  {
65  }
66  smart_socket(int _domain, int _type, int _protocol, bool _Block = false)
67  {
68  m_Socket = ::socket(_domain, _type, _protocol);
69  // Blocking or Non-blocking socket
70  if (_Block)
71  set_nonblock();
72  }
74  {
75  close();
76  }
77  // Socket_t* operator&()
78  // {
79  // return & m_Socket;
80  // }
81  operator int() const
82  {
83  return static_cast<int>(m_Socket);
84  }
85  int operator=(const int& _Val)
86  {
87  close();
88  return m_Socket = _Val;
89  }
91  {
92  Socket_t Socket(m_Socket);
93  m_Socket = INVALID_SOCKET;
94  return Socket;
95  }
97  {
98  return m_Socket;
99  }
100  int set_nonblock(bool _val = true)
101  {
102  int opts = fcntl(m_Socket, F_GETFL);
103 
104  if (opts < 0)
105  return -1;
106 
107  opts = _val ? (opts | O_NONBLOCK) : (opts & ~O_NONBLOCK);
108 
109  return fcntl(m_Socket, F_SETFL, opts);
110  }
111  void close()
112  {
113  if (INVALID_SOCKET != m_Socket)
114  {
115  shutdown();
116  ::close(m_Socket); // ignoring error code
117  m_Socket = INVALID_SOCKET;
118  }
119  }
120  bool is_valid() const
121  {
122  return (INVALID_SOCKET != m_Socket);
123  }
124  int shutdown(int _How = SHUT_RDWR)
125  {
126  return ::shutdown(m_Socket, _How);
127  }
129  int is_read_ready(size_t m_SecTimeOut, size_t m_USecTimeOut = 0)
130  {
131  if (!is_valid())
132  throw std::runtime_error("Socket is invalid");
133  fd_set readset;
134  FD_ZERO(&readset);
135  FD_SET(m_Socket, &readset);
136 
137  // Setting time-out
138  timeval timeout;
139  timeout.tv_sec = m_SecTimeOut;
140  timeout.tv_usec = m_USecTimeOut;
141 
142  // TODO: Send errno to log
143  int retval = ::select(m_Socket + 1, &readset, NULL, NULL, &timeout);
144  if (retval < 0)
145  throw std::runtime_error("Server's socket got error while calling \"select\"");
146  if (0 == retval)
147  return 0;
148 
149  return FD_ISSET(m_Socket, &readset);
150  }
151 
152  private:
153  Socket_t m_Socket;
154  };
155 
156  inline size_t read_from_socket(smart_socket& _Socket, BYTEVector_t* _Buf)
157  {
158  if (!_Buf)
159  throw std::runtime_error("The given buffer pointer is NULL.");
160 
161  const ssize_t bytes_read = ::recv(_Socket, &(*_Buf)[0], _Buf->capacity(), 0);
162  if (0 == bytes_read) // The return value will be 0 when the peer has performed an orderly shutdown
163  {
164  _Socket.close();
165  return 0;
166  }
167  if (bytes_read < 0)
168  {
169  if (ECONNRESET == errno || ENOTCONN == errno)
170  _Socket.close();
171  throw system_error("");
172  }
173 
174  return bytes_read;
175  }
182  template <typename _T>
183  smart_socket& operator>>(smart_socket& _Socket, _T* _Buf);
190  template <>
192  {
193  if (!_Buf)
194  throw std::runtime_error("The given buffer pointer is NULL.");
195 
196  const ssize_t bytes_read = ::recv(_Socket, &(*_Buf)[0], _Buf->capacity(), 0);
197  if (0 == bytes_read) // The return value will be 0 when the peer has performed an orderly shutdown
198  {
199  _Buf->resize(bytes_read);
200  _Socket.close();
201  return _Socket;
202  }
203  if (bytes_read < 0)
204  {
205  if (ECONNRESET == errno || ENOTCONN == errno)
206  _Socket.close();
207  throw system_error("");
208  }
209 
210  _Buf->resize(bytes_read);
211  return _Socket;
212  }
218  inline int sendall(int s, const unsigned char* const buf, int len, int flags)
219  {
220  // TODO: sendall - Make this code safer!!!
221  int total = 0;
222  int n = 0;
223 
224  while (total < len)
225  {
226  n = ::send(s, buf + total, len - total, flags);
227  if (n == -1)
228  {
229  // TODO: may be EWOULDBLOCK or on some systems EAGAIN when it returned
230  // due to its inability to send off data without blocking.
231  if (EAGAIN == errno || EWOULDBLOCK == errno)
232  {
233  // wait for a reasonable amount of time until
234  // we could send()
235  // sleep for 100 ms
236  // usleep(100 * 1000);
237  continue;
238  }
239  else
240  throw system_error("send data exception: ");
241  }
242  total += n;
243  }
244 
245  return total;
246  }
253  template <typename _T>
254  smart_socket& operator<<(smart_socket& _Socket, _T& _Buf);
261  template <>
263  {
264  //::send( _Socket, &_Buf[ 0 ], _Buf.size(), 0 );
265  sendall(_Socket, &_Buf[0], _Buf.size(), 0);
266  return _Socket;
267  }
273  inline void send_string(smart_socket& _Socket, const std::string& _Str2Send)
274  {
275  BYTEVector_t buf;
276  copy(_Str2Send.begin(), _Str2Send.end(), back_inserter(buf));
277  _Socket << buf;
278  }
284  inline void receive_string(smart_socket& _Socket, std::string* _Str2Receive, size_t _BufSize)
285  {
286  if (!_Str2Receive)
287  throw std::invalid_argument("smart_socket::receive_string: Parameter is NULL");
288 
289  BYTEVector_t buf(_BufSize);
290  _Socket >> &buf;
291  *_Str2Receive = std::string(reinterpret_cast<char*>(&buf[0]), buf.size());
292  }
298  inline bool is_ip_address(std::string _Addr)
299  {
300  // removing all dots
301  _Addr.erase(remove(_Addr.begin(), _Addr.end(), '.'), _Addr.end());
302  // Checking for all numerics
303  return (_Addr.end() == std::find_if(_Addr.begin(), _Addr.end(), std::not_fn(IsDigit())));
304  }
310  inline void host2ip(const std::string& _Host, std::string* _IP) // _Host can be either host name or IP address
311  {
312  if (!_IP)
313  return;
314 
315  if (is_ip_address(_Host))
316  {
317  *_IP = _Host;
318  return;
319  }
320 
321  hostent* he = gethostbyname(_Host.c_str());
322  if (!he)
323  return; // TODO: throw... herror()
324 
325  *_IP = inet_ntoa(*(reinterpret_cast<in_addr*>(he->h_addr)));
326  }
332  inline void ip2host(const std::string& _IP, std::string* _Host)
333  {
334  if (!_Host)
335  return;
336 
337  if (!is_ip_address(_IP))
338  {
339  *_Host = _IP;
340  return;
341  }
342 
343  in_addr addr;
344  inet_aton(_IP.c_str(), &addr);
345  hostent* he = gethostbyaddr(&addr, sizeof(addr), AF_INET);
346  if (!he)
347  return;
348 
349  *_Host = he->h_name;
350  }
357  {
358  public:
360  : m_Socket(AF_INET, SOCK_STREAM, 0)
361  {
362  }
363  void Bind(unsigned short _nPort, const std::string* _Addr = NULL)
364  {
365  if (m_Socket < 0)
366  throw std::runtime_error(socket_error_string(m_Socket, "NULL socket has been given to Bind"));
367 
368  sockaddr_in addr;
369  addr.sin_family = AF_INET;
370  addr.sin_port = htons(_nPort);
371  if (!_Addr)
372  addr.sin_addr.s_addr = htonl(INADDR_ANY);
373  else
374  inet_aton(_Addr->c_str(), &addr.sin_addr);
375 
376  if (::bind(m_Socket, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0)
377  throw std::runtime_error(socket_error_string(m_Socket, "Socket bind error..."));
378  }
379 
380  void Listen(int _Backlog)
381  {
382  if (::listen(m_Socket, _Backlog) < 0)
383  throw std::runtime_error(socket_error_string(m_Socket, "can't call listen on socket server"));
384  }
385 
387  {
388  return ::accept(m_Socket, NULL, NULL);
389  }
391  {
392  return m_Socket.get();
393  }
394  void setNonBlock(bool _val = true)
395  {
396  m_Socket.set_nonblock(_val);
397  }
399  {
400  return m_Socket.detach();
401  }
402 
403  protected:
405  };
412  {
413  public:
415  : m_Socket(AF_INET, SOCK_STREAM, 0)
416  {
417  }
418 
419  void connect(unsigned short _nPort, const std::string& _Addr)
420  {
421  if (m_Socket < 0)
422  throw std::runtime_error(
423  socket_error_string(m_Socket, "there was NULL socket given as a client socket to Connect"));
424 
425  sockaddr_in addr;
426  addr.sin_family = AF_INET;
427  addr.sin_port = htons(_nPort);
428  std::string ip;
429  host2ip(_Addr, &ip);
430  inet_aton(ip.c_str(), &addr.sin_addr);
431 
432  if (::connect(m_Socket, (struct sockaddr*)&addr, sizeof(addr)) < 0)
433  throw std::runtime_error(socket_error_string(m_Socket, "Can't connect to the server"));
434  }
435 
437  {
438  return m_Socket.get();
439  }
440  void setNonBlock(bool _val = true)
441  {
442  m_Socket.set_nonblock(_val);
443  }
445  {
446  return m_Socket.detach();
447  }
448 
449  protected:
451  };
458  {
459  bool operator()(Socket_t _socket, sockaddr_in* _addr) const
460  {
461  socklen_t size = sizeof(sockaddr);
462  return (getsockname(_socket, reinterpret_cast<sockaddr*>(_addr), &size) == -1) ? false : true;
463  }
464  };
471  {
472  bool operator()(Socket_t _socket, sockaddr_in* _addr) const
473  {
474  socklen_t size = sizeof(sockaddr);
475  return (getpeername(_socket, reinterpret_cast<sockaddr*>(_addr), &size) == -1) ? false : true;
476  }
477  };
484  template <class _Type>
486  {
487  _socket2string(Socket_t _Socket, std::string* _Str)
488  {
489  if (!_Str)
490  return;
491 
492  sockaddr_in addr;
493  if (!_Type()(_Socket, &addr))
494  return;
495 
496  std::string host;
497  ip2host(inet_ntoa(addr.sin_addr), &host);
498 
499  std::stringstream ss;
500  ss << host << ":" << ntohs(addr.sin_port);
501  *_Str = ss.str();
502  }
503  };
521  inline std::string socket_error_string(Socket_t _socket, const char* _strMsg)
522  {
523  std::string strSocket;
524  socket2string(_socket, &strSocket);
525  std::string strSocketPeer;
526  peer2string(_socket, &strSocketPeer);
527  std::string sErr;
528  dds::misc::errno2str(&sErr);
529 
530  std::ostringstream ss;
531  if (_strMsg)
532  {
533  ss << _strMsg << "\n";
534  }
535  ss << "Error on Socket<" << strSocket << ">";
536 
537  if (!strSocketPeer.empty())
538  {
539  ss << "and peer <" << strSocketPeer << ">";
540  }
541  ss << ": " << sErr;
542 
543  return ss.str();
544  }
550  inline int get_free_port(int _Min, int _Max)
551  {
552  CSocketServer serv;
553  for (int i = _Min; i <= _Max; ++i)
554  {
555  try
556  {
557  serv.Bind(i);
558  return i;
559  }
560  catch (...)
561  {
562  continue;
563  }
564  }
565  return 0;
566  }
572  inline int get_free_port(int _Port)
573  {
574  CSocketServer serv;
575  try
576  {
577  serv.Bind(_Port);
578  return _Port;
579  }
580  catch (...)
581  {
582  }
583  return 0;
584  }
585 
586 // some old Linux systems don't have ntohll and htonll
587 #ifndef ntohll
588  inline uint64_t htonll(uint64_t val)
589  {
590  return (((uint64_t)htonl(val)) << 32) + htonl(val >> 32);
591  }
592 
593  inline uint64_t ntohll(uint64_t val)
594  {
595  return (((uint64_t)ntohl(val)) << 32) + ntohl(val >> 32);
596  }
597 #endif
598  // The following 4 functions convert values between host and network byte order.
599  // Whenever data should be send to a remote peer the _normalizeWrite must be used.
600  // Whenever data are going to be read from the _normalizeRead must be used to check that Endianness is correct.
601  template <typename T>
602  T normalizeRead(T _value);
603 
604  template <>
605  inline uint16_t normalizeRead<uint16_t>(uint16_t _value)
606  {
607  return ntohs(_value);
608  }
609 
610  template <>
611  inline uint32_t normalizeRead<uint32_t>(uint32_t _value)
612  {
613  return ntohl(_value);
614  }
615 
616  template <>
617  inline uint64_t normalizeRead<uint64_t>(uint64_t _value)
618  {
619  return ntohll(_value);
620  }
621 
622  template <typename T>
623  T normalizeWrite(T _value);
624 
625  template <>
626  inline uint16_t normalizeWrite<uint16_t>(uint16_t _value)
627  {
628  return htons(_value);
629  }
630 
631  template <>
632  inline uint32_t normalizeWrite<uint32_t>(uint32_t _value)
633  {
634  return htonl(_value);
635  }
636 
637  template <>
638  inline uint64_t normalizeWrite<uint64_t>(uint64_t _value)
639  {
640  return htonll(_value);
641  }
642 
648  inline void writeall(int _handle, const std::string& _msg)
649  {
650  size_t total = 0;
651  int n = 0;
652 
653  std::vector<char> buf;
654  buf.reserve(_msg.size());
655  copy(_msg.begin(), _msg.end(), back_inserter(buf));
656 
657  const size_t len = buf.size();
658 
659  while (total < len)
660  {
661  if ((n = write(_handle, &buf[total], len - total)) < 0)
662  throw system_error("send command: Write error");
663  total += n;
664  }
665  }
666  }; // namespace INet
667 }; // namespace dds::misc
668 
669 #endif
smart_socket m_Socket
Definition: INet.h:450
Definition: MiscUtils.h:219
int get_free_port(int _Min, int _Max)
The function checks and returns a free port from the given range of the ports.
Definition: INet.h:550
_socket2string< SSocketPeer2String_Trait > peer2string
Socket-peer to string representation.
Definition: INet.h:515
T normalizeWrite(T _value)
uint64_t ntohll(uint64_t val)
Definition: INet.h:593
int is_read_ready(size_t m_SecTimeOut, size_t m_USecTimeOut=0)
This function indicates that socket is ready to be read (for non-blocking sockets)
Definition: INet.h:129
void setNonBlock(bool _val=true)
Definition: INet.h:440
CSocketServer()
Definition: INet.h:359
smart_socket & operator<<(smart_socket &_Socket, _T &_Buf)
This is a stream operator which helps to send data to the given socket.
Socket_t detach()
Definition: INet.h:444
A Trait class for _socket2string template. This class operates on a local side of the socket.
Definition: INet.h:457
CSocketClient()
Definition: INet.h:414
#define INVALID_SOCKET
this macro indicates an invalid status of the socket
Definition: INet.h:28
void ip2host(const std::string &_IP, std::string *_Host)
ip2host converts a given IP address to host name.
Definition: INet.h:332
int operator=(const int &_Val)
Definition: INet.h:85
void send_string(smart_socket &_Socket, const std::string &_Str2Send)
A helper function, which sends a string to the given socket.
Definition: INet.h:273
bool operator()(Socket_t _socket, sockaddr_in *_addr) const
Definition: INet.h:459
_socket2string< SSocket2String_Trait > socket2string
Socket to string representation.
Definition: INet.h:509
smart_socket()
Definition: INet.h:58
std::string socket_error_string(Socket_t _socket, const char *_strMsg=NULL)
The function returns socket's error string.
Definition: INet.h:521
void host2ip(const std::string &_Host, std::string *_IP)
host2ip converts a given host name to IP address.
Definition: INet.h:310
void connect(unsigned short _nPort, const std::string &_Addr)
Definition: INet.h:419
T normalizeRead(T _value)
Socket_t get()
Definition: INet.h:96
A Trait class for _socket2string template. This class operates a peer of the socket.
Definition: INet.h:470
int sendall(int s, const unsigned char *const buf, int len, int flags)
A helper function, which insures that whole buffer was send.
Definition: INet.h:218
int Socket_t
A basic socket type.
Definition: INet.h:44
~smart_socket()
Definition: INet.h:73
smart_socket & operator>>(smart_socket &_Socket, _T *_Buf)
This is a stream operator which helps to receive data from the given socket.
uint16_t normalizeRead< uint16_t >(uint16_t _value)
Definition: INet.h:605
Socket_t Accept()
Definition: INet.h:386
std::vector< unsigned char > BYTEVector_t
An STL vector of bytes.
Definition: def.h:124
smart_socket(int _domain, int _type, int _protocol, bool _Block=false)
Definition: INet.h:66
Socket_t detach()
Definition: INet.h:90
void close()
Definition: INet.h:111
uint64_t normalizeRead< uint64_t >(uint64_t _value)
Definition: INet.h:617
bool is_ip_address(std::string _Addr)
This function checks whether _Addr is an IP address or not.
Definition: INet.h:298
void setNonBlock(bool _val=true)
Definition: INet.h:394
uint64_t htonll(uint64_t val)
Definition: INet.h:588
bool operator()(Socket_t _socket, sockaddr_in *_addr) const
Definition: INet.h:472
int errno2str(std::string *_msg)
Retrieves a string, which represent the last error.
Definition: ErrorCode.h:49
void Bind(unsigned short _nPort, const std::string *_Addr=NULL)
Definition: INet.h:363
Socket_t detach()
Definition: INet.h:398
#define _T(s)
Use TCHAR instead of char or wchar_t. It will be appropriately translated.
Definition: def.h:82
The system_error exception class retrieves a string, which represent the last error.
Definition: ErrorCode.h:76
bool is_valid() const
Definition: INet.h:120
A wrapper for a basic Socket.
Definition: INet.h:54
Socket_t getSocket()
Definition: INet.h:390
void receive_string(smart_socket &_Socket, std::string *_Str2Receive, size_t _BufSize)
A helper function, which receives a string from the given socket.
Definition: INet.h:284
uint32_t normalizeWrite< uint32_t >(uint32_t _value)
Definition: INet.h:632
smart_socket(int _Socket)
Definition: INet.h:62
int shutdown(int _How=SHUT_RDWR)
Definition: INet.h:124
void writeall(int _handle, const std::string &_msg)
A helper function, which insures that whole buffer was written.
Definition: INet.h:648
Class which makes child to be non-copyable object.
Definition: MiscUtils.h:28
uint16_t normalizeWrite< uint16_t >(uint16_t _value)
Definition: INet.h:626
CSocketClient implements a simple socket client.
Definition: INet.h:411
void Listen(int _Backlog)
Definition: INet.h:380
_socket2string(Socket_t _Socket, std::string *_Str)
Definition: INet.h:487
uint32_t normalizeRead< uint32_t >(uint32_t _value)
Definition: INet.h:611
size_t read_from_socket(smart_socket &_Socket, BYTEVector_t *_Buf)
Definition: INet.h:156
Socket_t getSocket()
Definition: INet.h:436
uint64_t normalizeWrite< uint64_t >(uint64_t _value)
Definition: INet.h:638
A template class, which makes a string representation of the socket.
Definition: INet.h:485
int set_nonblock(bool _val=true)
Definition: INet.h:100
smart_socket m_Socket
Definition: INet.h:404
CSocketServer implements a simple socket server.
Definition: INet.h:356
Definition: BoostHelper.h:14