clockUtils  1.1
UdpSocket.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_UDPSOCKET_H__
26 #define __CLOCKUTILS_SOCKETS_UDPSOCKET_H__
27 
28 #include <condition_variable>
29 #include <cstdint>
30 #include <functional>
31 #include <map>
32 #include <mutex>
33 #include <queue>
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 
47  // already defined by MSVC
48  // #define INVALID_SOCKET -1
49 #elif CLOCKUTILS_PLATFORM == CLOCKUTILS_PLATFORM_LINUX
50  #include <arpa/inet.h>
51  #include <cstring>
52  #include <fcntl.h>
53  #include <netdb.h>
54  #include <netinet/in.h>
55  #include <sys/socket.h>
56  #include <sys/types.h>
57  #include <unistd.h>
58 
59  typedef int SOCKET;
60  #define INVALID_SOCKET -1
61 #endif
62 
63 namespace std {
64  class thread;
65 } /* namespace std */
66 
67 namespace clockUtils {
68  enum class ClockError;
69 namespace sockets {
70 
75  public:
79  typedef std::function<void(std::vector<uint8_t> packet, std::string ip, uint16_t port, ClockError err)> packetCallback;
80 
84  const size_t MAX_PACKET_SIZE = 32 * 1024;
85 
89  UdpSocket();
90 
94  ~UdpSocket();
95 
99  ClockError bind(uint16_t port);
100 
104  void close();
105 
110  ClockError writePacket(IPv4 ip, uint16_t port, const void * str, const size_t length);
111 
116  ClockError writePacket(IPv4 ip, uint16_t port, const std::vector<uint8_t> & vec);
117 
122  ClockError writePacket(IPv4 ip, uint16_t port, const std::string & str) {
123  return writePacket(ip, port, str.c_str(), str.length());
124  }
125 
130  ClockError writePacketAsync(IPv4 ip, uint16_t port, const void * str, const size_t length);
131 
136  ClockError writePacketAsync(IPv4 ip, uint16_t port, const std::vector<uint8_t> & vec);
137 
142  ClockError writePacketAsync(IPv4 ip, uint16_t port, const std::string & str) {
143  return writePacketAsync(ip, port, std::vector<uint8_t>(str.begin(), str.end()));
144  }
145 
150  ClockError write(IPv4 ip, uint16_t port, const void * str, size_t length);
151 
156  ClockError write(IPv4 ip, uint16_t port, const std::vector<uint8_t> & vec) {
157  return write(ip, port, const_cast<const unsigned char *>(&vec[0]), vec.size());
158  }
159 
164  ClockError write(IPv4 ip, uint16_t port, const std::string & str) {
165  return write(ip, port, str.c_str(), str.length());
166  }
167 
172  ClockError writeAsync(IPv4 ip, uint16_t port, const void * str, size_t length);
173 
178  ClockError writeAsync(IPv4 ip, uint16_t port, const std::vector<uint8_t> & vec);
179 
184  ClockError writeAsync(IPv4 ip, uint16_t port, const std::string & str) {
185  return writeAsync(ip, port, std::vector<uint8_t>(str.begin(), str.end()));
186  }
191  template<typename... T>
192  ClockError writePacketToIP(const std::string & ip, uint16_t port, T... data) {
193  return writePacket(convertIP(ip), port, data...);
194  }
195 
200  template<typename... T>
201  ClockError writePacketToIPAsync(const std::string & ip, uint16_t port, T... data) {
202  return writePacketAsync(convertIP(ip), port, data...);
203  }
204 
209  template<typename... T>
210  ClockError writeToIP(const std::string & ip, uint16_t port, T... data) {
211  return write(convertIP(ip), port, data...);
212  }
213 
218  template<typename... T>
219  ClockError writeToIPAsync(const std::string & ip, uint16_t port, T... data) {
220  return writeAsync(convertIP(ip), port, data...);
221  }
222 
227  template<typename... T>
228  ClockError writePacketToHostname(const std::string & hostname, uint16_t port, T... data) {
229  return writePacket(resolveHostname(hostname), port, data...);
230  }
231 
236  template<typename... T>
237  ClockError writePacketToHostnameAsync(const std::string & hostname, uint16_t port, T... data) {
238  return writePacketAsync(resolveHostname(hostname), port, data...);
239  }
240 
245  template<typename... T>
246  ClockError writeToHostname(const std::string & hostname, uint16_t port, T... data) {
247  return write(resolveHostname(hostname), port, data...);
248  }
249 
254  template<typename... T>
255  ClockError writeToHostnameAsync(const std::string & hostname, uint16_t port, T... data) {
256  return writeAsync(resolveHostname(hostname), port, data...);
257  }
258 
266  ClockError receivePacket(std::vector<uint8_t> & buffer, std::string & ip, uint16_t & port);
267 
274  ClockError receivePacket(std::string & buffer, std::string & ip, uint16_t & port);
275 
280  ClockError receiveCallback(packetCallback pcb);
281 
285  template<class Container>
286  ClockError read(Container & buffer, std::string & ip, uint16_t & port) {
287  if (_sock == INVALID_SOCKET) {
288  return ClockError::NOT_READY;
289  }
290 
291  buffer.resize(MAX_PACKET_SIZE + 4);
292  int rc = -1;
293  struct sockaddr_in remaddr;
294  remaddr.sin_family = 0;
295  remaddr.sin_port = 0;
296  memset(&remaddr.sin_addr, 0, sizeof(remaddr.sin_addr));
297  memset(remaddr.sin_zero, 0, 8);
298  socklen_t addrlen = sizeof(remaddr);
299 
300  do {
301 #if CLOCKUTILS_PLATFORM == CLOCKUTILS_PLATFORM_LINUX
302  rc = recvfrom(_sock, &buffer[0], MAX_PACKET_SIZE, 0, (struct sockaddr *) &remaddr, &addrlen);
303 #elif CLOCKUTILS_PLATFORM == CLOCKUTILS_PLATFORM_WIN32
304  rc = recvfrom(_sock, reinterpret_cast<char *>(&buffer[0]), int(MAX_PACKET_SIZE), 0, (struct sockaddr *) &remaddr, &addrlen);
305 #endif
306 
307  port = static_cast<uint16_t>(ntohs(remaddr.sin_port));
308  ip = inet_ntoa(remaddr.sin_addr);
309 
310  if (rc == -1) {
311  ClockError error = getLastError();
312 
313  if (error == ClockError::IN_PROGRESS) {
314  continue;
315  }
316 
317  return error;
318  } else if (rc == 0) {
319  return ClockError::NOT_CONNECTED;
320  }
321 
322  break;
323  } while (true);
324 
325  buffer.resize(size_t(rc));
326 
327  return ClockError::SUCCESS;
328  }
329 
330  private:
334  SOCKET _sock;
335 
339  std::map<std::pair<std::string, uint16_t>, std::vector<uint8_t>> _buffer;
340 
344  std::thread * _callbackThread;
345 
349  std::mutex _writePacketAsyncLock;
350  std::mutex _writeAsyncLock;
351 
355  enum AsyncQueueInfo {
356  Message,
357  IP,
358  Port
359  };
360  std::queue<std::tuple<std::vector<uint8_t>, IPv4, uint16_t>> _writePacketAsyncQueue;
361  std::queue<std::tuple<std::vector<uint8_t>, IPv4, uint16_t>> _writeAsyncQueue;
362 
363  std::condition_variable _condVar;
364  std::mutex _condMutex;
365 
366  std::thread * _worker;
367 
368  bool _terminate;
369 
373  ClockError getLastError();
374 
375  void work();
376 
377  UdpSocket(const UdpSocket &) = delete;
378  UdpSocket & operator=(const UdpSocket &) = delete;
379  };
380 
381 } /* namespace sockets */
382 } /* namespace clockUtils */
383 
384 #endif /* __CLOCKUTILS_SOCKETS_UDPSOCKET_H__ */
385 
ClockError write(IPv4 ip, uint16_t port, const std::vector< uint8_t > &vec)
sends a packet, doesn&#39;t work with receivePacket
Definition: UdpSocket.h:156
ClockError writePacketToIP(const std::string &ip, uint16_t port, T... data)
sends a packet being able to be completely received in one call of receivePacket
Definition: UdpSocket.h:192
ClockError writePacketAsync(IPv4 ip, uint16_t port, const std::string &str)
sends a packet asynchronous being able to be completely received in one call of receivePacket ...
Definition: UdpSocket.h:142
ClockError writePacket(IPv4 ip, uint16_t port, const std::string &str)
sends a packet being able to be completely received in one call of receivePacket
Definition: UdpSocket.h:122
ClockError writeToIP(const std::string &ip, uint16_t port, T... data)
sends a packet, doesn&#39;t work with receivePacket
Definition: UdpSocket.h:210
ClockError write(IPv4 ip, uint16_t port, const std::string &str)
sends a packet, doesn&#39;t work with receivePacket
Definition: UdpSocket.h:164
ClockError writeToHostnameAsync(const std::string &hostname, uint16_t port, T... data)
sends a message asynchronous, doesn&#39;t work with receivePacket
Definition: UdpSocket.h:255
Definition: TcpSocket.h:60
uint32_t IPv4
Definition: Commons.h:42
#define CLOCK_SOCKETS_API
ClockError writePacketToHostnameAsync(const std::string &hostname, uint16_t port, T... data)
sends a packet asynchronous being able to be completely received in one call of receivePacket ...
Definition: UdpSocket.h:237
ClockError writeToIPAsync(const std::string &ip, uint16_t port, T... data)
sends a message asynchronous, doesn&#39;t work with receivePacket
Definition: UdpSocket.h:219
CLOCK_SOCKETS_API IPv4 convertIP(const std::string &ip)
converts an IP in the numbers-and-dots notation into an IPv4 integer
ClockError writePacketToHostname(const std::string &hostname, uint16_t port, T... data)
sends a packet being able to be completely received in one call of receivePacket
Definition: UdpSocket.h:228
CLOCK_SOCKETS_API IPv4 resolveHostname(const std::string &hn)
returns the IP for a given hostname
class for sockets using udp
Definition: UdpSocket.h:74
ClockError writeAsync(IPv4 ip, uint16_t port, const std::string &str)
sends a message asynchronous, doesn&#39;t work with receivePacket
Definition: UdpSocket.h:184
int32_t socklen_t
Definition: UdpSocket.h:45
ClockError read(Container &buffer, std::string &ip, uint16_t &port)
receives data on the socket
Definition: UdpSocket.h:286
ClockError writePacketToIPAsync(const std::string &ip, uint16_t port, T... data)
sends a packet asynchronous being able to be completely received in one call of receivePacket ...
Definition: UdpSocket.h:201
ClockError writeToHostname(const std::string &hostname, uint16_t port, T... data)
sends a packet, doesn&#39;t work with receivePacket
Definition: UdpSocket.h:246
std::function< void(std::vector< uint8_t > packet, std::string ip, uint16_t port, ClockError err)> packetCallback
this function type is used receiving a packet using receiveCallback and is called for every packet ...
Definition: UdpSocket.h:79
ClockError
Definition: errors.h:30