Пример #1
0
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;
  if (last == this->nak_requests_.end()) {
    lastSeq = this->nak_requests_.rbegin()->second;
  }
  else {
    lastSeq = last->second;
  }

  if (lastSeq > this->nak_sequence_.low ()) {
    ACE_ERROR((LM_WARNING,
                ACE_TEXT("(%P|%t) WARNING: ")
                ACE_TEXT("ReliableSession::expire_naks: ")
                ACE_TEXT("timed out waiting on remote peer %d to send missing samples: %d - %d!\n"),
                this->remote_peer_, this->nak_sequence_.low ().getValue(), lastSeq.getValue()));
    this->nak_sequence_.shift(lastSeq);
  }

  // Clear expired repair requests:
  this->nak_requests_.erase(first, last);
}
Пример #2
0
void
SingleSendBuffer::insert_fragment(SequenceNumber sequence,
                                  SequenceNumber fragment,
                                  TransportSendStrategy::QueueType* queue,
                                  ACE_Message_Block* chain)
{
  check_capacity();

  // Insert into buffers_ so that the overall capacity is maintained
  // The entry in buffers_ with two null pointers indicates that the
  // actual data is stored in fragments_[sequence].
  buffers_[sequence] = std::make_pair(static_cast<QueueType*>(0),
                                      static_cast<ACE_Message_Block*>(0));

  BufferType& buffer = fragments_[sequence][fragment];
  insert_buffer(buffer, queue, chain);

  if (Transport_debug_level > 5) {
    ACE_DEBUG((LM_DEBUG,
      ACE_TEXT("(%P|%t) SingleSendBuffer::insert_fragment() - ")
      ACE_TEXT("saved PDU: %q,%q as buffer(0x%@,0x%@)\n"),
      sequence.getValue(), fragment.getValue(),
      buffer.first, buffer.second
    ));
  }
}
Пример #3
0
void
ReliableSession::send_nakack(SequenceNumber low)
{
  size_t len = sizeof(low.getValue());

  ACE_Message_Block* data;
  ACE_NEW(data, ACE_Message_Block(len));

  Serializer serializer(
    data, this->link_->transport()->swap_bytes());

  serializer << low.getValue();

  // Broadcast control sample to all peers:
  send_control(MULTICAST_NAKACK, data);
}
Пример #4
0
 void send_data(const SequenceNumber& seq)
 {
   dsle_.get_header().sequence_ = seq;
   dsle_.set_sample(new ACE_Message_Block(DataSampleHeader::max_marshaled_size()));
   *dsle_.get_sample() << dsle_.get_header();
   dsle_.get_sample()->cont(payload_.duplicate());
   ACE_DEBUG((LM_INFO, "sending with seq#: %q\n", seq.getValue()));
   send(list_);
 }
Пример #5
0
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();
}
Пример #6
0
void
TransportSendBuffer::insert(SequenceNumber sequence, const buffer_type& value)
{

  // Age off oldest sample if we are at capacity:
  if (this->buffers_.size() == this->capacity_) {
    BufferMap::iterator it(this->buffers_.begin());
    if (it == this->buffers_.end()) return;

    if ( OpenDDS::DCPS::Transport_debug_level >= 10) {
      ACE_DEBUG((LM_DEBUG,
        ACE_TEXT("(%P|%t) TransportSendBuffer::insert() - ")
        ACE_TEXT("aging off PDU: 0x%x as buffer(0x%x,0x%x)\n"),
        it->first.getValue(),
        it->second.first, it->second.second
      ));
    }

    release(it->second);
    this->buffers_.erase(it);
  }

  std::pair<BufferMap::iterator, bool> pair =
    this->buffers_.insert(BufferMap::value_type(sequence, buffer_type()));
  if (pair.first == this->buffers_.end()) return;

  buffer_type& buffer(pair.first->second);

  // Copy sample's TransportQueueElements:
  TransportSendStrategy::QueueType*& elems = buffer.first;
  ACE_NEW(elems, TransportSendStrategy::QueueType(value.first->size(), 1));

  CopyChainVisitor visitor(*elems,
                           &this->retained_allocator_,
                           &this->retained_mb_allocator_,
                           &this->retained_db_allocator_);
  value.first->accept_visitor(visitor);

  // Copy sample's message/data block descriptors:
  ACE_Message_Block*& data = buffer.second;
  data = TransportQueueElement::clone(value.second,
                                      &this->retained_mb_allocator_,
                                      &this->retained_db_allocator_);

  if ( OpenDDS::DCPS::Transport_debug_level >= 10) {
    ACE_DEBUG((LM_DEBUG,
      ACE_TEXT("(%P|%t) TransportSendBuffer::insert() - ")
      ACE_TEXT("saved PDU: 0x%x as buffer(0x%x,0x%x)\n"),
      sequence.getValue(),
      buffer.first, buffer.second
    ));
  }
}
Пример #7
0
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()));
    }
  }
}
Пример #8
0
void
SingleSendBuffer::insert(SequenceNumber sequence,
                         TransportSendStrategy::QueueType* queue,
                         ACE_Message_Block* chain)
{
  check_capacity();

  BufferType& buffer = this->buffers_[sequence];
  insert_buffer(buffer, queue, chain);

  if (Transport_debug_level > 5) {
    ACE_DEBUG((LM_DEBUG,
      ACE_TEXT("(%P|%t) SingleSendBuffer::insert() - ")
      ACE_TEXT("saved PDU: %q as buffer(0x%@,0x%@)\n"),
      sequence.getValue(),
      buffer.first, buffer.second
    ));
  }
}
Пример #9
0
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();
}
Пример #10
0
 void operator()(SequenceNumber i, SequenceNumber j) const {
     out << "[" << i.getValue() << "," << j.getValue() << "] ";
 }
