From 4ec33eb1e490c4570a4c2463fc4d9023720036a3 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Mon, 27 Jun 2016 16:56:11 -0400 Subject: [PATCH 01/13] Improve accuracy of bit rate targetting for iridium driver --- src/acomms/modemdriver/iridium_driver.cpp | 31 ++++++++---------- src/acomms/modemdriver/iridium_driver.h | 1 - .../modemdriver/iridium_driver_common.h | 20 +++++++++--- src/acomms/modemdriver/iridium_driver_fsm.cpp | 11 +++++-- src/acomms/modemdriver/iridium_driver_fsm.h | 32 +++---------------- 5 files changed, 44 insertions(+), 51 deletions(-) diff --git a/src/acomms/modemdriver/iridium_driver.cpp b/src/acomms/modemdriver/iridium_driver.cpp index d85bfee4..d06ddb4e 100644 --- a/src/acomms/modemdriver/iridium_driver.cpp +++ b/src/acomms/modemdriver/iridium_driver.cpp @@ -41,7 +41,6 @@ using goby::acomms::operator<<; goby::acomms::IridiumDriver::IridiumDriver() : fsm_(driver_cfg_), last_triple_plus_time_(0), - last_send_time_(0), serial_fd_(-1), next_frame_(0) { @@ -221,26 +220,24 @@ void goby::acomms::IridiumDriver::do_work() // display_state_cfg(&glog); double now = goby_time(); - // if we're on a call, keep pushing data at the target rate - const double send_interval = - driver_cfg_.GetExtension(IridiumDriverConfig::max_frame_size) / - (driver_cfg_.GetExtension(IridiumDriverConfig::target_bit_rate) / static_cast(BITS_IN_BYTE)); - - const fsm::OnCall* on_call = fsm_.state_cast(); - - if(fsm_.data_out().empty() && - (now > (last_send_time_ + send_interval))) - { - if(on_call && !on_call->bye_sent()) - { - process_transmission(rudics_mac_msg_, false); - last_send_time_ = now; - } - } if(on_call) { + // if we're on a call, keep pushing data at the target rate + const double send_wait = + on_call->last_bytes_sent() / + (driver_cfg_.GetExtension(IridiumDriverConfig::target_bit_rate) / static_cast(BITS_IN_BYTE)); + + if(fsm_.data_out().empty() && + (now > (on_call->last_tx_time() + send_wait))) + { + if(!on_call->bye_sent()) + { + process_transmission(rudics_mac_msg_, false); + } + } + if(!on_call->bye_sent() && now > (on_call->last_tx_time() + driver_cfg_.GetExtension(IridiumDriverConfig::handshake_hangup_seconds))) { diff --git a/src/acomms/modemdriver/iridium_driver.h b/src/acomms/modemdriver/iridium_driver.h index 24273c74..c403e046 100644 --- a/src/acomms/modemdriver/iridium_driver.h +++ b/src/acomms/modemdriver/iridium_driver.h @@ -74,7 +74,6 @@ namespace goby enum { TRIPLE_PLUS_WAIT = 2 }; protobuf::ModemTransmission rudics_mac_msg_; - double last_send_time_; int serial_fd_; diff --git a/src/acomms/modemdriver/iridium_driver_common.h b/src/acomms/modemdriver/iridium_driver_common.h index 6d100f3f..0eb46fdf 100644 --- a/src/acomms/modemdriver/iridium_driver_common.h +++ b/src/acomms/modemdriver/iridium_driver_common.h @@ -36,13 +36,17 @@ namespace goby : last_tx_time_(goby::common::goby_time()), last_rx_time_(0), bye_received_(false), - bye_sent_(false) + bye_sent_(false), + total_bytes_sent_(0), + last_bytes_sent_(0) { } - double last_rx_tx_time() const { return std::max(last_tx_time_, last_rx_time_); } double last_rx_time() const { return last_rx_time_; } double last_tx_time() const { return last_tx_time_; } - + + int last_bytes_sent() const { return last_bytes_sent_; } + int total_bytes_sent() const { return total_bytes_sent_; } + void set_bye_received(bool b) { bye_received_ = b; } void set_bye_sent(bool b) { bye_sent_ = b; } @@ -53,11 +57,19 @@ namespace goby void set_last_tx_time(double d) { last_tx_time_ = d; } void set_last_rx_time(double d) { last_rx_time_ = d; } + void set_last_bytes_sent(int i) + { + last_bytes_sent_ = i; + total_bytes_sent_ += i; + } + private: double last_tx_time_; double last_rx_time_; bool bye_received_; - bool bye_sent_; + bool bye_sent_; + int total_bytes_sent_; + int last_bytes_sent_; }; } diff --git a/src/acomms/modemdriver/iridium_driver_fsm.cpp b/src/acomms/modemdriver/iridium_driver_fsm.cpp index a47575c4..15674733 100644 --- a/src/acomms/modemdriver/iridium_driver_fsm.cpp +++ b/src/acomms/modemdriver/iridium_driver_fsm.cpp @@ -26,6 +26,7 @@ #include "goby/common/logger.h" #include "goby/common/time.h" #include "goby/util/binary.h" +#include "goby/acomms/acomms_constants.h" #include "rudics_packet.h" #include "iridium_driver_fsm.h" @@ -357,8 +358,13 @@ void goby::acomms::fsm::OnCall::in_state_react(const EvRxOnCallSerial& e) void goby::acomms::fsm::OnCall::in_state_react( const EvTxOnCallSerial& ) { + const static double target_byte_rate = (context().driver_cfg().GetExtension(IridiumDriverConfig::target_bit_rate) / static_cast(goby::acomms::BITS_IN_BYTE)); + + const double send_wait = last_bytes_sent() / target_byte_rate; + + double now = goby_time(); boost::circular_buffer& data_out = context().data_out(); - if(!data_out.empty()) + if(!data_out.empty() && (now > last_tx_time() + send_wait)) { // serialize the (protobuf) message std::string bytes; @@ -371,7 +377,8 @@ void goby::acomms::fsm::OnCall::in_state_react( const EvTxOnCallSerial& ) context().serial_tx_buffer().push_back(rudics_packet); data_out.pop_front(); - set_last_tx_time(goby_time()); + set_last_bytes_sent(rudics_packet.size()); + set_last_tx_time(now); } } diff --git a/src/acomms/modemdriver/iridium_driver_fsm.h b/src/acomms/modemdriver/iridium_driver_fsm.h index 241155b0..c3e69ef0 100644 --- a/src/acomms/modemdriver/iridium_driver_fsm.h +++ b/src/acomms/modemdriver/iridium_driver_fsm.h @@ -105,9 +105,6 @@ namespace goby struct EvSendBye : boost::statechart::event< EvSendBye > {}; - struct EvZMQConnect : boost::statechart::event< EvZMQConnect > {}; - struct EvZMQDisconnect : boost::statechart::event< EvZMQDisconnect > {}; - struct EvConfigured : boost::statechart::event< EvConfigured > {}; struct EvSBDBeginData : boost::statechart::event< EvSBDBeginData > { @@ -144,7 +141,6 @@ namespace goby struct Online; struct OnCall; - struct OnZMQCall; struct NotOnCall; struct SBD; @@ -426,37 +422,19 @@ namespace goby struct NotOnCall : boost::statechart::simple_state >, StateNotify { typedef boost::mpl::list< - boost::statechart::transition< EvConnect, OnCall >, - boost::statechart::transition< EvZMQConnect, OnZMQCall > + boost::statechart::transition< EvConnect, OnCall > > reactions; NotOnCall() : StateNotify("NotOnCall") {} ~NotOnCall() {} }; - struct OnZMQCall : boost::statechart::simple_state >, StateNotify, OnCallBase - { - - OnZMQCall() : StateNotify("OnZMQCall") { } - ~OnZMQCall() {} - - void in_state_react( const EvSendBye& ) - { - set_bye_sent(true); - } - - typedef boost::mpl::list< - boost::statechart::transition< EvZMQDisconnect, NotOnCall >, - boost::statechart::in_state_reaction< EvSendBye, OnZMQCall, &OnZMQCall::in_state_react > - > reactions; - - }; struct OnCall : boost::statechart::state >, StateNotify, OnCallBase { public: - OnCall(my_context ctx) : my_base(ctx), StateNotify("OnCall") + OnCall(my_context ctx) : my_base(ctx), StateNotify("OnCall") { // add a brief identifier that is *different* than the "~" which is what PPP uses // add a carriage return to clear out any garbage @@ -468,14 +446,14 @@ namespace goby } ~OnCall() { // signal the disconnect event for the command state to handle + glog.is(goby::common::logger::DEBUG1) && glog << group("iridiumdriver") << "Sent " << total_bytes_sent() << " bytes on this call." << std::endl; post_event(EvDisconnect()); } void in_state_react( const EvRxOnCallSerial& ); void in_state_react( const EvTxOnCallSerial& ); void in_state_react( const EvSendBye& ); - - + typedef boost::mpl::list< boost::statechart::transition< EvNoCarrier, NotOnCall >, boost::statechart::in_state_reaction< EvRxOnCallSerial, OnCall, &OnCall::in_state_react >, @@ -485,7 +463,7 @@ namespace goby > reactions; private: - + }; From 81f8594e16b4be26b4752a19c47c9c4fbc3bd8c8 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Mon, 27 Jun 2016 16:56:27 -0400 Subject: [PATCH 02/13] Added basic queue for IP Gateway --- .../acomms/goby_ip_gateway/ip_gateway.cpp | 98 +++++++++++++++---- .../goby_ip_gateway/ip_gateway_config.proto | 2 + 2 files changed, 81 insertions(+), 19 deletions(-) diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp index 2133d7c1..e1abf4eb 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "dccl/arithmetic/field_codec_arithmetic.h" @@ -60,14 +61,15 @@ namespace goby void init_tun(); void loop(); - void handle_udp_packet(protobuf::ModemTransmission* m, - const goby::acomms::protobuf::IPv4Header& ip_hdr, + void receive_packets(); + + void handle_udp_packet(const goby::acomms::protobuf::IPv4Header& ip_hdr, const goby::acomms::protobuf::UDPHeader& udp_hdr, const std::string& payload); void write_udp_packet(goby::acomms::protobuf::IPv4Header& ip_hdr, goby::acomms::protobuf::UDPHeader& udp_hdr, const std::string& payload); - + std::pair to_src_dest_pair(int srcdest); int from_src_dest_pair(std::pair src_dest); @@ -97,6 +99,9 @@ namespace goby std::vector dynamic_udp_fd_; int ip_mtu_; // the MTU on the tun interface, which is slightly different than the Goby MTU specified in the config file since the IP and Goby NetworkHeader are different sizes. + + // maps destination goby address to message buffer + std::map > outgoing_; }; } } @@ -264,11 +269,13 @@ goby::acomms::IPGateway::~IPGateway() void goby::acomms::IPGateway::loop() { - mac_.do_work(); + mac_.do_work(); + receive_packets(); } + + void goby::acomms::IPGateway::handle_udp_packet( - protobuf::ModemTransmission* m, const goby::acomms::protobuf::IPv4Header& ip_hdr, const goby::acomms::protobuf::UDPHeader& udp_hdr, const std::string& payload) @@ -278,12 +285,6 @@ void goby::acomms::IPGateway::handle_udp_packet( int src = ipv4_to_goby_address(ip_hdr.source_ip_address()); int dest = ipv4_to_goby_address(ip_hdr.dest_ip_address()); - - if(m->src() != src) - glog.is(WARN) && glog << "Wrong source ID on data request" << std::endl; - - m->set_dest(dest); - m->set_ack_requested(false); goby::acomms::protobuf::NetworkHeader net_header; net_header.set_protocol(goby::acomms::protobuf::NetworkHeader::UDP); @@ -329,7 +330,17 @@ void goby::acomms::IPGateway::handle_udp_packet( std::string nh; dccl_goby_nh_.encode(&nh, net_header); - m->add_frame(nh + payload); + + std::map >::iterator it = outgoing_.find(dest); + if(it == outgoing_.end()) + { + std::pair >::iterator, bool> itboolpair = + outgoing_.insert(std::make_pair(dest, boost::circular_buffer(cfg_.queue_size()))); + it = itboolpair.first; + } + + it->second.push_back(nh + payload); + glog.is(DEBUG1) && glog << "Queue size is: " << it->second.size() << std::endl; } void goby::acomms::IPGateway::handle_initiate_transmission(const protobuf::ModemTransmission& m) @@ -337,12 +348,9 @@ void goby::acomms::IPGateway::handle_initiate_transmission(const protobuf::Modem publish(m, "Tx" + goby::util::as(local_modem_id_)); } - -void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmission& orig_msg) +void goby::acomms::IPGateway::receive_packets() { - protobuf::ModemTransmission msg = orig_msg; - - while((unsigned)msg.frame_size() < msg.max_num_frames()) + while(true) { fd_set rd_set; FD_ZERO(&rd_set); @@ -353,7 +361,7 @@ void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmiss if (ret < 0 && errno != EINTR) { glog.is(WARN) && glog << "Could not select on tun fd." << std::endl; - break; + return; } else if(ret > 0) { @@ -388,7 +396,7 @@ void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmiss goby::acomms::protobuf::UDPHeader udp_hdr; std::string udp_header_data(&buffer[ip_header_size], UDP_HEADER_SIZE); dccl_udp_.decode(udp_header_data, &udp_hdr); - handle_udp_packet(&msg, ip_hdr, udp_hdr, std::string(&buffer[ip_header_size+UDP_HEADER_SIZE], ip_hdr.total_length()-ip_header_size-UDP_HEADER_SIZE)); + handle_udp_packet(ip_hdr, udp_hdr, std::string(&buffer[ip_header_size+UDP_HEADER_SIZE], ip_hdr.total_length()-ip_header_size-UDP_HEADER_SIZE)); break; } } @@ -398,8 +406,60 @@ void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmiss } else { + // no select items + return; + } + } +} + + + +void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmission& orig_msg) +{ + protobuf::ModemTransmission msg = orig_msg; + + while((unsigned)msg.frame_size() < msg.max_num_frames()) + { + if(msg.dest() != goby::acomms::QUERY_DESTINATION_ID) + { + std::map >::iterator it = outgoing_.find(msg.dest()); + if(it == outgoing_.end()) + { + break; + } + else if(it->second.size() == 0) + { + break; + } + else + { + msg.set_ack_requested(false); + msg.add_frame(it->second.front()); + it->second.pop_front(); + } + } + else + { + // TODO: not fair - prioritizes lower valued destinations + for(std::map >::iterator it = outgoing_.begin(), + end = outgoing_.end(); it != end; ++it) + { + if(it->second.size() == 0) + { + continue; + } + else + { + msg.set_dest(it->first); + msg.set_ack_requested(false); + msg.add_frame(it->second.front()); + it->second.pop_front(); + break; + } + } break; } + } publish(msg, "DataResponse" + goby::util::as(local_modem_id_)); diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto b/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto index 79d91ac4..faf6e9cf 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto @@ -31,4 +31,6 @@ message IPGatewayConfig required MACConfig mac_cfg = 30; required uint32 mtu = 31; + + optional int32 queue_size = 40 [default = 100]; } From 2c4a4f223801bd0813bb8c62268d4d4c515492cb Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Mon, 27 Jun 2016 17:48:46 -0400 Subject: [PATCH 03/13] Added improved bit rate targeting to Iridium shore driver as well --- .../modemdriver/iridium_shore_driver.cpp | 30 ++++++++++--------- src/acomms/modemdriver/iridium_shore_driver.h | 4 +-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/acomms/modemdriver/iridium_shore_driver.cpp b/src/acomms/modemdriver/iridium_shore_driver.cpp index c4a7a79b..1a88da1e 100644 --- a/src/acomms/modemdriver/iridium_shore_driver.cpp +++ b/src/acomms/modemdriver/iridium_shore_driver.cpp @@ -113,31 +113,32 @@ void goby::acomms::IridiumShoreDriver::do_work() // display_state_cfg(&glog); double now = goby_time(); - // if we're on a call, keep pushing data at the target rate - const double send_interval = - driver_cfg_.GetExtension(IridiumDriverConfig::max_frame_size) / - (driver_cfg_.GetExtension(IridiumDriverConfig::target_bit_rate) / static_cast(BITS_IN_BYTE)); for(std::map::iterator it = remote_.begin(), end = remote_.end(); it != end; ++it) { RemoteNode& remote = it->second; - boost::shared_ptr on_call_base = it->second.on_call; + boost::shared_ptr on_call_base = remote.on_call; ModemId id = it->first; - if(now > (remote.last_send_time + send_interval)) - { - if(on_call_base && !on_call_base->bye_sent()) - { - rudics_mac_msg_.set_dest(it->first); - process_transmission(rudics_mac_msg_); - remote.last_send_time = now; - } - } // if we're on either type of call, see if we need to send the "bye" message or hangup if(on_call_base) { + // if we're on a call, keep pushing data at the target rate + const double send_wait = + on_call_base->last_bytes_sent() / + (driver_cfg_.GetExtension(IridiumDriverConfig::target_bit_rate) / static_cast(BITS_IN_BYTE)); + + if(now > (on_call_base->last_tx_time() + send_wait)) + { + if(!on_call_base->bye_sent()) + { + rudics_mac_msg_.set_dest(it->first); + process_transmission(rudics_mac_msg_); + } + } + if(!on_call_base->bye_sent() && now > (on_call_base->last_tx_time() + driver_cfg_.GetExtension(IridiumDriverConfig::handshake_hangup_seconds))) { @@ -205,6 +206,7 @@ void goby::acomms::IridiumShoreDriver::send(const protobuf::ModemTransmission& m rudics_send(rudics_packet, msg.dest()); boost::shared_ptr on_call_base = remote.on_call; on_call_base->set_last_tx_time(goby_time()); + on_call_base->set_last_bytes_sent(rudics_packet.size()); } else if(msg.rate() == RATE_SBD) { diff --git a/src/acomms/modemdriver/iridium_shore_driver.h b/src/acomms/modemdriver/iridium_shore_driver.h index 88166b57..d39ba51f 100644 --- a/src/acomms/modemdriver/iridium_shore_driver.h +++ b/src/acomms/modemdriver/iridium_shore_driver.h @@ -84,13 +84,11 @@ namespace goby struct RemoteNode { enum { DATA_BUFFER_CAPACITY = 30 }; - RemoteNode() : data_out(DATA_BUFFER_CAPACITY), - last_send_time(0) + RemoteNode() : data_out(DATA_BUFFER_CAPACITY) { } boost::shared_ptr on_call; boost::circular_buffer data_out; - double last_send_time; }; From b8eb6432a7f125161c673693b32fa73eaaf0cad6 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Tue, 28 Jun 2016 12:23:41 -0400 Subject: [PATCH 04/13] Switched encoding (using Protobuf defaults) entire ModemTransmission for Iridium drivers to a DCCL based header. This should save significant data --- src/acomms/modemdriver/iridium_driver.cpp | 14 +++- .../modemdriver/iridium_driver_common.h | 67 +++++++++++++++++++ src/acomms/modemdriver/iridium_driver_fsm.cpp | 8 +-- .../modemdriver/iridium_shore_driver.cpp | 11 +-- src/acomms/protobuf/iridium_driver.proto | 26 ++++++- 5 files changed, 113 insertions(+), 13 deletions(-) diff --git a/src/acomms/modemdriver/iridium_driver.cpp b/src/acomms/modemdriver/iridium_driver.cpp index d06ddb4e..caa6ea0e 100644 --- a/src/acomms/modemdriver/iridium_driver.cpp +++ b/src/acomms/modemdriver/iridium_driver.cpp @@ -38,13 +38,16 @@ using goby::common::goby_time; using goby::acomms::operator<<; +boost::shared_ptr goby::acomms::iridium_header_dccl_; + goby::acomms::IridiumDriver::IridiumDriver() : fsm_(driver_cfg_), last_triple_plus_time_(0), serial_fd_(-1), next_frame_(0) { - + init_iridium_dccl(); + // assert(byte_string_to_uint32(uint32_to_byte_string(16540)) == 16540); } @@ -189,8 +192,10 @@ void goby::acomms::IridiumDriver::process_transmission(protobuf::ModemTransmissi { signal_modify_transmission(&msg); + const static unsigned frame_max = IridiumHeader::descriptor()->FindFieldByName("frame_start")->options().GetExtension(dccl::field).max(); + if(!msg.has_frame_start()) - msg.set_frame_start(next_frame_); + msg.set_frame_start(next_frame_ % frame_max); // set the frame size, if not set or if it exceeds the max configured if(!msg.has_max_frame_bytes() || msg.max_frame_bytes() > driver_cfg_.GetExtension(IridiumDriverConfig::max_frame_size)) @@ -335,8 +340,11 @@ void goby::acomms::IridiumDriver::send(const protobuf::ModemTransmission& msg) fsm_.buffer_data_out(msg); else { + std::string iridium_packet; + serialize_iridium_modem_message(&iridium_packet, msg); + std::string rudics_packet; - serialize_rudics_packet(msg.SerializeAsString(), &rudics_packet); + serialize_rudics_packet(iridium_packet, &rudics_packet); fsm_.process_event(fsm::EvSBDBeginData(rudics_packet)); } diff --git a/src/acomms/modemdriver/iridium_driver_common.h b/src/acomms/modemdriver/iridium_driver_common.h index 0eb46fdf..babf7d5a 100644 --- a/src/acomms/modemdriver/iridium_driver_common.h +++ b/src/acomms/modemdriver/iridium_driver_common.h @@ -23,6 +23,12 @@ #ifndef IridiumDriverCommon20150508H #define IridiumDriverCommon20150508H +#include +#include +#include + +#include "goby/acomms/protobuf/iridium_driver.pb.h" + namespace goby { namespace acomms @@ -71,7 +77,68 @@ namespace goby int total_bytes_sent_; int last_bytes_sent_; }; + + + // placeholder id codec that uses no bits, since we're always sending just this message on the wire + class IridiumHeaderIdentifierCodec : public dccl::TypedFixedFieldCodec + { + dccl::Bitset encode() { return dccl::Bitset(); } + dccl::Bitset encode(const uint32& wire_value) { return dccl::Bitset(); } + dccl::uint32 decode(dccl::Bitset* bits) { return 0; } + virtual unsigned size() { return 0; } + + }; + + extern boost::shared_ptr iridium_header_dccl_; + + inline void init_iridium_dccl() + { + dccl::FieldCodecManager::add("iridium_header_id"); + iridium_header_dccl_.reset(new dccl::Codec("iridium_header_id")); + iridium_header_dccl_->load(); + } + + inline void serialize_iridium_modem_message(std::string* out, const goby::acomms::protobuf::ModemTransmission& in) + { + IridiumHeader header; + header.set_src(in.src()); + header.set_dest(in.dest()); + if(in.has_rate()) + header.set_rate(in.rate()); + header.set_type(in.type()); + if(in.has_ack_requested()) + header.set_ack_requested(in.ack_requested()); + if(in.has_frame_start()) + header.set_frame_start(in.frame_start()); + if(in.acked_frame_size()) + header.set_acked_frame(in.acked_frame(0)); + + iridium_header_dccl_->encode(out, header); + if(in.frame_size()) + *out += in.frame(0); + } + + inline void parse_iridium_modem_message(std::string in, goby::acomms::protobuf::ModemTransmission* out) + { + IridiumHeader header; + iridium_header_dccl_->decode(&in, &header); + out->set_src(header.src()); + out->set_dest(header.dest()); + if(header.has_rate()) + out->set_rate(header.rate()); + out->set_type(header.type()); + if(header.has_ack_requested()) + out->set_ack_requested(header.ack_requested()); + if(header.has_frame_start()) + out->set_frame_start(header.frame_start()); + if(header.has_acked_frame()) + out->add_acked_frame(header.acked_frame()); + + if(in.size()) + out->add_frame(in); + } + } } diff --git a/src/acomms/modemdriver/iridium_driver_fsm.cpp b/src/acomms/modemdriver/iridium_driver_fsm.cpp index 15674733..28c30c05 100644 --- a/src/acomms/modemdriver/iridium_driver_fsm.cpp +++ b/src/acomms/modemdriver/iridium_driver_fsm.cpp @@ -145,7 +145,7 @@ void goby::acomms::fsm::Command::handle_sbd_rx(const std::string& in) std::string bytes; parse_rudics_packet(&bytes, sbd_rx_data); protobuf::ModemTransmission msg; - msg.ParseFromString(bytes); + parse_iridium_modem_message(bytes, &msg); context< IridiumDriverFSM >().received().push_back(msg); at_out().pop_front(); @@ -344,7 +344,7 @@ void goby::acomms::fsm::OnCall::in_state_react(const EvRxOnCallSerial& e) parse_rudics_packet(&bytes, in); protobuf::ModemTransmission msg; - msg.ParseFromString(bytes); + parse_iridium_modem_message(bytes, &msg); context< IridiumDriverFSM >().received().push_back(msg); set_last_rx_time(goby_time()); } @@ -368,8 +368,8 @@ void goby::acomms::fsm::OnCall::in_state_react( const EvTxOnCallSerial& ) { // serialize the (protobuf) message std::string bytes; - data_out.front().SerializeToString(&bytes); - + serialize_iridium_modem_message(&bytes, data_out.front()); + // frame message std::string rudics_packet; serialize_rudics_packet(bytes, &rudics_packet); diff --git a/src/acomms/modemdriver/iridium_shore_driver.cpp b/src/acomms/modemdriver/iridium_shore_driver.cpp index 1a88da1e..0a2990e7 100644 --- a/src/acomms/modemdriver/iridium_shore_driver.cpp +++ b/src/acomms/modemdriver/iridium_shore_driver.cpp @@ -47,6 +47,7 @@ using goby::acomms::protobuf::DirectIPMTPayload; goby::acomms::IridiumShoreDriver::IridiumShoreDriver() : next_frame_(0) { + init_iridium_dccl(); } goby::acomms::IridiumShoreDriver::~IridiumShoreDriver() @@ -198,7 +199,7 @@ void goby::acomms::IridiumShoreDriver::send(const protobuf::ModemTransmission& m if(msg.rate() == RATE_RUDICS || remote.on_call) { std::string bytes; - msg.SerializeToString(&bytes); + serialize_iridium_modem_message(&bytes, msg); // frame message std::string rudics_packet; @@ -211,7 +212,7 @@ void goby::acomms::IridiumShoreDriver::send(const protobuf::ModemTransmission& m else if(msg.rate() == RATE_SBD) { std::string bytes; - msg.SerializeToString(&bytes); + serialize_iridium_modem_message(&bytes, msg); std::string sbd_packet; serialize_rudics_packet(bytes, &sbd_packet); @@ -296,8 +297,9 @@ void goby::acomms::IridiumShoreDriver::rudics_line(const std::string& data, boos parse_rudics_packet(&decoded_line, data); protobuf::ModemTransmission modem_msg; - modem_msg.ParseFromString(decoded_line); + parse_iridium_modem_message(decoded_line, &modem_msg); + glog.is(DEBUG1) && glog << "Received RUDICS message from: " << modem_msg.src() << " to: " << modem_msg.dest() << " from endpoint: " << connection->remote_endpoint_str() << std::endl; if(!clients_.left.count(modem_msg.src())) { @@ -349,8 +351,7 @@ void goby::acomms::IridiumShoreDriver::receive_sbd_mo() try { parse_rudics_packet(&bytes, (*it)->message().body().payload()); - - modem_msg.ParseFromString(bytes); + parse_iridium_modem_message(bytes, &modem_msg); glog.is(DEBUG1) && glog << "Rx SBD ModemTransmission: " << modem_msg.ShortDebugString() << std::endl; diff --git a/src/acomms/protobuf/iridium_driver.proto b/src/acomms/protobuf/iridium_driver.proto index 970342e7..08ddbb9f 100644 --- a/src/acomms/protobuf/iridium_driver.proto +++ b/src/acomms/protobuf/iridium_driver.proto @@ -1,6 +1,7 @@ import "goby/common/protobuf/option_extensions.proto"; import "goby/acomms/protobuf/driver_base.proto"; -import "goby/common/protobuf/zero_mq_node_config.proto"; +import "goby/acomms/protobuf/modem_message.proto"; +import "dccl/protobuf/option_extensions.proto"; message IridiumDriverConfig { @@ -25,3 +26,26 @@ message IridiumDriverConfig optional int32 handshake_hangup_seconds = 1392 [default = 5]; } } + +// subset of goby.acomms.protobuf.ModemTransmission +message IridiumHeader +{ + option (dccl.msg).id = 0; + option (dccl.msg).max_bytes = 7; + + required int32 src = 1 [(dccl.field).min = 0, + (dccl.field).max = 30]; + + required int32 dest = 2 [(dccl.field).min = 0, + (dccl.field).max = 30]; + + optional int32 rate = 3 [(dccl.field).min = 0, + (dccl.field).max = 1]; + + required goby.acomms.protobuf.ModemTransmission.TransmissionType type = 4; + + + optional bool ack_requested = 5; + optional uint32 frame_start = 6 [(dccl.field).min = 0, (dccl.field).max = 0xFFFF]; + optional int32 acked_frame = 7 [(dccl.field).min = 0, (dccl.field).max = 0xFFFF]; +} \ No newline at end of file From 3ce1c6d7345e172c7cc6f161de4b644390f3cb60 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Tue, 28 Jun 2016 12:44:16 -0400 Subject: [PATCH 05/13] Added ability to goby_ip_gateway to filter by ModemTransmission::rate --- src/apps/acomms/goby_ip_gateway/ip_gateway.cpp | 3 ++- src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp index e1abf4eb..60608059 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp @@ -467,7 +467,8 @@ void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmiss void goby::acomms::IPGateway::handle_modem_receive(const goby::acomms::protobuf::ModemTransmission& modem_msg) { - std::cout << modem_msg.DebugString() << std::endl; + if(cfg_.has_only_rate() && cfg_.only_rate() != modem_msg.rate()) + return; for(int i = 0, n = modem_msg.frame_size(); i < n; ++i) { diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto b/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto index faf6e9cf..6fe638f2 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto @@ -33,4 +33,6 @@ message IPGatewayConfig required uint32 mtu = 31; optional int32 queue_size = 40 [default = 100]; + + optional int32 only_rate = 50; } From 9483f527448ca8c55830757f8526d2ba72fabd14 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Tue, 28 Jun 2016 14:52:52 -0400 Subject: [PATCH 06/13] Added only rate check for data request as well in goby_ip_gateway --- src/apps/acomms/goby_ip_gateway/ip_gateway.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp index 60608059..79ff0a92 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp @@ -416,6 +416,9 @@ void goby::acomms::IPGateway::receive_packets() void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmission& orig_msg) { + if(cfg_.has_only_rate() && cfg_.only_rate() != orig_msg.rate()) + return; + protobuf::ModemTransmission msg = orig_msg; while((unsigned)msg.frame_size() < msg.max_num_frames()) From 3b5d9fe8192ac5be6b68fd29ccbb7984a7f39030 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Tue, 28 Jun 2016 16:32:28 -0400 Subject: [PATCH 07/13] Added ICMP control message support to goby_ip_gateway --- src/acomms/protobuf/network_header.proto | 35 +++++ .../acomms/goby_ip_gateway/ip_gateway.cpp | 128 ++++++++++++++++-- 2 files changed, 153 insertions(+), 10 deletions(-) diff --git a/src/acomms/protobuf/network_header.proto b/src/acomms/protobuf/network_header.proto index 4728fc54..fdaf06ec 100644 --- a/src/acomms/protobuf/network_header.proto +++ b/src/acomms/protobuf/network_header.proto @@ -98,3 +98,38 @@ message UDPHeader required uint32 checksum = 4 [(dccl.field).codec = "net.short"]; } + + +message ICMPHeader +{ + option (dccl.msg).id = 0xF003; + option (dccl.msg).max_bytes = 8; + option (dccl.msg).codec_version = 3; + + required uint32 type = 1 [(dccl.field).min = 0, (dccl.field).max = 255]; + required uint32 code = 2 [(dccl.field).min = 0, (dccl.field).max = 255]; + required uint32 checksum = 3 [(dccl.field).codec = "net.short"]; + required uint32 short1 = 4 [(dccl.field).codec = "net.short"]; + required uint32 short2 = 5 [(dccl.field).codec = "net.short"]; +} + +message IPGatewayICMPControl +{ + enum MessageType + { + QUEUE_REPORT = 1; + } + required MessageType type = 1; + required string address = 2; + + message QueueReport + { + message SubQueue + { + required int32 dest = 1; + required int32 size = 2; + } + repeated SubQueue queue = 1; + } + optional QueueReport queue_report = 3; +} diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp index 79ff0a92..71e25bde 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp @@ -40,7 +40,11 @@ enum { IPV4_ADDRESS_BITS = 32, MIN_IPV4_HEADER_LENGTH = 5, // number of 32-bit words - UDP_HEADER_SIZE = 8 }; + UDP_HEADER_SIZE = 8, + ICMP_HEADER_SIZE = 8, + ICMP_TYPE = 250, + IPV4_VERSION = 4, + ICMP_CODE = 0}; int tun_alloc(char *dev); int tun_config(const char* dev, const char* host, unsigned cidr_prefix, unsigned mtu); @@ -69,6 +73,14 @@ namespace goby void write_udp_packet(goby::acomms::protobuf::IPv4Header& ip_hdr, goby::acomms::protobuf::UDPHeader& udp_hdr, const std::string& payload); + void write_icmp_control_message(const protobuf::IPGatewayICMPControl& control_msg); + + void write_icmp_packet(goby::acomms::protobuf::IPv4Header& ip_hdr, + goby::acomms::protobuf::ICMPHeader& icmp_hdr, + const std::string& payload); + + void icmp_report_queue(); + std::pair to_src_dest_pair(int srcdest); int from_src_dest_pair(std::pair src_dest); @@ -84,7 +96,7 @@ namespace goby private: goby::acomms::protobuf::IPGatewayConfig& cfg_; - dccl::Codec dccl_goby_nh_, dccl_ip_, dccl_udp_; + dccl::Codec dccl_goby_nh_, dccl_ip_, dccl_udp_, dccl_icmp_; int tun_fd_; int total_addresses_; goby::uint32 local_address_; // in host byte order @@ -112,6 +124,7 @@ goby::acomms::IPGateway::IPGateway(goby::acomms::protobuf::IPGatewayConfig* cfg) dccl_goby_nh_("ip_gateway_id_codec_0"), dccl_ip_("ip_gateway_id_codec_1"), dccl_udp_("ip_gateway_id_codec_2"), + dccl_icmp_("ip_gateway_id_codec_3"), tun_fd_(-1), total_addresses_((1 << (IPV4_ADDRESS_BITS-cfg_.cidr_netmask_prefix()))-1), // minus one since we don't need to use .255 as broadcast local_address_(0), @@ -234,7 +247,8 @@ void goby::acomms::IPGateway::init_dccl() dccl_goby_nh_.load(); dccl_ip_.load(); dccl_udp_.load(); - + dccl_icmp_.load(); + dccl_goby_nh_.info_all(&std::cout); } @@ -340,7 +354,7 @@ void goby::acomms::IPGateway::handle_udp_packet( } it->second.push_back(nh + payload); - glog.is(DEBUG1) && glog << "Queue size is: " << it->second.size() << std::endl; + icmp_report_queue(); } void goby::acomms::IPGateway::handle_initiate_transmission(const protobuf::ModemTransmission& m) @@ -399,6 +413,17 @@ void goby::acomms::IPGateway::receive_packets() handle_udp_packet(ip_hdr, udp_hdr, std::string(&buffer[ip_header_size+UDP_HEADER_SIZE], ip_hdr.total_length()-ip_header_size-UDP_HEADER_SIZE)); break; } + case IPPROTO_ICMP: + { + goby::acomms::protobuf::ICMPHeader icmp_hdr; + std::string icmp_header_data(&buffer[ip_header_size], ICMP_HEADER_SIZE); + dccl_icmp_.decode(icmp_header_data, &icmp_hdr); + glog.is(DEBUG1) && glog << "Received ICMP Packet with header: " << icmp_hdr.ShortDebugString() << std::endl; + glog.is(DEBUG1) && glog << "ICMP sending is not supported." << std::endl; + + break; + } + } } @@ -420,7 +445,8 @@ void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmiss return; protobuf::ModemTransmission msg = orig_msg; - + + bool had_data = false; while((unsigned)msg.frame_size() < msg.max_num_frames()) { if(msg.dest() != goby::acomms::QUERY_DESTINATION_ID) @@ -439,6 +465,7 @@ void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmiss msg.set_ack_requested(false); msg.add_frame(it->second.front()); it->second.pop_front(); + had_data = true; } } else @@ -457,6 +484,7 @@ void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmiss msg.set_ack_requested(false); msg.add_frame(it->second.front()); it->second.pop_front(); + had_data = true; break; } } @@ -466,6 +494,8 @@ void goby::acomms::IPGateway::handle_data_request(const protobuf::ModemTransmiss } publish(msg, "DataResponse" + goby::util::as(local_modem_id_)); + if(had_data) + icmp_report_queue(); } void goby::acomms::IPGateway::handle_modem_receive(const goby::acomms::protobuf::ModemTransmission& modem_msg) @@ -478,11 +508,6 @@ void goby::acomms::IPGateway::handle_modem_receive(const goby::acomms::protobuf: goby::acomms::protobuf::IPv4Header ip_hdr; goby::acomms::protobuf::UDPHeader udp_hdr; - enum - { - IPV4_VERSION = 4, - }; - goby::acomms::protobuf::NetworkHeader net_header; std::string frame = modem_msg.frame(i); @@ -595,6 +620,88 @@ void goby::acomms::IPGateway::write_udp_packet(goby::acomms::protobuf::IPv4Heade glog.is(WARN) && glog << "Failed to write all " << packet.size() << " bytes." << std::endl; } +void goby::acomms::IPGateway::icmp_report_queue() +{ + protobuf::IPGatewayICMPControl control_msg; + control_msg.set_type(protobuf::IPGatewayICMPControl::QUEUE_REPORT); + control_msg.set_address(cfg_.local_ipv4_address()); + + for(std::map >::const_iterator it = outgoing_.begin(), end = outgoing_.end(); it != end; ++it) + { + int size = it->second.size(); + if(size) + { + protobuf::IPGatewayICMPControl::QueueReport::SubQueue* q = control_msg.mutable_queue_report()->add_queue(); + q->set_dest(it->first); + q->set_size(size); + } + } + write_icmp_control_message(control_msg); +} + +void goby::acomms::IPGateway::write_icmp_control_message(const protobuf::IPGatewayICMPControl& control_msg) +{ + std::string control_data; + control_msg.SerializeToString(&control_data); + + glog.is(DEBUG1) && glog << "Writing ICMP Control message: " << control_msg.DebugString() << std::endl; + + + goby::acomms::protobuf::IPv4Header ip_hdr; + ip_hdr.set_ihl(MIN_IPV4_HEADER_LENGTH); + ip_hdr.set_version(IPV4_VERSION); + ip_hdr.set_ecn(0); + ip_hdr.set_dscp(0); + ip_hdr.set_total_length(MIN_IPV4_HEADER_LENGTH*4 + ICMP_HEADER_SIZE + control_data.size()); + ip_hdr.set_identification(0); + ip_hdr.mutable_flags_frag_offset()->set_dont_fragment(false); + ip_hdr.mutable_flags_frag_offset()->set_more_fragments(false); + ip_hdr.mutable_flags_frag_offset()->set_fragment_offset(0); + ip_hdr.set_ttl(63); + ip_hdr.set_protocol(IPPROTO_ICMP); + ip_hdr.set_source_ip_address(cfg_.local_ipv4_address()); + ip_hdr.set_dest_ip_address(cfg_.local_ipv4_address()); + + goby::acomms::protobuf::ICMPHeader icmp_hdr; + icmp_hdr.set_type(ICMP_TYPE); + icmp_hdr.set_code(ICMP_CODE); + + write_icmp_packet(ip_hdr, icmp_hdr, control_data); +} + + + +void goby::acomms::IPGateway::write_icmp_packet(goby::acomms::protobuf::IPv4Header& ip_hdr, goby::acomms::protobuf::ICMPHeader& icmp_hdr, const std::string& payload) +{ + // set checksum 0 for calculation + ip_hdr.set_header_checksum(0); + icmp_hdr.set_checksum(0); + icmp_hdr.set_short1(0); + icmp_hdr.set_short2(0); + + std::string ip_hdr_data, icmp_hdr_data; + dccl_icmp_.encode(&icmp_hdr_data, icmp_hdr); + dccl_ip_.encode(&ip_hdr_data, ip_hdr); + + enum { NET_SHORT_BYTES = 2, NET_LONG_BYTES = 4 }; + enum { IPV4_SOURCE_ADDR_OFFSET = 12, IPV4_DEST_ADDR_OFFSET = 16, IPV4_CS_OFFSET = 10 }; + enum { ICMP_CS_OFFSET = 2}; + + uint16_t ip_checksum = net_checksum(ip_hdr_data); + uint16_t icmp_checksum = net_checksum(icmp_hdr_data + payload); + + ip_hdr_data[IPV4_CS_OFFSET] = (ip_checksum >> 8) & 0xFF; + ip_hdr_data[IPV4_CS_OFFSET+1] = ip_checksum & 0xFF; + + icmp_hdr_data[ICMP_CS_OFFSET] = (icmp_checksum >> 8) & 0xFF; + icmp_hdr_data[ICMP_CS_OFFSET+1] = icmp_checksum & 0xFF; + + std::string packet(ip_hdr_data + icmp_hdr_data + payload); + unsigned len = write(tun_fd_, packet.c_str(), packet.size()); + if(len < packet.size()) + glog.is(WARN) && glog << "Failed to write all " << packet.size() << " bytes." << std::endl; +} + // src // 0 1 2 3 // ------------ @@ -679,6 +786,7 @@ int main(int argc, char* argv[]) dccl::FieldCodecManager::add >("ip_gateway_id_codec_0"); dccl::FieldCodecManager::add >("ip_gateway_id_codec_1"); dccl::FieldCodecManager::add >("ip_gateway_id_codec_2"); + dccl::FieldCodecManager::add >("ip_gateway_id_codec_3"); dccl::FieldCodecManager::add("net.short"); dccl::FieldCodecManager::add("ip.v4.address"); dccl::FieldCodecManager::add("ip.v4.flagsfragoffset"); From 026374e89321a828bfd99de8457ad2e4c243d1c9 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Thu, 7 Jul 2016 15:15:19 -0400 Subject: [PATCH 08/13] Added support for AIS NMEA prefix ('git diff') and cleaned up the linebasedcomms read loop --- src/test/util/nmea/nmea.cpp | 7 +++++++ src/util/linebasedcomms/connection.h | 21 +++++---------------- src/util/linebasedcomms/nmea_sentence.cpp | 10 +++++----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/test/util/nmea/nmea.cpp b/src/test/util/nmea/nmea.cpp index 13364b75..90845be6 100644 --- a/src/test/util/nmea/nmea.cpp +++ b/src/test/util/nmea/nmea.cpp @@ -56,6 +56,13 @@ int main() std::cout << nmea.message() << std::endl; assert(nmea.at(8) == "ROLL"); } + + { + goby::util::NMEASentence nmea("!AIVDO,1,1,,,B0000003wk?8mP=18D3Q3wwUkP06,0*7B"); + std::cout << nmea.message() << std::endl; + assert(nmea.as(1) == 1); + assert(nmea.as(2) == 1); + } std::cout << "all tests passed" << std::endl; diff --git a/src/util/linebasedcomms/connection.h b/src/util/linebasedcomms/connection.h index e97b6353..c77129a6 100644 --- a/src/util/linebasedcomms/connection.h +++ b/src/util/linebasedcomms/connection.h @@ -86,31 +86,21 @@ namespace goby } std::istream is(&buffer_); - std::string& line = *in_datagram_.mutable_data(); - + if(!remote_endpoint().empty()) in_datagram_.set_src(remote_endpoint()); if(!local_endpoint().empty()) in_datagram_.set_dest(local_endpoint()); in_datagram_.set_time(goby::common::goby_time()); - char last = interface_->delimiter().at(interface_->delimiter().length()-1); - while(!std::getline(is, line, last).eof()) + std::getline(is, line, last); + { - line = extra_ + line + last; - // grab a lock on the in_ deque because the user can modify - boost::mutex::scoped_lock lock(interface_->in_mutex()); - + boost::mutex::scoped_lock lock(interface_->in_mutex()); interface_->in().push_back(in_datagram_); - - extra_.clear(); - } - - // store any remainder for the next round - if(!line.empty()) extra_ = line; - + } read_start(); // start waiting for another asynchronous read again } @@ -144,7 +134,6 @@ namespace goby private: LineBasedInterface* interface_; boost::asio::streambuf buffer_; - std::string extra_; protobuf::Datagram in_datagram_; std::deque out_; // buffered write data diff --git a/src/util/linebasedcomms/nmea_sentence.cpp b/src/util/linebasedcomms/nmea_sentence.cpp index 4e66434b..030c25df 100644 --- a/src/util/linebasedcomms/nmea_sentence.cpp +++ b/src/util/linebasedcomms/nmea_sentence.cpp @@ -37,8 +37,8 @@ goby::util::NMEASentence::NMEASentence(std::string s, strategy cs_strat /*= VALI // Basic error checks ($, empty) if (s.empty()) throw bad_nmea_sentence("NMEASentence: no message provided."); - if (s[0] != '$') - throw bad_nmea_sentence("NMEASentence: no $: '" + s + "'."); + if (s[0] != '$' && s[0] != '!') + throw bad_nmea_sentence("NMEASentence: no $ or !: '" + s + "'."); // Check if the checksum exists and is correctly placed, and strip it. // If it's not correctly placed, we'll interpret it as part of message. // NMEA spec doesn't seem to say that * is forbidden elsewhere? (should be) @@ -68,11 +68,11 @@ unsigned char goby::util::NMEASentence::checksum(const std::string& s) { if(s.empty()) throw bad_nmea_sentence("NMEASentence::checksum: no message provided."); - std::string::size_type star = s.find_first_of("*\r\n"); - std::string::size_type dollar = s.find('$'); + std::string::size_type star = s.find_first_of("*"); + std::string::size_type dollar = s.find_first_of("$!"); if(dollar == std::string::npos) - throw bad_nmea_sentence("NMEASentence::checksum: no $ found."); + throw bad_nmea_sentence("NMEASentence::checksum: no $ or ! found."); if(star == std::string::npos) star = s.length(); From 4adc1b21f1fb7108c69106932808e9ac42d194c5 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Fri, 5 May 2017 16:49:28 -0400 Subject: [PATCH 09/13] Added bypassing MAC to ip_gateway --- src/apps/acomms/goby_ip_gateway/ip_gateway.cpp | 18 ++++++++++++++++++ .../goby_ip_gateway/ip_gateway_config.proto | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp index 522db742..e75e24fb 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp @@ -355,6 +355,24 @@ void goby::acomms::IPGateway::handle_udp_packet( it->second.push_back(nh + payload); icmp_report_queue(); + + // skip the MACManager and directly initiate the transmission + if(cfg_.bypass_mac()) + { + if(cfg_.has_bypass_mac_slot()) + { + handle_initiate_transmission(cfg_.bypass_mac_slot()); + } + else + { + protobuf::ModemTransmission m; + m.set_src(local_modem_id_); + m.set_type(protobuf::ModemTransmission::DATA); + if(cfg_.has_only_rate()) + m.set_rate(cfg_.only_rate()); + handle_initiate_transmission(m); + } + } } void goby::acomms::IPGateway::handle_initiate_transmission(const protobuf::ModemTransmission& m) diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto b/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto index 6fe638f2..98bf8233 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto @@ -1,6 +1,7 @@ import "goby/common/protobuf/option_extensions.proto"; import "goby/common/protobuf/app_base_config.proto"; import "goby/acomms/protobuf/amac_config.proto"; +import "goby/acomms/protobuf/modem_message.proto"; package goby.acomms.protobuf; @@ -29,8 +30,10 @@ message IPGatewayConfig optional int32 total_ports = 20 [default = 1]; repeated uint32 static_udp_port = 21; - required MACConfig mac_cfg = 30; + optional MACConfig mac_cfg = 30; required uint32 mtu = 31; + optional bool bypass_mac = 32 [default = false]; + optional ModemTransmission bypass_mac_slot = 33; optional int32 queue_size = 40 [default = 100]; From c406b3be87b810f07d255ff50fcb1bb2cd42d867 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Fri, 5 May 2017 17:35:39 -0400 Subject: [PATCH 10/13] Improve bypass MAC --- .../acomms/goby_ip_gateway/ip_gateway.cpp | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp index e75e24fb..e8f0ec5c 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp @@ -355,24 +355,6 @@ void goby::acomms::IPGateway::handle_udp_packet( it->second.push_back(nh + payload); icmp_report_queue(); - - // skip the MACManager and directly initiate the transmission - if(cfg_.bypass_mac()) - { - if(cfg_.has_bypass_mac_slot()) - { - handle_initiate_transmission(cfg_.bypass_mac_slot()); - } - else - { - protobuf::ModemTransmission m; - m.set_src(local_modem_id_); - m.set_type(protobuf::ModemTransmission::DATA); - if(cfg_.has_only_rate()) - m.set_rate(cfg_.only_rate()); - handle_initiate_transmission(m); - } - } } void goby::acomms::IPGateway::handle_initiate_transmission(const protobuf::ModemTransmission& m) @@ -644,6 +626,8 @@ void goby::acomms::IPGateway::icmp_report_queue() control_msg.set_type(protobuf::IPGatewayICMPControl::QUEUE_REPORT); control_msg.set_address(cfg_.local_ipv4_address()); + int total_messages = 0; + for(std::map >::const_iterator it = outgoing_.begin(), end = outgoing_.end(); it != end; ++it) { int size = it->second.size(); @@ -652,9 +636,28 @@ void goby::acomms::IPGateway::icmp_report_queue() protobuf::IPGatewayICMPControl::QueueReport::SubQueue* q = control_msg.mutable_queue_report()->add_queue(); q->set_dest(it->first); q->set_size(size); + total_messages += size; } } write_icmp_control_message(control_msg); + + // skip the MACManager and directly initiate the transmission + if(total_messages > 0 && cfg_.bypass_mac()) + { + if(cfg_.has_bypass_mac_slot()) + { + handle_initiate_transmission(cfg_.bypass_mac_slot()); + } + else + { + protobuf::ModemTransmission m; + m.set_src(local_modem_id_); + m.set_type(protobuf::ModemTransmission::DATA); + if(cfg_.has_only_rate()) + m.set_rate(cfg_.only_rate()); + handle_initiate_transmission(m); + } + } } void goby::acomms::IPGateway::write_icmp_control_message(const protobuf::IPGatewayICMPControl& control_msg) From fc9a589d9bb77870541a3d76a4cf4ad9c14cc23f Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Mon, 8 May 2017 12:46:37 -0400 Subject: [PATCH 11/13] Added configuration to set tunnel device number (tunN) for goby_ip_gateway --- .../acomms/goby_ip_gateway/ip_gateway.cpp | 35 ++++++++++++------- .../goby_ip_gateway/ip_gateway_config.proto | 1 + 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp index e8f0ec5c..089b7897 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp @@ -255,7 +255,14 @@ void goby::acomms::IPGateway::init_dccl() void goby::acomms::IPGateway::init_tun() { char tun_name[IFNAMSIZ]; - strcpy(tun_name, "\0"); + + std::string desired_tun_name = "tun"; + if(cfg_.has_tun_number()) + desired_tun_name += goby::util::as(cfg_.tun_number()); + else + desired_tun_name += "%d"; + + strcpy(tun_name, desired_tun_name.c_str()); tun_fd_ = tun_alloc(tun_name); if(tun_fd_ < 0) glog.is(DIE) && glog << "Could not allocate tun interface. Check permissions?" << std::endl; @@ -304,6 +311,20 @@ void goby::acomms::IPGateway::handle_udp_packet( net_header.set_protocol(goby::acomms::protobuf::NetworkHeader::UDP); net_header.set_srcdest_addr(from_src_dest_pair(std::make_pair(src,dest))); + // map destination first - we need this mapping to exist on the other end + // if we map the source first, we might use the source mapping when source port == dest port + boost::bimap::right_map::const_iterator dest_it = port_map_.right.find(udp_hdr.dest_port()); + if(dest_it != port_map_.right.end()) + { + net_header.mutable_udp()->add_srcdest_port(dest_it->second); + } + else + { + glog.is(WARN) && glog << "No mapping for destination UDP port: " << udp_hdr.dest_port() << ". Unable to send packet." << std::endl; + return; + } + + boost::bimap::right_map::const_iterator src_it = port_map_.right.find(udp_hdr.source_port()); if(src_it != port_map_.right.end()) { @@ -328,18 +349,6 @@ void goby::acomms::IPGateway::handle_udp_packet( } } - boost::bimap::right_map::const_iterator dest_it = port_map_.right.find(udp_hdr.dest_port()); - if(dest_it != port_map_.right.end()) - { - net_header.mutable_udp()->add_srcdest_port(dest_it->second); - } - else - { - glog.is(WARN) && glog << "No mapping for destination UDP port: " << udp_hdr.dest_port() << ". Unable to send packet." << std::endl; - return; - } - - glog.is(VERBOSE) && glog << "NetHeader: " << net_header.DebugString() << std::endl; std::string nh; diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto b/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto index 98bf8233..9cc9237f 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway_config.proto @@ -11,6 +11,7 @@ message IPGatewayConfig required string local_ipv4_address = 2; required uint32 cidr_netmask_prefix = 3; + optional int32 tun_number = 4; optional bool enable_broadcast_address = 10 [default = true]; // use all ones address as broadcast (e.g. 192.168.1.255 in /24 subnet optional uint32 dynamic_address_count = 11 [default = 0]; // number of dynamic addresses for use as reverse-NAT (starting at one less than broadcast and counting down). From a07914b4d6eaf99db7e2862212c10879d30def5d Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Mon, 8 May 2017 13:33:09 -0400 Subject: [PATCH 12/13] Fix regression with ordering of src/dest ports in goby_ip_gateway --- src/apps/acomms/goby_ip_gateway/ip_gateway.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp index 089b7897..f15c0b22 100644 --- a/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp +++ b/src/apps/acomms/goby_ip_gateway/ip_gateway.cpp @@ -313,10 +313,11 @@ void goby::acomms::IPGateway::handle_udp_packet( // map destination first - we need this mapping to exist on the other end // if we map the source first, we might use the source mapping when source port == dest port + int dest_port = 0, src_port = 0; boost::bimap::right_map::const_iterator dest_it = port_map_.right.find(udp_hdr.dest_port()); if(dest_it != port_map_.right.end()) { - net_header.mutable_udp()->add_srcdest_port(dest_it->second); + dest_port = dest_it->second; } else { @@ -328,7 +329,7 @@ void goby::acomms::IPGateway::handle_udp_packet( boost::bimap::right_map::const_iterator src_it = port_map_.right.find(udp_hdr.source_port()); if(src_it != port_map_.right.end()) { - net_header.mutable_udp()->add_srcdest_port(src_it->second); + src_port = src_it->second; } else { @@ -348,6 +349,9 @@ void goby::acomms::IPGateway::handle_udp_packet( dynamic_port_index_ = cfg_.static_udp_port_size(); } } + + net_header.mutable_udp()->add_srcdest_port(src_port); + net_header.mutable_udp()->add_srcdest_port(dest_port); glog.is(VERBOSE) && glog << "NetHeader: " << net_header.DebugString() << std::endl; From f7ad94500dc028950aa2c9b00c7f4b9fc82fc401 Mon Sep 17 00:00:00 2001 From: Toby Schneider Date: Mon, 8 May 2017 15:44:14 -0400 Subject: [PATCH 13/13] Added option to disable mailbox check on empty Iridium SDB messages --- src/acomms/modemdriver/iridium_driver.cpp | 3 ++- src/acomms/protobuf/iridium_driver.proto | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/acomms/modemdriver/iridium_driver.cpp b/src/acomms/modemdriver/iridium_driver.cpp index a265df8b..3716592f 100644 --- a/src/acomms/modemdriver/iridium_driver.cpp +++ b/src/acomms/modemdriver/iridium_driver.cpp @@ -213,7 +213,8 @@ void goby::acomms::IridiumDriver::process_transmission(protobuf::ModemTransmissi } else if(msg.rate() == RATE_SBD) { - fsm_.process_event(fsm::EvSBDBeginData()); // mailbox check + if(msg.GetExtension(IridiumDriverConfig::if_no_data_do_mailbox_check)) + fsm_.process_event(fsm::EvSBDBeginData()); // mailbox check } } diff --git a/src/acomms/protobuf/iridium_driver.proto b/src/acomms/protobuf/iridium_driver.proto index 08ddbb9f..3879b69d 100644 --- a/src/acomms/protobuf/iridium_driver.proto +++ b/src/acomms/protobuf/iridium_driver.proto @@ -25,6 +25,12 @@ message IridiumDriverConfig optional bool use_dtr = 1390 [default = false]; optional int32 handshake_hangup_seconds = 1392 [default = 5]; } + + extend goby.acomms.protobuf.ModemTransmission + { + optional bool if_no_data_do_mailbox_check = 1381 [default = true]; + } + } // subset of goby.acomms.protobuf.ModemTransmission