clockUtils  1.1
TcpSocket.h
Go to the documentation of this file.
1 /*
2  * clockUtils
3  * Copyright (2015) Michael Baer, Daniel Bonrath, All rights reserved.
4  *
5  * This file is part of clockUtils; clockUtils is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
25 #ifndef __CLOCKUTILS_SOCKETS_TCPSOCKET_H__
26 #define __CLOCKUTILS_SOCKETS_TCPSOCKET_H__
27 
28 #include <condition_variable>
29 #include <cstdint>
30 #include <functional>
31 #include <mutex>
32 #include <queue>
33 #include <sstream>
34 #include <string>
35 #include <vector>
36 
37 #include "clockUtils/errors.h"
38 
41 
42 #if CLOCKUTILS_PLATFORM == CLOCKUTILS_PLATFORM_WIN32
43  #include <WinSock2.h>
44 
45  typedef int32_t socklen_t;
46 #elif CLOCKUTILS_PLATFORM == CLOCKUTILS_PLATFORM_LINUX
47  #include <arpa/inet.h>
48  #include <cstring>
49  #include <fcntl.h>
50  #include <netdb.h>
51  #include <netinet/in.h>
52  #include <sys/socket.h>
53  #include <sys/types.h>
54  #include <unistd.h>
55 
56  typedef int SOCKET;
57  #define INVALID_SOCKET -1
58 #endif
59 
60 namespace std {
61  class thread;
62 } /* namespace std */
63 namespace clockUtils {
64  enum class ClockError;
65 namespace sockets {
66 
85  public:
89  typedef std::function<void(TcpSocket *, ClockError)> acceptCallback;
90 
94  typedef std::function<void(std::vector<uint8_t> packet, TcpSocket * socket, ClockError err)> packetCallback;
95 
99  TcpSocket();
100 
104  ~TcpSocket();
105 
113  ClockError listen(uint16_t listenPort, int maxParallelConnections, bool acceptMultiple, const acceptCallback acb);
114 
121  ClockError connectToIP(const std::string & remoteIP, uint16_t remotePort, unsigned int timeout) {
122  IPv4 ip = convertIP(remoteIP);
123  if (ip == NO_IP) {
124  // not a valid hostname
125  return ClockError::INVALID_IP;
126  }
127  return connect(ip, remotePort, timeout);
128  }
129 
136  ClockError connectToHostname(const std::string & remoteHostname, uint16_t remotePort, unsigned int timeout) {
137  IPv4 ip = resolveHostname(remoteHostname);
138  if (ip == NO_IP) {
139  // not a valid hostname
140  return ClockError::INVALID_IP;
141  }
142  return connect(ip, remotePort, timeout);
143  }
144 
151  ClockError connect(const IPv4 remoteIP, uint16_t remotePort, unsigned int timeout);
152 
156  void close();
157 
161  std::string getRemoteIP() const;
162 
166  uint16_t getRemotePort() const;
167 
171  static std::vector<std::pair<std::string, std::string>> enumerateLocalIPs();
172 
176  std::string getLocalIP() const;
177 
181  std::string getPublicIP() const;
182 
186  uint16_t getLocalPort() const;
187 
193  ClockError writePacket(const void * str, const size_t length);
194 
200  ClockError writePacket(const std::vector<uint8_t> & vec);
201 
207  ClockError writePacket(const std::string & str) {
208  return writePacket(str.c_str(), str.size());
209  }
210 
216  ClockError writePacketAsync(const void * str, const size_t length);
217 
223  ClockError writePacketAsync(const std::vector<uint8_t> & vec);
224 
230  ClockError writePacketAsync(const std::string & str) {
231  return writePacketAsync(std::vector<uint8_t>(str.begin(), str.end()));
232  }
233 
238  ClockError receivePacket(std::vector<uint8_t> & buffer);
239 
243  ClockError receivePacket(std::string & buffer);
244 
249  ClockError receiveCallback(packetCallback pcb);
250 
256  ClockError write(const void * str, size_t length);
257 
263  ClockError write(const std::vector<uint8_t> & vec);
264 
270  ClockError write(const std::string & str) {
271  return write(str.c_str(), str.length());
272  }
273 
279  ClockError writeAsync(const void * str, const size_t length);
280 
286  ClockError writeAsync(const std::vector<uint8_t> & vec);
287 
293  ClockError writeAsync(const std::string & str) {
294  return writeAsync(std::vector<uint8_t>(str.begin(), str.end()));
295  }
296 
300  template<class Container>
301  ClockError read(Container & buffer) {
302  if (_status != SocketStatus::CONNECTED) {
303  return ClockError::NOT_READY;
304  }
305 
306  buffer.resize(260);
307  int rc = -1;
308 
309  do {
310 #if CLOCKUTILS_PLATFORM == CLOCKUTILS_PLATFORM_LINUX
311  rc = recv(_sock, &buffer[0], 256, 0);
312 #elif CLOCKUTILS_PLATFORM == CLOCKUTILS_PLATFORM_WIN32
313  rc = recv(_sock, reinterpret_cast<char *>(&buffer[0]), 256, 0);
314 #endif
315 
316  if (rc == -1) {
317  ClockError error = getLastError();
318 
319  if (error == ClockError::IN_PROGRESS) {
320  continue;
321  }
322 
323  return error;
324  } else if (rc == 0) {
325  return ClockError::NOT_CONNECTED;
326  }
327  break;
328  } while (true);
329 
330  buffer.resize(size_t(rc));
331 
332  return ClockError::SUCCESS;
333  }
334 
339  template<typename T>
340  typename std::enable_if<std::is_enum<T>::value, TcpSocket &>::type operator<<(const T & a) {
341  std::stringstream ss;
342  ss << uint32_t(a);
343  writePacket(ss.str());
344  return *this;
345  }
346 
351  template<typename T>
352  typename std::enable_if<!std::is_enum<T>::value, TcpSocket &>::type operator<<(const T & a) {
353  std::stringstream ss;
354  ss << a;
355  writePacket(ss.str());
356  return *this;
357  }
358 
363  template<typename T>
364  typename std::enable_if<std::is_enum<T>::value, TcpSocket &>::type operator>>(T & a) {
365  std::string buffer;
366  receivePacket(buffer);
367  std::stringstream ss(buffer);
368  uint32_t e;
369  ss >> e;
370  a = T(e);
371  return *this;
372  }
373 
378  template<typename T>
379  typename std::enable_if<!std::is_enum<T>::value, TcpSocket &>::type operator>>(T & a) {
380  std::string buffer;
381  receivePacket(buffer);
382  std::stringstream ss(buffer);
383  ss >> a;
384  return *this;
385  }
386 
387  private:
391  enum class SocketStatus {
392  INACTIVE, //<! socket was only created, but is neither listening nor connected
393  LISTENING, //<! socket is listening on connections
394  CONNECTED //<! socket is connected to another socket
395  };
396 
400  SOCKET _sock;
401 
405  SocketStatus _status;
406 
410  std::mutex _writePacketAsyncLock;
411  std::mutex _writeAsyncLock;
412 
416  std::queue<std::vector<uint8_t>> _writePacketAsyncQueue;
417  std::queue<std::vector<uint8_t>> _writeAsyncQueue;
418 
422  std::vector<uint8_t> _buffer;
423 
424  bool _terminate;
425 
426  std::thread * _worker;
427  std::thread * _listenThread;
428 
429  std::condition_variable _condVar;
430  std::mutex _condMutex;
431 
432  std::thread * _callbackThread;
433 
438  TcpSocket(SOCKET fd);
439 
443  ClockError getLastError();
444 
448  void work();
449 
450  void closeSocket();
451 
452  void listenFunc(SOCKET sock, bool acceptMultiple, const acceptCallback acb);
453 
454  TcpSocket(const TcpSocket &) = delete;
455  TcpSocket & operator=(const TcpSocket &) = delete;
456  };
457 
461  template<>
462  CLOCK_SOCKETS_API TcpSocket & TcpSocket::operator<< <std::string>(const std::string & s);
463 
467  template<>
468  CLOCK_SOCKETS_API TcpSocket & TcpSocket::operator>> <std::string>(std::string & s);
469 
470 } /* namespace sockets */
471 } /* namespace clockUtils */
472 
473 #endif /* __CLOCKUTILS_SOCKETS_TCPSOCKET_H__ */
474 
ClockError writeAsync(const std::string &str)
sends a message asynchron, doesn&#39;t work with receivePacket See Writing to the socket ...
Definition: TcpSocket.h:293
std::enable_if<!std::is_enum< T >::value, TcpSocket & >::type operator>>(T &a)
receives a packet being sent using operator<< or writePacket(Async) T has to be streamable ...
Definition: TcpSocket.h:379
std::enable_if<!std::is_enum< T >::value, TcpSocket & >::type operator<<(const T &a)
sends parameter as a packet being receivable using operator>> or receivePacket T has to be streamable...
Definition: TcpSocket.h:352
class for sockets using tcp
Definition: TcpSocket.h:84
ClockError connectToHostname(const std::string &remoteHostname, uint16_t remotePort, unsigned int timeout)
creates a connection to the given pair of hostname and port
Definition: TcpSocket.h:136
Definition: TcpSocket.h:60
uint32_t IPv4
Definition: Commons.h:42
ClockError read(Container &buffer)
receives data on the socket
Definition: TcpSocket.h:301
#define CLOCK_SOCKETS_API
ClockError write(const std::string &str)
sends a message, doesn&#39;t work with receivePacket See Writing to the socket
Definition: TcpSocket.h:270
std::function< void(std::vector< uint8_t > packet, TcpSocket *socket, ClockError err)> packetCallback
this function type is used receiving a packet using receiveCallback and is called for every packet ...
Definition: TcpSocket.h:94
std::enable_if< std::is_enum< T >::value, TcpSocket & >::type operator<<(const T &a)
sends parameter as a packet being receivable using operator>> or receivePacket T is an enum value ...
Definition: TcpSocket.h:340
ClockError writePacket(const std::string &str)
sends a packet being able to be completely received in one call of receivePacket See Writing to the...
Definition: TcpSocket.h:207
std::function< void(TcpSocket *, ClockError)> acceptCallback
this function type is used as accept callback, so every accepted socket will reach this function on h...
Definition: TcpSocket.h:89
CLOCK_SOCKETS_API IPv4 convertIP(const std::string &ip)
converts an IP in the numbers-and-dots notation into an IPv4 integer
CLOCK_SOCKETS_API IPv4 resolveHostname(const std::string &hn)
returns the IP for a given hostname
int32_t socklen_t
Definition: TcpSocket.h:45
ClockError writePacketAsync(const std::string &str)
sends a packet being able to be completely received in one call of receivePacket See Writing to the...
Definition: TcpSocket.h:230
const IPv4 NO_IP
Definition: Commons.h:44
ClockError connectToIP(const std::string &remoteIP, uint16_t remotePort, unsigned int timeout)
creates a connection to the given pair of IP and port
Definition: TcpSocket.h:121
ClockError
Definition: errors.h:30
std::enable_if< std::is_enum< T >::value, TcpSocket & >::type operator>>(T &a)
receives a packet being sent using operator<< or writePacket(Async) T is an enum value ...
Definition: TcpSocket.h:364