void ReliableSession::nak_received(ACE_Message_Block* control) { if (! this->active_) return; // sub send naks, then doesn't receive them. const TransportHeader& header = this->link_->receive_strategy()->received_header(); Serializer serializer( control, header.swap_bytes()); MulticastPeer local_peer; CORBA::ULong size = 0; serializer >> local_peer; // sent as remote_peer serializer >> size; std::vector<SequenceRange> ranges; for (CORBA::ULong i = 0; i < size; ++i) { SequenceNumber::Value low; serializer >> low; SequenceNumber::Value high; serializer >> high; ranges.push_back (SequenceRange (low, high)); } // Track peer repair requests for later suppression: if (local_peer == this->remote_peer_) { for (CORBA::ULong i = 0; i < size; ++i) { this->nak_peers_.insert(ranges[i]); } return; } // Ignore sample if not destined for us: if ((local_peer != this->link_->local_peer()) // Not to us. || (this->remote_peer_ != header.source_)) return; // Not from the remote peer for this session. TransportSendBuffer* send_buffer = this->link_->send_buffer(); // Broadcast a MULTICAST_NAKACK control sample before resending to suppress // repair requests for unrecoverable samples by providing a // new low-water mark for affected peers: if (!send_buffer->empty() && send_buffer->low() > ranges.begin()->first) { send_nakack(send_buffer->low()); } for (CORBA::ULong i = 0; i < size; ++i) { bool ret = send_buffer->resend(ranges[i]); if (OpenDDS::DCPS::DCPS_debug_level > 0) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) ReliableSession::nak_received") ACE_TEXT (" %d <- %d %d - %d resend result %d\n"), this->link_->local_peer(), this->remote_peer_, ranges[i].first.getValue(), ranges[i].second.getValue(), ret)); } } }
void ReliableSession::syn_hook(const SequenceNumber& seq) { const std::vector<SequenceRange> ranges(this->nak_sequence_.present_sequence_ranges()); this->nak_sequence_.reset(); this->nak_sequence_.insert(seq); for (std::vector<SequenceRange>::const_iterator iter = ranges.begin(); iter != ranges.end(); ++iter) { this->nak_sequence_.insert(SequenceRange(iter->first, iter->second)); } }
void ReliableSession::expire_naks() { if (this->nak_requests_.empty()) return; // nothing to expire ACE_Time_Value deadline(ACE_OS::gettimeofday()); deadline -= this->link_->config()->nak_timeout_; NakRequestMap::iterator first(this->nak_requests_.begin()); NakRequestMap::iterator last(this->nak_requests_.upper_bound(deadline)); if (first == last) return; // nothing to expire // Skip unrecoverable datagrams to // re-establish a baseline to detect future reception gaps. SequenceNumber lastSeq = (last == this->nak_requests_.end()) ? this->nak_requests_.rbegin()->second : last->second; std::vector<SequenceRange> dropped; if (this->nak_sequence_.insert(SequenceRange(this->nak_sequence_.low(), lastSeq), dropped)) { for (size_t i = 0; i < dropped.size(); ++i) { this->reassembly_.data_unavailable(dropped[i]); } ACE_ERROR((LM_WARNING, ACE_TEXT("(%P|%t) WARNING: ") ACE_TEXT("ReliableSession::expire_naks: ") ACE_TEXT("timed out waiting on remote peer %#08x%08x to send missing samples: %q - %q!\n"), (unsigned int)(this->remote_peer_ >> 32), (unsigned int) this->remote_peer_, this->nak_sequence_.low().getValue(), lastSeq.getValue())); } // Clear expired repair requests: this->nak_requests_.erase(first, last); deliver_held_data(); }
void ReliableSession::nakack_received(ACE_Message_Block* control) { if (this->active_) return; // pub send syn, then doesn't receive them. const TransportHeader& header = this->link_->receive_strategy()->received_header(); // Not from the remote peer for this session. if (this->remote_peer_ != header.source_) return; Serializer serializer(control, header.swap_bytes()); SequenceNumber low; serializer >> low; // MULTICAST_NAKACK control samples indicate data which cannot be // repaired by a remote peer; if any values were needed below // this value, then the sequence needs to be shifted: std::vector<SequenceRange> dropped; if (this->nak_sequence_.insert(SequenceRange(this->nak_sequence_.low(), low.previous()), dropped)) { for (size_t i = 0; i < dropped.size(); ++i) { this->reassembly_.data_unavailable(dropped[i]); } if (DCPS_debug_level > 0) { ACE_ERROR((LM_WARNING, ACE_TEXT("(%P|%t) WARNING: ReliableSession::nakack_received ") ACE_TEXT("local %d remote %d [%q - %q] ") ACE_TEXT("not repaired.\n"), this->link_->local_peer(), this->remote_peer_, this->nak_sequence_.low().getValue(), low.getValue())); } } }
void ReliableSession::send_naks() { // Could get data samples before syn control message. // No use nak'ing until syn control message is received and session is acked. if (!this->acked()) return; if (DCPS_debug_level > 5) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) ReliableSession::send_naks local %d ") ACE_TEXT("remote %d nak request size %d \n"), this->link_->local_peer(), this->remote_peer_, this->nak_requests_.size())); } if (!this->nak_sequence_.disjoint()) return; // nothing to send ACE_Time_Value now(ACE_OS::gettimeofday()); // Record high-water mark for this interval; this value will // be used to reset the low-water mark in the event the remote // peer becomes unresponsive: this->nak_requests_[now] = this->nak_sequence_.high(); typedef std::vector<SequenceRange> RangeVector; RangeVector ignored; /// The range first - second will be skiped (no naks sent for it). SequenceNumber first; SequenceNumber second; NakRequestMap::reverse_iterator itr(this->nak_requests_.rbegin()); if (this->nak_requests_.size() > 1) { // The sequences between rbegin - 1 and rbegin will not be ignored for naking. ++itr; size_t nak_delay_intervals = this->link()->config()->nak_delay_intervals_; size_t nak_max = this->link()->config()->nak_max_; size_t sz = this->nak_requests_.size(); // Image i is the index of element in nak_requests_ in reverse order. // index 0 sequence is most recent high water mark. // e.g index , 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 // 0 (rbegin) is always skipped because missing sample between 1 and 0 interval // should always be naked., // if nak_delay_intervals=4, nak_max=3, any sequence between 5 - 1, 10 - 6, 15 - 11 // are skipped for naking due to nak_delay_intervals and 20 - 16 are skipped for // naking due to nak_max. for (size_t i = 1; i < sz; ++i) { if ((i * 1.0) / (nak_delay_intervals + 1) > nak_max) { if (first != SequenceNumber()) { first = this->nak_requests_.begin()->second; } else { ignored.push_back(std::make_pair(this->nak_requests_.begin()->second, itr->second)); } break; } if (i % (nak_delay_intervals + 1) == 1) { second = itr->second; } if (second != SequenceNumber()) { first = itr->second; } if (i % (nak_delay_intervals + 1) == 0) { first = itr->second; if (first != SequenceNumber() && second != SequenceNumber()) { ignored.push_back(std::make_pair(first, second)); first = SequenceNumber(); second = SequenceNumber(); } } ++itr; } if (first != SequenceNumber() && second != SequenceNumber() && first != second) { ignored.push_back(std::make_pair(first, second)); } } // Take a copy to facilitate temporary suppression: DisjointSequence received(this->nak_sequence_); if (DCPS_debug_level > 0) { received.dump(); } size_t sz = ignored.size(); for (size_t i = 0; i < sz; ++i) { if (ignored[i].second > received.cumulative_ack()) { SequenceNumber high = ignored[i].second; SequenceNumber low = ignored[i].first; if (low < received.cumulative_ack()) { low = received.cumulative_ack(); } if (DCPS_debug_level > 0) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) ReliableSession::send_naks local %d ") ACE_TEXT("remote %d ignore missing [%q - %q]\n"), this->link_->local_peer(), this->remote_peer_, low.getValue(), high.getValue())); } // Make contiguous between ignored sequences. received.insert(SequenceRange(low, high)); } } for (NakPeerSet::iterator it(this->nak_peers_.begin()); it != this->nak_peers_.end(); ++it) { // Update sequence to temporarily suppress repair requests for // ranges already requested by other peers for this interval: received.insert(*it); } if (received.disjoint()) { send_naks(received); } // Clear peer repair requests: this->nak_peers_.clear(); }