DESERT 4.0.0
position_listener.h
Go to the documentation of this file.
1//
2// Copyright (c) 2017 Regents of the SIGNET lab, University of Padova.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions
7// are met:
8// 1. Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright
11// notice, this list of conditions and the following disclaimer in the
12// documentation and/or other materials provided with the distribution.
13// 3. Neither the name of the University of Padova (SIGNET lab) nor the
14// names of its contributors may be used to endorse or promote products
15// derived from this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
39#ifndef _POSITION_LISTENER_H_
40#define _POSITION_LISTENER_H_
41
42#include <arpa/inet.h>
43#include <netinet/in.h>
44#include <sys/socket.h>
45#include <sys/time.h>
46#include <unistd.h>
47#define SOCKET_TYPE int
48#define SET_SOCKOPT_TYPE void *
49#define SENDTO_TYPE const char *
50#define SOCKET_ERROR -1
51
52#include <cstring>
53#include <stdexcept>
54#include <vector>
55
56#include "logging.h"
57#include "position_data.h"
58#include "stoppable_thread.h"
59
63template <typename Owner> class PositionListener : public StoppableThread
64{
65public:
66 PositionListener(Owner *owner, uint16_t port, timeval read_timeout)
67 {
68 p_Owner = owner;
69 m_Port = port;
70 m_ReadTimeout = read_timeout;
71 }
73 {
74 if (m_SocketFD)
75 ::close(m_SocketFD);
76 }
78 virtual void
80 {
81 try {
82 if (p_Owner->debugLevel() > 0)
83 LOG_MSG_INFO(
84 "Starting position data listener on port " << m_Port);
85 // set up socket....
86 m_SocketFD = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
87 if (m_SocketFD < 0)
88 throw std::runtime_error(
89 "PositionListener::ListenLoop()::socket()");
90
91 // allow to reuse the address
92 int reuse = 1;
93 if (setsockopt(m_SocketFD,
94 SOL_SOCKET,
95 SO_REUSEADDR,
96 (SET_SOCKOPT_TYPE) &reuse,
97 sizeof(reuse)) == -1)
98 throw std::runtime_error(
99 "PositionListener::ListenLoop::setsockopt::reuse");
100
101 // setup receive buffer to be large enough
102 int rx_buffer_size = 1024;
103 if (setsockopt(m_SocketFD,
104 SOL_SOCKET,
105 SO_RCVBUF,
106 (SET_SOCKOPT_TYPE) &rx_buffer_size,
107 sizeof(rx_buffer_size)) == -1)
108 throw std::runtime_error(
109 "PositionListener::ListenLoop()::setsockopt::rcvbuf");
110
111 // construct a datagram address structure
112 struct sockaddr_in dg_addr;
113 memset(&dg_addr, 0, sizeof(dg_addr));
114 dg_addr.sin_family = AF_INET;
115 // listen on any address
116 dg_addr.sin_addr.s_addr = htonl(INADDR_ANY);
117 dg_addr.sin_port = htons(m_Port);
118
119 if (bind(m_SocketFD,
120 (struct sockaddr *) &dg_addr,
121 sizeof(dg_addr)) == -1)
122 throw std::runtime_error(
123 "PositionListener::ListenLoop()::bind");
124
125 // reserve receive buffer, make it large enough (2 * serialized size
126 // for now)
127 PositionData pd;
128 std::vector<char> incoming_buffer(pd.size() * 2);
129 while (!StopRequested()) {
130 if (ReadyToRead()) {
131 if (p_Owner->debugLevel() >= 3)
132 LOG_MSG_INFO("Trying to read data from peer");
133 int num_bytes_read = recvfrom(m_SocketFD,
134 (char *) incoming_buffer.data(),
135 (int) incoming_buffer.size(),
136 0,
137 0,
138 0);
139 if (num_bytes_read < 0) {
140 LOG_MSG_ERROR("Error reading from UDP port: "
141 << num_bytes_read);
142 continue;
143 }
144 if (p_Owner->debugLevel() >= 3)
145 LOG_MSG_INFO("Received " << num_bytes_read
146 << " bytes from peer");
147 try {
148 pd.deserialize(
149 incoming_buffer.data(), incoming_buffer.size());
150 p_Owner->setPosition(pd);
151 } catch (const std::exception &e) {
152 LOG_MSG_ERROR(
153 "Caught exception while reading position data: "
154 << e.what() << " - " << std::strerror(errno));
155 }
156 }
157 }
158 if (p_Owner->debugLevel() > 0)
159 LOG_MSG_INFO(
160 "Stopping position data listener on port " << m_Port);
161 } catch (const std::exception &e) {
162 LOG_MSG_ERROR("Caught exception in listening thread: "
163 << e.what() << " - " << std::strerror(errno));
164 }
165 }
166
167protected:
171 bool
173 {
174 int nfds;
175 fd_set fdset;
176
177 FD_ZERO(&fdset);
178 FD_SET(m_SocketFD, &fdset);
179
180 nfds = (int) m_SocketFD;
181 int ret = select(nfds + 1, &fdset, NULL, NULL, &m_ReadTimeout);
182 if (ret == SOCKET_ERROR) {
183 LOG_MSG_ERROR("Error on select: " << ret);
184 }
185 return ret == 1;
186 }
188 SOCKET_TYPE m_SocketFD{0};
192 uint16_t m_Port;
194 Owner *p_Owner;
195};
196
197#endif // _POSITION_LISTENER_H_
Definition position_listener.h:64
bool ReadyToRead()
Definition position_listener.h:172
virtual void Run()
Definition position_listener.h:79
virtual ~PositionListener()
Definition position_listener.h:72
SOCKET_TYPE m_SocketFD
Definition position_listener.h:188
timeval m_ReadTimeout
Definition position_listener.h:190
uint16_t m_Port
Definition position_listener.h:192
Owner * p_Owner
Definition position_listener.h:194
PositionListener(Owner *owner, uint16_t port, timeval read_timeout)
Definition position_listener.h:66
Definition stoppable_thread.h:50
bool StopRequested()
Definition stoppable_thread.h:127
Provides the definition of PositionData struct.
Provides the definition of PositionData struct.
Provides a simple C++11 thread the StoppableThread class.
Definition position_data.h:56
constexpr size_t size() const
Definition position_data.h:68
bool deserialize(char *buffer, size_t buffer_size)
Definition position_data.h:100