Пример #11
0
int
ACE_TMAIN(int, ACE_TCHAR*[])
{
  // Construction (default)
  TEST_CHECK(SequenceNumber(SN_MIN) == SequenceNumber());

  TEST_CHECK(SequenceNumber::ZERO().getValue() == 0);
  TEST_CHECK(SequenceNumber::ZERO() < SequenceNumber());
  TEST_CHECK(++SequenceNumber(SequenceNumber::ZERO()) == SequenceNumber());

  // testing numerical sequence
  TEST_CHECK(SequenceNumber(SN_MIN) < SequenceNumber(SN_MIN+1));
  TEST_CHECK(!(SequenceNumber(SN_MIN+1) < SequenceNumber(SN_MIN)));
  TEST_CHECK(SequenceNumber(SN_SEAM) < SequenceNumber(SN_SEAM+1));
  TEST_CHECK(!(SequenceNumber(SN_SEAM+1) < SequenceNumber(SN_SEAM)));
  TEST_CHECK(SequenceNumber(SN_MAX-1) < SequenceNumber(SN_MAX));
  TEST_CHECK(!(SequenceNumber(SN_MAX) < SequenceNumber(SN_MAX-1)));

  // testing values and increment operator
  {
    SequenceNumber num(SN_MIN);
    TEST_CHECK(num.getValue() == SN_MIN);
    TEST_CHECK((++num).getValue() == SN_MIN+1);
  }

  {
    SequenceNumber num(SN_SEAM);
    TEST_CHECK(num.getValue() == SN_SEAM);
    TEST_CHECK((++num).getValue() == SN_SEAM+1);
    TEST_CHECK((++num).getValue() == SN_SEAM+2);
  }

  {
    SequenceNumber num(SN_MAX);
    TEST_CHECK(num.getValue() == SN_MAX);
    TEST_CHECK((++num).getValue() == SN_MIN);
    // test post-incrementer
    TEST_CHECK((num++).getValue() == SN_MIN);
    TEST_CHECK(num.getValue() == SN_MIN+1);
  }

  // Test SEQUENCENUMBER_UNKNOWN
  {
    SequenceNumber num = SequenceNumber::SEQUENCENUMBER_UNKNOWN();
    TEST_CHECK(num.getValue() == ACE_INT64(0xffffffff) << 32);
    SequenceNumber min;
    TEST_CHECK(num != min);
    TEST_CHECK(num == SequenceNumber::SEQUENCENUMBER_UNKNOWN());
  }

  // Test previous() member function
  {
    SequenceNumber num(SN_MIN);
    TEST_CHECK(num.previous() == SN_MAX);
  }

  {
    SequenceNumber num(SN_SEAM+1);
    TEST_CHECK(num.previous() == SN_SEAM);
  }

  {
    SequenceNumber num(99);
    TEST_CHECK(num.previous() == 98);
  }

  {
    SequenceNumber num(SN_MAX);
    TEST_CHECK(num.previous() == SN_MAX-1);
  }


  return 0;
}