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