Goby3 3.2.3
2025.05.13
Loading...
Searching...
No Matches
iridium_shore_sbd_directip.h
Go to the documentation of this file.
1// Copyright 2015-2025:
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_SBD_DIRECTIP_H
25#define GOBY_ACOMMS_MODEMDRIVER_IRIDIUM_SHORE_SBD_DIRECTIP_H
26
27#include <boost/asio.hpp>
28#include <boost/bind/bind.hpp>
29#include <boost/enable_shared_from_this.hpp>
30
33#include "goby/time.h"
35#include "goby/util/binary.h"
37
38namespace goby
39{
40namespace acomms
41{
42namespace directip
43{
44
46{
47 public:
48 SBDMessageReader(boost::asio::ip::tcp::socket& socket)
49 : socket_(socket), pos_(0), data_(1 << 16)
50 {
51 }
52
53 virtual bool data_ready() const = 0;
54
56 {
57 return pre_header_;
58 }
62 {
63 return confirm_;
64 }
65
66 enum
67 {
70 };
71
72 void pre_header_handler(const boost::system::error_code& error, std::size_t bytes_transferred)
73 {
74 if (error)
75 throw std::runtime_error("Error while reading: " + error.message());
76
77 pre_header_.set_protocol_ver(read_byte());
78 pre_header_.set_overall_length(read_uint16());
79
80 boost::asio::async_read(socket_, boost::asio::buffer(data_),
81 boost::asio::transfer_at_least(pre_header_.overall_length() +
82 PRE_HEADER_SIZE - bytes_transferred),
83 boost::bind(&SBDMessageReader::ie_handler, this,
84 boost::placeholders::_1, boost::placeholders::_2));
85 }
86
87 std::vector<char>& data() { return data_; }
88
89 private:
90 void ie_handler(const boost::system::error_code& error, std::size_t bytes_transferred)
91 {
92 if (error)
93 throw std::runtime_error("Error while reading: " + error.message());
94
95 char iei = read_byte();
96 unsigned length = read_uint16();
97
98 switch (iei)
99 {
100 case 0x01: // header
101 {
102 header_.set_iei(iei);
103 header_.set_length(length);
104 header_.set_cdr_reference(read_uint32()); // 4 bytes
105
106 header_.set_imei(read_imei()); // 15 bytes
107
108 header_.set_session_status(read_byte()); // 1 byte
109 header_.set_momsn(read_uint16()); // 2 bytes
110 header_.set_mtmsn(read_uint16()); // 2 bytes
111 header_.set_time_of_session(read_uint32()); // 4 bytes
112 }
113 break;
114
115 case 0x02: // payload
116 body_.set_iei(iei);
117 body_.set_length(length);
118 body_.set_payload(std::string(data_.begin() + pos_, data_.begin() + pos_ + length));
119 pos_ += length;
120 break;
121
122 case 0x44: // confirmation
123 confirm_.set_iei(iei);
124 confirm_.set_length(length);
125 confirm_.set_client_id(read_uint32());
126 confirm_.set_imei(read_imei());
127 confirm_.set_auto_ref_id(read_uint32());
128 confirm_.set_status(read_int16());
129
130 default: // skip this IE
131 pos_ += length;
132 break;
133 }
134
135 if (pos_ < pre_header_.overall_length() + PRE_HEADER_SIZE)
136 ie_handler(error, bytes_transferred);
137 }
138
139 char read_byte() { return data_.at(pos_++) & 0xff; }
140
141 unsigned read_uint16()
142 {
143 unsigned u = (data_.at(pos_++) & 0xff) << BITS_PER_BYTE;
144 u |= data_.at(pos_++) & 0xff;
145 return u;
146 }
147
148 int read_int16()
149 {
150 int i = (data_.at(pos_++) & 0xff) << BITS_PER_BYTE;
151 i |= data_.at(pos_++) & 0xff;
152
153 // sign extend
154 int sign_bit_mask = 0x8000;
155 if (i & sign_bit_mask)
156 i |= (-1 - 0xFFFF); // extend bits to fill int
157
158 return i;
159 }
160
161 unsigned read_uint32()
162 {
163 unsigned u = 0;
164 for (int i = 0; i < 4; ++i) u |= (data_.at(pos_++) & 0xff) << ((3 - i) * BITS_PER_BYTE);
165 return u;
166 }
167
168 std::string read_imei()
169 {
170 const int imei_size = 15;
171 std::string imei = std::string(data_.begin() + pos_, data_.begin() + pos_ + imei_size);
172 pos_ += imei_size;
173 return imei;
174 }
175
176 private:
181
182 boost::asio::ip::tcp::socket& socket_;
183
184 std::vector<char>::size_type pos_;
185 std::vector<char> data_;
186};
187
189{
190 public:
191 SBDMOMessageReader(boost::asio::ip::tcp::socket& socket) : SBDMessageReader(socket) {}
192
193 bool data_ready() const
194 {
196 }
197};
198
200{
201 public:
202 SBDMTConfirmationMessageReader(boost::asio::ip::tcp::socket& socket) : SBDMessageReader(socket)
203 {
204 }
205
206 bool data_ready() const { return pre_header().IsInitialized() && confirm().IsInitialized(); }
207};
208
209class SBDConnection : public boost::enable_shared_from_this<SBDConnection>
210{
211 public:
212 static std::shared_ptr<SBDConnection> create(
214 boost::asio::io_service& executor)
215#else
216 const boost::asio::ip::tcp::socket::executor_type& executor)
217#endif
218 {
219 return std::shared_ptr<SBDConnection>(new SBDConnection(executor));
220 }
221
222 boost::asio::ip::tcp::socket& socket() { return socket_; }
223
224 void start()
225 {
226 remote_endpoint_str_ = boost::lexical_cast<std::string>(socket_.remote_endpoint());
227
228 connect_time_ = time::SystemClock::now().time_since_epoch() / std::chrono::seconds(1);
229 boost::asio::async_read(socket_, boost::asio::buffer(message_.data()),
230 boost::asio::transfer_at_least(SBDMessageReader::PRE_HEADER_SIZE),
231 boost::bind(&SBDMessageReader::pre_header_handler, &message_,
232 boost::placeholders::_1, boost::placeholders::_2));
233 }
234
236
237 double connect_time() const { return connect_time_; }
238
239 const SBDMOMessageReader& message() const { return message_; }
240 const std::string& remote_endpoint_str() { return remote_endpoint_str_; }
241
242 private:
245 boost::asio::io_service& executor)
246#else
247 const boost::asio::ip::tcp::socket::executor_type& executor)
248#endif
249 : socket_(executor), connect_time_(-1), message_(socket_), remote_endpoint_str_("Unknown")
250 {
251 }
252
253 boost::asio::ip::tcp::socket socket_;
254 double connect_time_;
255 SBDMOMessageReader message_;
256 std::string remote_endpoint_str_;
257};
258
260{
261 public:
262 SBDServer(boost::asio::io_context& io_context, int port, bool ipv6)
263 : acceptor_(io_context,
264 boost::asio::ip::tcp::endpoint(
265 ipv6 ? boost::asio::ip::tcp::v6() : boost::asio::ip::tcp::v4(), port))
266 {
267 start_accept();
268 }
269
270 std::set<std::shared_ptr<SBDConnection>>& connections() { return connections_; }
271
272 private:
273 void start_accept()
274 {
275 std::shared_ptr<SBDConnection> new_connection =
276#ifdef USE_BOOST_IO_SERVICE
277 SBDConnection::create(acceptor_.get_io_service());
278#else
279 SBDConnection::create(acceptor_.get_executor());
280#endif
281 connections_.insert(new_connection);
282
283 acceptor_.async_accept(new_connection->socket(),
284 boost::bind(&SBDServer::handle_accept, this, new_connection,
285 boost::asio::placeholders::error));
286 }
287
288 void handle_accept(std::shared_ptr<SBDConnection> new_connection,
289 const boost::system::error_code& error)
290 {
291 if (!error)
292 {
293 using namespace goby::util::logger;
294 using goby::glog;
295
296 glog.is(DEBUG1) && glog << "Received SBD connection from: "
297 << new_connection->socket().remote_endpoint() << std::endl;
298
299 new_connection->start();
300 }
301
302 start_accept();
303 }
304
305 std::set<std::shared_ptr<SBDConnection>> connections_;
306 boost::asio::ip::tcp::acceptor acceptor_;
307};
308
309} // namespace directip
310} // namespace acomms
311} // namespace goby
312
313#endif
#define USE_BOOST_IO_SERVICE
Definition asio_compat.h:33
static std::shared_ptr< SBDConnection > create(const boost::asio::ip::tcp::socket::executor_type &executor)
const SBDMOMessageReader & message() const
SBDMOMessageReader(boost::asio::ip::tcp::socket &socket)
SBDMTConfirmationMessageReader(boost::asio::ip::tcp::socket &socket)
SBDMessageReader(boost::asio::ip::tcp::socket &socket)
const goby::acomms::iridium::protobuf::DirectIPMOHeader & header() const
const goby::acomms::iridium::protobuf::DirectIPMOPayload & body() const
const goby::acomms::iridium::protobuf::DirectIPMTConfirmation & confirm() const
const goby::acomms::iridium::protobuf::DirectIPMOPreHeader & pre_header() const
void pre_header_handler(const boost::system::error_code &error, std::size_t bytes_transferred)
SBDServer(boost::asio::io_context &io_context, int port, bool ipv6)
std::set< std::shared_ptr< SBDConnection > > & connections()
void set_imei(ArgT0 &&arg0, ArgT... args)
void set_payload(ArgT0 &&arg0, ArgT... args)
bool is(goby::util::logger::Verbosity verbosity)
The global namespace for the Goby project.
util::FlexOstream glog
Access the Goby logger through this object.
static time_point now() noexcept
Returns the current system time unless SimulatorSettings::using_sim_time is set to true,...