Goby3 3.5.1
2026.06.04
Loading...
Searching...
No Matches
iridium_shore_sbd_directip.h
Go to the documentation of this file.
1// Copyright 2015-2026:
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(
213 const boost::asio::ip::tcp::socket::executor_type& executor)
214 {
215 return std::shared_ptr<SBDConnection>(new SBDConnection(executor));
216 }
217
218 boost::asio::ip::tcp::socket& socket() { return socket_; }
219
220 void start()
221 {
222 remote_endpoint_str_ = boost::lexical_cast<std::string>(socket_.remote_endpoint());
223
224 connect_time_ = time::SystemClock::now().time_since_epoch() / std::chrono::seconds(1);
225 boost::asio::async_read(socket_, boost::asio::buffer(message_.data()),
226 boost::asio::transfer_at_least(SBDMessageReader::PRE_HEADER_SIZE),
227 boost::bind(&SBDMessageReader::pre_header_handler, &message_,
228 boost::placeholders::_1, boost::placeholders::_2));
229 }
230
232
233 double connect_time() const { return connect_time_; }
234
235 const SBDMOMessageReader& message() const { return message_; }
236 const std::string& remote_endpoint_str() { return remote_endpoint_str_; }
237
238 private:
240 const boost::asio::ip::tcp::socket::executor_type& executor)
241 : socket_(executor), connect_time_(-1), message_(socket_), remote_endpoint_str_("Unknown")
242 {
243 }
244
245 boost::asio::ip::tcp::socket socket_;
246 double connect_time_;
247 SBDMOMessageReader message_;
248 std::string remote_endpoint_str_;
249};
250
252{
253 public:
254 SBDServer(boost::asio::io_context& io_context, int port, bool ipv6)
255 : acceptor_(io_context,
256 boost::asio::ip::tcp::endpoint(
257 ipv6 ? boost::asio::ip::tcp::v6() : boost::asio::ip::tcp::v4(), port))
258 {
259 start_accept();
260 }
261
262 std::set<std::shared_ptr<SBDConnection>>& connections() { return connections_; }
263
264 private:
265 void start_accept()
266 {
267 std::shared_ptr<SBDConnection> new_connection =
268 SBDConnection::create(acceptor_.get_executor());
269 connections_.insert(new_connection);
270
271 acceptor_.async_accept(new_connection->socket(),
272 boost::bind(&SBDServer::handle_accept, this, new_connection,
273 boost::asio::placeholders::error));
274 }
275
276 void handle_accept(std::shared_ptr<SBDConnection> new_connection,
277 const boost::system::error_code& error)
278 {
279 if (!error)
280 {
281 using namespace goby::util::logger;
282 using goby::glog;
283
284 glog.is(DEBUG1) && glog << "Received SBD connection from: "
285 << new_connection->socket().remote_endpoint() << std::endl;
286
287 new_connection->start();
288 }
289
290 start_accept();
291 }
292
293 std::set<std::shared_ptr<SBDConnection>> connections_;
294 boost::asio::ip::tcp::acceptor acceptor_;
295};
296
297} // namespace directip
298} // namespace acomms
299} // namespace goby
300
301#endif
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,...