int ThreadPerConnectionSendTask::add_request(SendStrategyOpType op,
                                             TransportQueueElement* element)
{
  DBG_ENTRY("ThreadPerConnectionSendTask", "add");

  ACE_Auto_Ptr<SendRequest> req(new SendRequest);
  req->op_ = op;
  req->element_ = element;

  int result = -1;
  { // guard scope
    GuardType guard(this->lock_);

    if (this->shutdown_initiated_) {
      return -1;
    }

    result = this->queue_.put(req.get());

    if (result == 0) {
      this->work_available_.signal();
      req.release();

    } else {
      ACE_ERROR((LM_ERROR,
                 ACE_TEXT("(%P|%t) ERROR: ThreadPerConnectionSendTask::add %p\n"),
                 ACE_TEXT("put")));
    }
  }

  return result;
}
int ThreadPerConnectionSendTask::close(u_long flag)
{
  DBG_ENTRY("ThreadPerConnectionSendTask","close");

  if (flag == 0) {
    return 0;
  }

  {
    GuardType guard(this->lock_);

    if (this->shutdown_initiated_) {
      return 0;
    }

    // Set the shutdown flag to true.
    this->shutdown_initiated_ = true;
    this->work_available_.signal();
  }

  if (this->opened_ && !ACE_OS::thr_equal(this->thr_id_, ACE_OS::thr_self())) {
    this->wait();
  }

  return 0;
}
Beispiel #3
0
void
PubDriver::init()
{
  DBG_ENTRY("PubDriver","init");

  OpenDDS::DCPS::TransportInst_rch inst;

  if (shmem_) {
    VDBG((LM_DEBUG, "(%P|%t) DBG:   Create a new ShmemInst object.\n"));

    inst = TheTransportRegistry->create_inst("shmem1", "shmem");

  } else {
    VDBG((LM_DEBUG, "(%P|%t) DBG:   Create a new TcpInst object.\n"));

    inst = TheTransportRegistry->create_inst("tcp1", "tcp");

    OpenDDS::DCPS::TcpInst_rch tcp_inst =
      OpenDDS::DCPS::dynamic_rchandle_cast<OpenDDS::DCPS::TcpInst>(inst);

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
               "Set the inst->local_address_ to our (local) pub_addr_.\n"));

    tcp_inst->local_address(ACE_TEXT_ALWAYS_CHAR(this->pub_addr_str_.c_str()));
  }

  OpenDDS::DCPS::TransportConfig_rch cfg =
    TheTransportRegistry->create_config("cfg");
  cfg->instances_.push_back(inst);

  TheTransportRegistry->global_config(cfg);

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "The Transport has been successfully configured.\n"));
}
SimpleDataWriter::SimpleDataWriter(const OpenDDS::DCPS::RepoId& pub_id)
  : pub_id_(pub_id)
  , num_messages_sent_(0)
  , num_messages_delivered_(0)
{
  DBG_ENTRY("SimpleDataWriter","SimpleDataWriter");
}
void
SimpleDataWriter::init(TAO::DCPS::RepoId pub_id)
{
  DBG_ENTRY("SimpleDataWriter","init");

  this->pub_id_ = pub_id;
}
int OpenDDS::DCPS::ThreadPerConnectionSendTask::open(void*)
{
  DBG_ENTRY("ThreadPerConnectionSendTask","open");

  GuardType guard(this->lock_);

  // We can assume that we are in the proper state to handle this open()
  // call as long as we haven't been open()'ed before.
  if (this->opened_)
  {
    ACE_ERROR_RETURN((LM_ERROR,
      "(%P|%t) ThreadPerConnectionSendTask failed to open.  "
      "Task has previously been open()'ed.\n"),
      -1);
  }

  // Activate this task object with one worker thread.
  if (this->activate(THR_NEW_LWP | THR_JOINABLE, 1) != 0)
  {
    // Assumes that when activate returns non-zero return code that
    // no threads were activated.
    ACE_ERROR_RETURN((LM_ERROR,
      "(%P|%t) ThreadPerConnectionSendTask failed to activate "
      "the worker threads.\n"),
      -1);
  }

  // Now we have past the point where we can say we've been open()'ed before.
  this->opened_ = true;

  return 0;
}
Beispiel #7
0
int
ACE_TMAIN (int argc, ACE_TCHAR *argv[])
{
  DBG_ENTRY("pub_main.cpp","main");

  ACE_LOG_MSG->priority_mask(LM_TRACE     |
                             LM_DEBUG     |
                             LM_INFO      |
                             LM_NOTICE    |
                             LM_WARNING   |
                             LM_ERROR     |
                             LM_CRITICAL  |
                             LM_ALERT     |
                             LM_EMERGENCY,
                             ACE_Log_Msg::PROCESS);

  for (int i = 1; i < argc; ++i) {
    if (0 == ACE_OS::strcasecmp(argv[i], ACE_TEXT("-q"))) {
      const u_long mask = ACE_LOG_MSG->priority_mask(ACE_Log_Msg::PROCESS);
      ACE_LOG_MSG->priority_mask(mask & ~LM_DEBUG, ACE_Log_Msg::PROCESS);
    }
  }


  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "Create the PubDriver object.\n"));

  PubDriver driver;

  try
  {
    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
               "Tell the PubDriver object to run(argc,argv).\n"));

    driver.run(argc, argv);

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
               "PubDriver object has completed running.  "
               "Exit process with success code (0).\n"));

    return 0;
  }
  catch (const TestException&)
  {
    ACE_ERROR((LM_ERROR,
               "(%P|%t) PubDriver TestException.\n"));
  }
  catch (...)
  {
    ACE_ERROR((LM_ERROR,
               "(%P|%t) PubDriver unknown (...) exception.\n"));
  }

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "PubDriver object has completed running due to an exception.  "
             "Exit process with failure code (1).\n"));

  return 1;
}
void
SimpleDataWriter::transport_lost()
{
  DBG_ENTRY("SimpleDataWriter","transport_lost");

  ACE_DEBUG((LM_DEBUG,
             "(%P|%t) The transport has been lost.\n"));
}
Beispiel #9
0
SubDriver::SubDriver()
  : pub_id_(OpenDDS::DCPS::GuidBuilder::create())
  , sub_id_(OpenDDS::DCPS::GuidBuilder::create())
  , reader_(sub_id_)
  , num_msgs_(1)
  , shmem_(false)
{
  DBG_ENTRY("SubDriver","SubDriver");
}
Beispiel #10
0
void
SimpleSubscriber::transport_detached_i()
{
  DBG_ENTRY("SimpleSubscriber","transport_detached_i");

  ACE_DEBUG((LM_DEBUG,
             "(%P|%t) Transport has detached from SimpleSubscriber.\n"));

  this->reader_.transport_lost();
}
Beispiel #11
0
PubDriver::PubDriver()
  : pub_id_(OpenDDS::DCPS::GuidBuilder::create())
  , sub_id_(OpenDDS::DCPS::GuidBuilder::create())
  , writer_(pub_id_)
  , num_msgs_(1)
  , msg_size_(0)
  , shmem_(false)
{
  DBG_ENTRY("PubDriver","PubDriver");
}
int ThreadPerConnectionSendTask::open(void*)
{
  DBG_ENTRY("ThreadPerConnectionSendTask", "open");

  GuardType guard(this->lock_);

  // We can assume that we are in the proper state to handle this open()
  // call as long as we haven't been open()'ed before.
  if (this->opened_) {
    ACE_ERROR_RETURN((LM_ERROR,
                      "(%P|%t) ThreadPerConnectionSendTask failed to open.  "
                      "Task has previously been open()'ed.\n"),
                     -1);
  }

  DirectPriorityMapper mapper(this->link_->transport_priority());
  int priority = mapper.thread_priority();

  long flags  = THR_NEW_LWP | THR_JOINABLE ;//|THR_SCOPE_PROCESS | THR_SCOPE_THREAD;
  int policy = TheServiceParticipant->scheduler();

  if (policy >= 0) {
    flags |= policy;
  } else {
    flags |= THR_INHERIT_SCHED;
  }

  if (DCPS_debug_level > 0) {
    ACE_DEBUG((LM_DEBUG,
               ACE_TEXT("(%P|%t) ThreadPerConnectionSendTask::open(): ")
               ACE_TEXT("activating thread with flags 0x%08.8x ")
               ACE_TEXT("and priority %d.\n"),
               flags,
               priority));
  }

  // Activate this task object with one worker thread.
  if (this->activate(flags, 1, 0, priority) != 0) {
    // Assumes that when activate returns non-zero return code that
    // no threads were activated.
    ACE_ERROR_RETURN((LM_ERROR,
                      "(%P|%t) ThreadPerConnectionSendTask failed to activate "
                      "the worker threads.\n"),
                     -1);
  }

  // Now we have past the point where we can say we've been open()'ed before.
  this->opened_ = true;

  return 0;
}
int
OpenDDS::DCPS::ThreadPerConnectionSendTask::remove_sample(TransportSendElement& element)
{
  DBG_ENTRY("ThreadPerConnectionSendTask","remove_sample");

  GuardType guard(this->lock_);

  ThreadPerConRemoveVisitor vistor(element.msg());

  // Let it visit our elems_ collection as a "replace" visitor.
  this->queue_.accept_visitor(vistor);

  return vistor.status();
}
RemoveResult
ThreadPerConnectionSendTask::remove_sample(const DataSampleElement* element)
{
  DBG_ENTRY("ThreadPerConnectionSendTask", "remove_sample");

  GuardType guard(this->lock_);

  ACE_Message_Block* payload = element->get_sample()->cont();
  ThreadPerConRemoveVisitor visitor(payload);

  this->queue_.accept_visitor(visitor);

  return visitor.status();
}
void
SimpleDataWriter::init(const OpenDDS::DCPS::AssociationData& subscription)
{
  DBG_ENTRY("SimpleDataWriter","init");

  // Add the association between the local sub_id and the remote pub_id
  // to the transport via the TransportInterface.
  bool result = this->associate(subscription, true /* active */);

  if (!result) {
    ACE_ERROR((LM_ERROR,
               "(%P|%t) SimpleDataWriter::init() Failed to associate.\n"));
    throw TestException();
  }
}
int
OpenDDS::DCPS::ThreadPerConnectionSendTask::remove_sample ( const DataSampleListElement* sample )
{
  DBG_ENTRY("ThreadPerConnectionSendTask","remove_sample");

  GuardType guard(this->lock_);

  // Construct a PacketRemoveVisitor object.
  ThreadPerConRemoveVisitor vistor(sample->sample_);

  // Let it visit our elems_ collection as a "replace" visitor.
  this->queue_.accept_visitor(vistor);

  return vistor.status();
}
Beispiel #17
0
int
SubDriver::parse_sub_arg(const ACE_TString& arg)
{
  DBG_ENTRY("SubDriver","parse_sub_arg");

  size_t pos;

  // Find the first ':' character, and make sure it is in a legal spot.
  if ((pos = std::find(arg.c_str(), arg.c_str() + arg.length(), ACE_TEXT(':')) - arg.c_str()) == arg.length()) {
    ACE_ERROR((LM_ERROR,
               "(%P|%t) Bad -p command-line value (%s). Missing ':' char.\n",
               arg.c_str()));
    return -1;
  }

  if (pos == 0) {
    ACE_ERROR((LM_ERROR,
               "(%P|%t) Bad -p command-line value (%s). "
               "':' char cannot be first char.\n",
               arg.c_str()));
    return -1;
  }

  if (pos == (arg.length() - 1)) {
    ACE_ERROR((LM_ERROR,
               "(%P|%t) Bad -p command-line value  (%s) - "
               "':' char cannot be last char.\n",
               arg.c_str()));
    return -1;
  }

  // Parse the sub_id from left of ':' char, and remainder to right of ':'.
  ACE_TString sub_id_str(arg.c_str(), pos);
  this->sub_addr_str_ = arg.c_str() + pos + 1;

  // RepoIds are conventionally created and managed by the DCPSInfoRepo. Those
  // generated here are for the sole purpose of verifying internal behavior.
  OpenDDS::DCPS::RepoIdBuilder builder(sub_id_);

  builder.participantId(1);
  builder.entityKey(ACE_OS::atoi(sub_id_str.c_str()));
  builder.entityKind(OpenDDS::DCPS::ENTITYKIND_USER_WRITER_WITH_KEY);

  // Use the remainder as the "stringified" ACE_INET_Addr.
  this->sub_addr_ = ACE_INET_Addr(this->sub_addr_str_.c_str());

  return 0;
}
void
SimpleDataWriter::data_delivered(const OpenDDS::DCPS::DataSampleElement* sample)
{
  DBG_ENTRY("SimpleDataWriter","data_delivered");

  ACE_UNUSED_ARG(sample);

  ACE_DEBUG((LM_DEBUG,
             "(%P|%t) The transport has confirmed that a sample has "
             "been delivered.\n"));

  //TBD: Cannot delete the sample here because this sample will be
  //     used by the TransportInterface::send to look for the next
  //     send sample.
  //     Just leak here or put into a list for deletion later.
  // Delete the element
  //delete sample;

  ++this->num_messages_delivered_;
}
Beispiel #19
0
void
SimpleDataWriter::data_dropped(TAO::DCPS::DataSampleListElement* sample,
                               bool dropped_by_transport)
{
  DBG_ENTRY("SimpleDataWriter","data_dropped");

  ACE_UNUSED_ARG(sample);
  ACE_UNUSED_ARG(dropped_by_transport);
  ACE_DEBUG((LM_DEBUG,
             "(%P|%t) The transport has confirmed that a sample has "
             "been dropped.\n"));

  //TBD: Cannot delete the sample here because this sample will be
  //     used by the TransportInterface::send to look for the next
  //     send sample.
  //     Just leak here or put into a list for deletion later.
  // Delete the element
  //delete sample;

  this->delivered_test_message_ = 1;
}
int
OpenDDS::DCPS::ThreadPerConRemoveVisitor::visit_element_remove(SendRequest* element,
                                                               int&         remove)
{
  DBG_ENTRY("ThreadPerConRemoveVisitor","visit_element_remove");

  if ((this->sample_ != 0) && (element->op_ == SEND) && (*(element->element_) == this->sample_))
    {
      // We are visiting the element that we want to remove, since the
      // element "matches" our sample_.

      // In order to have the BasicQueue<T> remove the element that we
      // are currently visiting, set the remove flag to true (1).  The
      // BasicQueue<T> will perform the actual removal once we return
      // from this method.
      remove = 1;

      // Inform the element that we've made a decision - and it is
      // data_dropped()
      element->element_->data_dropped();

      // Adjust our status_ to indicate that we actually found (and removed)
      // the sample.
      this->status_ = 1;

      if (this->sample_ != 0)
        {
          // Stop visitation since we've handled the element that matched
          // our sample_.
          return 0;
        }

      // When this->sample_ == 0, we visit every element.
    }

  // Continue visitation.
  return 1;
}
int OpenDDS::DCPS::ThreadPerConnectionSendTask::close(u_long flag)
{
  DBG_ENTRY("ThreadPerConnectionSendTask","close");

  if (flag == 0)
    return 0;

  {
    GuardType guard(this->lock_);

    if (this->shutdown_initiated_)
      return 0;

    // Set the shutdown flag to true.
    this->shutdown_initiated_ = true;
    this->work_available_.signal();
  }

  if (this->opened_ && this->thr_id_ != ACE_OS::thr_self())
    this->wait();

  return 0;
}
Beispiel #22
0
SimpleDataWriter::SimpleDataWriter()
  : delivered_test_message_(0)
{
  DBG_ENTRY("SimpleDataWriter","SimpleDataWriter");
}
SimpleDataWriter::~SimpleDataWriter()
{
  DBG_ENTRY("SimpleDataWriter","~SimpleDataWriter");
}
Beispiel #24
0
int
SimpleDataWriter::run(SimplePublisher* publisher)
{
  DBG_ENTRY("SimpleDataWriter","run");

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "Build the DataSampleElementList to contain one element - "
             "our 'Hello World' string.\n"));

  // We just send one message.

  // This is what goes in the "Data Block".
  ACE_TString data = "Hello World!";

  // Now we can create the DataSampleHeader struct and set its fields.
  TAO::DCPS::DataSampleHeader header;

  // The +1 makes the null terminator ('/0') get placed into the block.
  header.message_length_ = data.length() + 1;
  header.message_id_ = 1;
  header.sequence_ = 0;
  // TMB - Compiler no longer likes the next line...  source_timestamp_ is gone.
  //header.source_timestamp_ = ACE_OS::gettimeofday().msec();
  header.publication_id_ = this->pub_id_;

  // The DataSampleHeader is what goes in the "Header Block".
  ACE_Message_Block* header_block = new ACE_Message_Block
                                                (header.max_marshaled_size());
  header_block << header;

  // The +1 makes the null terminator ('/0') get placed into the block.
  ACE_Message_Block* data_block = new ACE_Message_Block(data.length() + 1);
  data_block->copy(data.c_str());

  // Chain the "Data Block" to the "Header Block"
  header_block->cont(data_block);

  // Create the DataSampleListElement now.
  TAO::DCPS::DataSampleListElementAllocator allocator(3);
  TAO::DCPS::TransportSendElementAllocator trans_allocator(3, sizeof (TAO::DCPS::TransportSendElement));
  TAO::DCPS::DataSampleListElement* element;

  ACE_NEW_MALLOC_RETURN(element,
           static_cast<TAO::DCPS::DataSampleListElement*> (allocator.malloc(sizeof (TAO::DCPS::DataSampleListElement))),
           TAO::DCPS::DataSampleListElement(this->pub_id_, this, 0, &trans_allocator),
           1);

  // The Sample Element will hold on to the chain of blocks (header + data).
  element->sample_ = header_block;

  // Set up the DataSampleList
  TAO::DCPS::DataSampleList samples;

  samples.head_ = element;
  samples.tail_ = element;
  samples.size_ = 1;

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "Ask the publisher to send the DataSampleList (samples).\n"));

  publisher->send_samples(samples);

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "The Publisher has finished sending the samples.\n"));

  return 0;
}
Beispiel #25
0
PubDriver::~PubDriver()
{
  DBG_ENTRY("PubDriver","~PubDriver");
}
Beispiel #26
0
SubDriver::~SubDriver()
{
  DBG_ENTRY("SubDriver","~SubDriver");
}
OpenDDS::DCPS::ThreadPerConRemoveVisitor::~ThreadPerConRemoveVisitor()
{
  DBG_ENTRY("ThreadPerConRemoveVisitor","~ThreadPerConRemoveVisitor");
}
Beispiel #28
0
void
SimpleSubscriber::init(TAO::DCPS::TransportIdType          transport_id,
                       TAO::DCPS::RepoId                   sub_id,
                       ssize_t                             num_publications,
                       const TAO::DCPS::AssociationData*   publications)
{
  DBG_ENTRY("SimpleSubscriber","init");

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "Use TheTransportFactory to obtain() the TransportImpl object "
             "that it knows as transport_id (%d).\n", transport_id));

  // Obtain the transport.
  TAO::DCPS::TransportImpl_rch transport =
                                    TheTransportFactory->obtain(transport_id);

  if (transport.is_nil())
    {
      // Failed to obtain the transport.
      ACE_ERROR((LM_ERROR,
                 "(%P|%t) Failed to obtain TransportImpl (id %d) from "
                 "TheTransportFactory.\n", transport_id));
      throw TestException();
    }

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "Attach ourselves (SimpleSubscriber) to the TransportImpl.\n"));

  // Attempt to attach the transport to ourselves.
  TAO::DCPS::AttachStatus status = this->attach_transport(transport.in());

  if (status != TAO::DCPS::ATTACH_OK)
    {
      // We failed to attach to the transport for some reason.
      ACE_TString status_str;

      switch (status)
        {
          case TAO::DCPS::ATTACH_BAD_TRANSPORT:
            status_str = "ATTACH_BAD_TRANSPORT";
            break;
          case TAO::DCPS::ATTACH_ERROR:
            status_str = "ATTACH_ERROR";
            break;
          case TAO::DCPS::ATTACH_INCOMPATIBLE_QOS:
            status_str = "ATTACH_INCOMPATIBLE_QOS";
            break;
          default:
            status_str = "Unknown Status";
            break;
        }

      ACE_ERROR((LM_ERROR,
                 "(%P|%t) Failed to attach to the transport. "
                 "AttachStatus == %s\n", status_str.c_str()));
      throw TestException();
    }

  // Good!  We are now attached to the transport.
  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "SimpleSubscriber is now attached to the TransportImpl.\n"));

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "Initialize our SimpleDataReader object.\n"));

  // Initialize our DataReader.
  this->reader_.init(sub_id);

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "Add the publications.\n"));

  // Add the association between the local sub_id and the remote pub_id
  // to the transport via the TransportInterface.
  int result = this->add_publications(sub_id,
                                      &this->reader_,
                                      0,   /* priority */
                                      num_publications,
                                      publications);

  if (result != 0)
    {
      ACE_ERROR((LM_ERROR,
                 "(%P|%t) Failed to add publications to the "
                 "TransportInterface.\n"));
      throw TestException();
    }

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
             "The publications have been added successfully.\n"));
}
Beispiel #29
0
SimpleSubscriber::~SimpleSubscriber()
{
  DBG_ENTRY("SimpleSubscriber","~SimpleSubscriber");
}
Beispiel #30
0
void
SubDriver::parse_args(int& argc, ACE_TCHAR* argv[])
{
  DBG_ENTRY("SubDriver","parse_args");

  // Command-line arguments:
  //
  // -p <pub_id:pub_host:pub_port>
  // -s <sub_id:sub_port>
  // -n <num_messages>
  // -m                use shared memory
  //
  ACE_Arg_Shifter arg_shifter(argc, argv);

  bool got_n = false;
  bool got_p = false;
  bool got_s = false;

  const ACE_TCHAR* current_arg = 0;

  while (arg_shifter.is_anything_left())
  {
    // The '-p' option
    if ((current_arg = arg_shifter.get_the_parameter(ACE_TEXT("-p")))) {
      if (got_p) {
        ACE_ERROR((LM_ERROR,
                   "(%P|%t) Only one -p allowed on command-line.\n"));
        throw TestException();
      }

      int result = parse_pub_arg(current_arg);
      arg_shifter.consume_arg();

      if (result != 0) {
        ACE_ERROR((LM_ERROR,
                   "(%P|%t) Failed to parse -p command-line arg.\n"));
        throw TestException();
      }

      got_p = true;
    }
    // A '-s' option
    else if ((current_arg = arg_shifter.get_the_parameter(ACE_TEXT("-s")))) {
      if (got_s) {
        ACE_ERROR((LM_ERROR,
                   "(%P|%t) Only one -s allowed on command-line.\n"));
        throw TestException();
      }

      int result = parse_sub_arg(current_arg);
      arg_shifter.consume_arg();

      if (result != 0) {
        ACE_ERROR((LM_ERROR,
                   "(%P|%t) Failed to parse -s command-line arg.\n"));
        throw TestException();
      }

      got_s = true;
    }
    // The '-n' option
    else if ((current_arg = arg_shifter.get_the_parameter(ACE_TEXT("-n")))) {
      if (got_n) {
        ACE_ERROR((LM_ERROR,
                   "(%P|%t) Only one -n allowed on command-line.\n"));
        throw TestException();
      }

      int value = ACE_OS::atoi(current_arg);
      arg_shifter.consume_arg();

      if (value <= 0) {
        ACE_ERROR((LM_ERROR,
                   "(%P|%t) Value following -n option must be > 0.\n"));
        throw TestException();
      }

      this->num_msgs_ = value;

      got_n = true;
    }
    else if (arg_shifter.cur_arg_strncasecmp(ACE_TEXT("-m")) == 0) {
      this->shmem_ = true;
      arg_shifter.consume_arg();
    }
    // The '-?' option
    else if (arg_shifter.cur_arg_strncasecmp(ACE_TEXT("-?")) == 0) {
      ACE_DEBUG((LM_DEBUG,
                 "usage: %s "
                 "-p pub_id:pub_host:pub_port -s sub_id:sub_host:sub_port\n",
                 argv[0]));

      arg_shifter.consume_arg();
      throw TestException();
    }
    // Anything else we just skip
    else {
      arg_shifter.ignore_arg();
    }
  }

  // Make sure we got the required arguments:
  if (!got_p) {
    ACE_ERROR((LM_ERROR,
               "(%P|%t) -p command-line option not specified (required).\n"));
    throw TestException();
  }

  if (!got_s) {
    ACE_ERROR((LM_ERROR,
               "(%P|%t) -s command-line option not specified (required).\n"));
    throw TestException();
  }
}