Goby3 3.1.5a
2024.05.23
Loading...
Searching...
No Matches
iridium_shore_rudics.h
Go to the documentation of this file.
1// Copyright 2015-2023:
2// GobySoft, LLC (2013-)
3// Community contributors (see AUTHORS file)
4// File authors:
5// Toby Schneider <toby@gobysoft.org>
6//
7//
8// This file is part of the Goby Underwater Autonomy Project Libraries
9// ("The Goby Libraries").
10//
11// The Goby Libraries are free software: you can redistribute them and/or modify
12// them under the terms of the GNU Lesser General Public License as published by
13// the Free Software Foundation, either version 2.1 of the License, or
14// (at your option) any later version.
15//
16// The Goby Libraries are distributed in the hope that they will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public License
22// along with Goby. If not, see <http://www.gnu.org/licenses/>.
23
24#ifndef GOBY_ACOMMS_MODEMDRIVER_IRIDIUM_SHORE_RUDICS_H
25#define GOBY_ACOMMS_MODEMDRIVER_IRIDIUM_SHORE_RUDICS_H
26
28#include <boost/asio.hpp>
29
30#include <boost/bind/bind.hpp>
31#include <boost/signals2.hpp>
32
33#include "goby/time.h"
34#include "goby/util/binary.h"
36
37namespace goby
38{
39namespace acomms
40{
41class RUDICSConnection : public std::enable_shared_from_this<RUDICSConnection>
42{
43 public:
44 static std::shared_ptr<RUDICSConnection> create(
46 boost::asio::io_service& executor)
47#else
48 const boost::asio::ip::tcp::socket::executor_type& executor)
49#endif
50 {
51 return std::shared_ptr<RUDICSConnection>(new RUDICSConnection(executor));
52 }
53
54 boost::asio::ip::tcp::socket& socket() { return socket_; }
55
56 void start()
57 {
58 remote_endpoint_str_ = boost::lexical_cast<std::string>(socket_.remote_endpoint());
59 read_start();
60 }
61
62 void close()
63 {
64 socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
65 socket_.close();
66 }
67
69 {
70 boost::asio::async_read_until(socket_, buffer_, '\r',
71 boost::bind(&RUDICSConnection::handle_read, this, boost::placeholders::_1, boost::placeholders::_2));
72 }
73
74 void write_start(const std::string& data)
75 {
76 boost::asio::async_write(socket_, boost::asio::buffer(data),
77 boost::bind(&RUDICSConnection::handle_write, this, boost::placeholders::_1, boost::placeholders::_2));
78 }
79
81 {
82 using goby::glog;
84 glog.is(DEBUG1) && glog << "Disconnecting from: " << remote_endpoint_str_ << std::endl;
85 }
86
88 {
89 using goby::glog;
91 const int max_packet_failures = 3;
92 if (++packet_failures_ >= max_packet_failures)
93 {
94 glog.is(DEBUG1) && glog << "More than " << max_packet_failures << " bad RUDICS packets."
95 << std::endl;
96 close();
97 }
98 }
99
100 boost::signals2::signal<void(const std::string& line,
101 std::shared_ptr<RUDICSConnection> connection)>
103 boost::signals2::signal<void(std::shared_ptr<RUDICSConnection> connection)> disconnect_signal;
104
105 const std::string& remote_endpoint_str() { return remote_endpoint_str_; }
106
107 private:
110 boost::asio::io_service& executor)
111#else
112 const boost::asio::ip::tcp::socket::executor_type& executor)
113#endif
114 : socket_(executor), remote_endpoint_str_("Unknown"), packet_failures_(0)
115 {
116 }
117
118 void handle_write(const boost::system::error_code& error, size_t bytes_transferred)
119 {
120 if (error)
121 {
122 using goby::glog;
124 glog.is(WARN) && glog << "Error writing to TCP connection: " << error << std::endl;
125 disconnect_signal(shared_from_this());
126 }
127 }
128
129 void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
130 {
131 using goby::glog;
134 if (!error)
135 {
136 std::istream istrm(&buffer_);
137 std::string line;
138 std::getline(istrm, line, '\r');
139 line_signal(line + "\r", shared_from_this());
140 read_start();
141 }
142 else
143 {
144 if (error == boost::asio::error::eof)
145 {
146 glog.is(DEBUG1) && glog << "Connection reached EOF" << std::endl;
147 }
148 else if (error == boost::asio::error::operation_aborted)
149 {
150 glog.is(DEBUG1) && glog << "Read operation aborted (socket closed)" << std::endl;
151 }
152 else
153 {
154 glog.is(WARN) && glog << "Error reading from TCP connection: " << error
155 << std::endl;
156 }
157
158 disconnect_signal(shared_from_this());
159 }
160 }
161
162 private:
163 boost::asio::ip::tcp::socket socket_;
164 boost::asio::streambuf buffer_;
165 std::string remote_endpoint_str_;
166 int packet_failures_;
167};
168
170{
171 public:
173 : acceptor_(io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
174 {
175 start_accept();
176 }
177
178 std::set<std::shared_ptr<RUDICSConnection> >& connections() { return connections_; }
179
180 boost::signals2::signal<void(std::shared_ptr<RUDICSConnection> connection)> connect_signal;
181
182 void disconnect(std::shared_ptr<RUDICSConnection> connection) { connection->close(); }
183
184 private:
185 void start_accept()
186 {
187 std::shared_ptr<RUDICSConnection> new_connection =
188#ifdef USE_BOOST_IO_SERVICE
189 RUDICSConnection::create(acceptor_.get_io_service());
190#else
191 RUDICSConnection::create(acceptor_.get_executor());
192#endif
193 acceptor_.async_accept(new_connection->socket(),
194 boost::bind(&RUDICSServer::handle_accept, this, new_connection,
195 boost::asio::placeholders::error));
196 }
197
198 void handle_accept(std::shared_ptr<RUDICSConnection> new_connection,
199 const boost::system::error_code& error)
200 {
201 if (!error)
202 {
203 using namespace goby::util::logger;
204 using goby::glog;
205
206 connections_.insert(new_connection);
207
208 new_connection->disconnect_signal.connect(
209 boost::bind(&RUDICSServer::handle_disconnect, this, boost::placeholders::_1));
210 connect_signal(new_connection);
211 new_connection->start();
212 glog.is(DEBUG1) && glog << "Received connection from: "
213 << new_connection->remote_endpoint_str() << std::endl;
214 }
215
216 start_accept();
217 }
218
219 void handle_disconnect(std::shared_ptr<RUDICSConnection> connection)
220 {
221 using goby::glog;
223
224 connections_.erase(connection);
225
226 glog.is(DEBUG1) &&
227 glog << "Server removing connection: " << connection->remote_endpoint_str()
228 << ". Remaining connection count: " << connections_.size() << std::endl;
229 }
230
231 std::set<std::shared_ptr<RUDICSConnection> > connections_;
232 boost::asio::ip::tcp::acceptor acceptor_;
233};
234
235} // namespace acomms
236} // namespace goby
237
238#endif
#define USE_BOOST_IO_SERVICE
Definition asio_compat.h:33
const std::string & remote_endpoint_str()
static std::shared_ptr< RUDICSConnection > create(const boost::asio::ip::tcp::socket::executor_type &executor)
boost::signals2::signal< void(const std::string &line, std::shared_ptr< RUDICSConnection > connection)> line_signal
boost::signals2::signal< void(std::shared_ptr< RUDICSConnection > connection)> disconnect_signal
void write_start(const std::string &data)
boost::asio::ip::tcp::socket & socket()
RUDICSServer(boost::asio::io_context &io_context, int port)
void disconnect(std::shared_ptr< RUDICSConnection > connection)
std::set< std::shared_ptr< RUDICSConnection > > & connections()
boost::signals2::signal< void(std::shared_ptr< RUDICSConnection > connection)> connect_signal
bool is(goby::util::logger::Verbosity verbosity)
@ error
throw a parse_error exception in case of a tag
The global namespace for the Goby project.
util::FlexOstream glog
Access the Goby logger through this object.