#ifndef ACE_ACCEPTOR_CPP #define ACE_ACCEPTOR_CPP #include "ace/ACE.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "ace/Acceptor.h" #include "ace/Svc_Handler.h" #include "ace/WFMO_Reactor.h" #include "ace/OS_NS_stdio.h" #include "ace/OS_NS_string.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_ALLOC_HOOK_DEFINE_Tca(ACE_Acceptor) template void ACE_Acceptor::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Acceptor::dump"); ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); this->peer_acceptor_.dump (); ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* ACE_HAS_DUMP */ } template ACE_Acceptor::operator PEER_ACCEPTOR & () const { ACE_TRACE ("ACE_Acceptor::operator PEER_ACCEPTOR &"); return (PEER_ACCEPTOR &) this->peer_acceptor_; } template PEER_ACCEPTOR & ACE_Acceptor::acceptor () const { ACE_TRACE ("ACE_Acceptor::acceptor"); return const_cast (this->peer_acceptor_); } // Returns ACE_HANDLE of the underlying Acceptor_Strategy. template ACE_HANDLE ACE_Acceptor::get_handle () const { ACE_TRACE ("ACE_Acceptor::get_handle"); return this->peer_acceptor_.get_handle (); } // Initialize the appropriate strategies for creation, passive // connection acceptance, and concurrency, and then register // with the Reactor and listen for connection requests at the // designated . template int ACE_Acceptor::open (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, ACE_Reactor *reactor, int flags, int use_select, int reuse_addr) { ACE_TRACE ("ACE_Acceptor::open"); this->flags_ = flags; this->use_select_ = use_select; this->reuse_addr_ = reuse_addr; this->peer_acceptor_addr_ = local_addr; // Must supply a valid Reactor to Acceptor::open()... if (reactor == 0) { errno = EINVAL; return -1; } // Open the underlying PEER_ACCEPTOR. if (this->peer_acceptor_.open (local_addr, reuse_addr) == -1) return -1; // Set the peer acceptor's handle into non-blocking mode. This is a // safe-guard against the race condition that can otherwise occur // between the time when indicates that a passive-mode // socket handle is "ready" and when we call . During this // interval, the client can shutdown the connection, in which case, // the call can hang! if (this->accept_strategy_->acceptor ().enable (ACE_NONBLOCK) != 0) return -1; // Initialize the concurrency strategy. if (con_s == 0) { ACE_NEW_RETURN (con_s, CONCURRENCY_STRATEGY, -1); this->delete_concurrency_strategy_ = true; } this->concurrency_strategy_ = con_s; // Initialize the scheduling strategy. if (sch_s == 0) { ACE_NEW_RETURN (sch_s, SCHEDULING_STRATEGY, -1); this->delete_scheduling_strategy_ = true; } this->scheduling_strategy_ = sch_s; this->use_select_ = use_select; return this->reactor ()->register_handler (this, ACE_Event_Handler::ACCEPT_MASK); } // Simple constructor. template ACE_Strategy_Acceptor::ACE_Strategy_Acceptor (const ACE_TCHAR service_name[], const ACE_TCHAR service_description[], int use_select, int reuse_addr) : creation_strategy_ (0), delete_creation_strategy_ (false), accept_strategy_ (0), delete_accept_strategy_ (false), concurrency_strategy_ (0), delete_concurrency_strategy_ (false), scheduling_strategy_ (0), delete_scheduling_strategy_ (false), service_name_ (0), service_description_ (0) { ACE_TRACE ("ACE_Strategy_Acceptor::ACE_Strategy_Acceptor"); if (service_name != 0) ACE_ALLOCATOR (this->service_name_, ACE_OS::strdup (service_name)); if (service_description != 0) ACE_ALLOCATOR (this->service_description_, ACE_OS::strdup (service_description)); this->use_select_ = use_select; this->reuse_addr_ = reuse_addr; } template ACE_Strategy_Acceptor::ACE_Strategy_Acceptor (const typename PEER_ACCEPTOR::PEER_ADDR &addr, ACE_Reactor *reactor, ACE_Creation_Strategy *cre_s, ACE_Accept_Strategy *acc_s, ACE_Concurrency_Strategy *con_s, ACE_Scheduling_Strategy *sch_s, const ACE_TCHAR service_name[], const ACE_TCHAR service_description[], int use_select, int reuse_addr) : creation_strategy_ (0), delete_creation_strategy_ (false), accept_strategy_ (0), delete_accept_strategy_ (false), concurrency_strategy_ (0), delete_concurrency_strategy_ (false), scheduling_strategy_ (0), delete_scheduling_strategy_ (false), service_name_ (0), service_description_ (0) { ACE_TRACE ("ACE_Strategy_Acceptor::ACE_Strategy_Acceptor"); if (this->open (addr, reactor, cre_s, acc_s, con_s, sch_s, service_name, service_description, use_select, reuse_addr) == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Strategy_Acceptor::ACE_Strategy_Acceptor"))); } // Perform termination activities when is removed from the // . template int ACE_Strategy_Acceptor::handle_close (ACE_HANDLE, ACE_Reactor_Mask) { ACE_TRACE ("ACE_Strategy_Acceptor::handle_close"); // Guard against multiple closes. if (this->reactor () != 0) { ACE_HANDLE handle = this->get_handle (); if (this->delete_creation_strategy_) delete this->creation_strategy_; this->delete_creation_strategy_ = false; this->creation_strategy_ = 0; if (this->delete_accept_strategy_) delete this->accept_strategy_; this->delete_accept_strategy_ = false; this->accept_strategy_ = 0; if (this->delete_concurrency_strategy_) delete this->concurrency_strategy_; this->delete_concurrency_strategy_ = false; this->concurrency_strategy_ = 0; if (this->delete_scheduling_strategy_) delete this->scheduling_strategy_; this->delete_scheduling_strategy_ = false; this->scheduling_strategy_ = 0; // We must use the obtained *before* we deleted the // accept_strategy_... this->reactor ()->remove_handler (handle, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); // Set the Reactor to 0 so that we don't try to close down // again. this->reactor (0); } return 0; } // Bridge method for creating a . The strategy for // creating a are configured into the Acceptor via it's // . The default is to create a new // . However, subclasses can override this strategy to // perform creation in any way that they like (such as // creating subclass instances of , using a singleton, // dynamically linking the handler, etc.). template int ACE_Strategy_Acceptor::make_svc_handler (SVC_HANDLER *&sh) { ACE_TRACE ("ACE_Strategy_Acceptor::make_svc_handler"); return this->creation_strategy_->make_svc_handler (sh); } // Bridge method for accepting the new connection into the // . The default behavior delegates to the // in the Acceptor_Strategy. template int ACE_Strategy_Acceptor::accept_svc_handler (SVC_HANDLER *svc_handler) { ACE_TRACE ("ACE_Strategy_Acceptor::accept_svc_handler"); return this->accept_strategy_->accept_svc_handler (svc_handler); } // Bridge method for activating a with the appropriate // concurrency strategy. The default behavior of this method is to // activate the SVC_HANDLER by calling its open() method (which allows // the SVC_HANDLER to define its own concurrency strategy). However, // subclasses can override this strategy to do more sophisticated // concurrency activations (such as creating the SVC_HANDLER as an // "active object" via multi-threading or multi-processing). template int ACE_Strategy_Acceptor::activate_svc_handler (SVC_HANDLER *svc_handler) { ACE_TRACE ("ACE_Strategy_Acceptor::activate_svc_handler"); return this->concurrency_strategy_->activate_svc_handler (svc_handler, (void *) this); } template ACE_Strategy_Acceptor::~ACE_Strategy_Acceptor () { ACE_TRACE ("ACE_Strategy_Acceptor::~ACE_Strategy_Acceptor"); ACE_OS::free ((void *) this->service_name_); ACE_OS::free ((void *) this->service_description_); this->handle_close (); } // Signal the server to shutdown gracefully. template int ACE_Strategy_Acceptor::handle_signal (int, siginfo_t *, ucontext_t *) { ACE_Reactor::instance()->end_reactor_event_loop (); return 0; } template int ACE_Strategy_Acceptor::info (ACE_TCHAR **strp, size_t length) const { ACE_TRACE ("ACE_Strategy_Acceptor::info"); ACE_TCHAR service_addr_str[BUFSIZ]; typename PEER_ACCEPTOR::PEER_ADDR addr; if (this->acceptor ().get_local_addr (addr) == -1) return -1; else if (addr.addr_to_string (service_addr_str, sizeof service_addr_str) == -1) return -1; // // gcc10 complains that it is possible that buf could be truncated by up to // 6 bytes in this call to snprintf. Technically, this is possible // (however unlikely that may be). Since service_addr_str is defined to be // of size BUFSIZ, gcc assumes that the string could actually be BUFSIZ in // length. That makes the possible total length of the combined string // (given the size of the literal string constants) 5 + BUFSIZE + 1. // const size_t additional = 6; ACE_TCHAR buf[BUFSIZ + additional]; ACE_OS::snprintf (buf, sizeof buf, ACE_TEXT ("%s\t %s #%s\n"), this->service_name_ == 0 ? ACE_TEXT ("") : this->service_name_, service_addr_str, this->service_description_ == 0 ? ACE_TEXT ("") : this->service_description_); if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) return -1; else ACE_OS::strsncpy (*strp, buf, length); return static_cast (ACE_OS::strlen (buf)); } template int ACE_Strategy_Acceptor::fini () { ACE_TRACE ("ACE_Strategy_Acceptor::fini"); return this->ACE_Strategy_Acceptor::handle_close (); } ACE_ALLOC_HOOK_DEFINE_Tca(ACE_Oneshot_Acceptor) template void ACE_Oneshot_Acceptor::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Oneshot_Acceptor::dump"); ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nsvc_handler_ = %x"), this->svc_handler_)); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nrestart_ = %d"), this->restart_)); this->peer_acceptor_.dump (); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("delete_concurrency_strategy_ = %d"), delete_concurrency_strategy_)); this->concurrency_strategy_->dump (); ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* ACE_HAS_DUMP */ } template int ACE_Oneshot_Acceptor::open (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, ACE_Reactor *reactor, ACE_Concurrency_Strategy *con_s) { ACE_TRACE ("ACE_Oneshot_Acceptor::open"); this->reactor (reactor); // Initialize the concurrency strategy. if (con_s == 0) { ACE_NEW_RETURN (con_s, ACE_Concurrency_Strategy, -1); this->delete_concurrency_strategy_ = true; } this->concurrency_strategy_ = con_s; // Reuse the addr, even if it is already in use...! return this->peer_acceptor_.open (local_addr, 1); } template ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor () : svc_handler_ (0), restart_ (false), concurrency_strategy_ (0), delete_concurrency_strategy_ (false) { ACE_TRACE ("ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor"); this->reactor (0); } template ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, ACE_Reactor *reactor, ACE_Concurrency_Strategy *cs) : svc_handler_ (0), restart_ (false), concurrency_strategy_ (0), delete_concurrency_strategy_ (false) { ACE_TRACE ("ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor"); if (this->open (local_addr, reactor, cs) == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor"))); } template ACE_Oneshot_Acceptor::~ACE_Oneshot_Acceptor () { ACE_TRACE ("ACE_Oneshot_Acceptor::~ACE_Oneshot_Acceptor"); this->handle_close (); } template int ACE_Oneshot_Acceptor::close () { ACE_TRACE ("ACE_Oneshot_Acceptor::close"); return this->handle_close (); } template int ACE_Oneshot_Acceptor::handle_close (ACE_HANDLE, ACE_Reactor_Mask) { ACE_TRACE ("ACE_Oneshot_Acceptor::handle_close"); // Guard against multiple closes. if (this->delete_concurrency_strategy_) { delete this->concurrency_strategy_; this->delete_concurrency_strategy_ = false; this->concurrency_strategy_ = 0; } // Note that if we aren't actually registered with the // ACE_Reactor then it's ok for this call to fail... if (this->reactor ()) this->reactor ()->remove_handler (this, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); if (this->peer_acceptor_.close () == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("close\n"))); return 0; } template int ACE_Oneshot_Acceptor::handle_timeout (const ACE_Time_Value &tv, const void *arg) { ACE_TRACE ("ACE_Oneshot_Acceptor::handle_timeout"); errno = ETIME; if (this->svc_handler_->handle_timeout (tv, arg) == -1) this->svc_handler_->handle_close (this->svc_handler_->get_handle (), ACE_Event_Handler::TIMER_MASK); // Since we aren't necessarily registered with the Reactor, don't // bother to check the return value here... if (this->reactor ()) this->reactor ()->remove_handler (this, ACE_Event_Handler::ACCEPT_MASK); return 0; } template int ACE_Oneshot_Acceptor::cancel () { ACE_TRACE ("ACE_Oneshot_Acceptor::cancel"); return this->reactor () && this->reactor ()->cancel_timer (this); } template int ACE_Oneshot_Acceptor::register_handler (SVC_HANDLER *svc_handler, const ACE_Synch_Options &synch_options, bool restart) { ACE_TRACE ("ACE_Oneshot_Acceptor::register_handler"); // Can't do this if we don't have a Reactor. if (this->reactor () == 0) { errno = EINVAL; return -1; } else { this->svc_handler_ = svc_handler; this->restart_ = restart; ACE_Time_Value *tv = (ACE_Time_Value *) synch_options.time_value (); if (tv != 0 && this->reactor ()->schedule_timer (this, synch_options.arg (), *tv) == -1) return -1; else return this->reactor ()->register_handler (this, ACE_Event_Handler::ACCEPT_MASK); } } // Bridge method for activating a with the appropriate // concurrency strategy. The default behavior of this method is to // activate the SVC_HANDLER by calling its open() method (which allows // the SVC_HANDLER to define its own concurrency strategy). However, // subclasses can override this strategy to do more sophisticated // concurrency activations (such as creating the SVC_HANDLER as an // "active object" via multi-threading or multi-processing). template int ACE_Oneshot_Acceptor::activate_svc_handler (SVC_HANDLER *svc_handler) { ACE_TRACE ("ACE_Oneshot_Acceptor::activate_svc_handler"); return this->concurrency_strategy_->activate_svc_handler (svc_handler, (void *) this); } // Factors out the code shared between the and // methods. template int ACE_Oneshot_Acceptor::shared_accept (SVC_HANDLER *svc_handler, typename PEER_ACCEPTOR::PEER_ADDR *remote_addr, ACE_Time_Value *timeout, bool restart, bool reset_new_handle) { ACE_TRACE ("ACE_Oneshot_Acceptor::shared_accept"); if (svc_handler == 0) return -1; // Accept connection into the Svc_Handler. else if (this->peer_acceptor_.accept (svc_handler->peer (), // stream remote_addr, // remote address timeout, // timeout restart, // restart reset_new_handle // reset new handle ) == -1) { // Check whether we just timed out or whether we failed... if (!(errno == EWOULDBLOCK || errno == ETIME)) // Close down handler to avoid memory leaks. svc_handler->close (CLOSE_DURING_NEW_CONNECTION); return -1; } // Activate the using the designated concurrency // strategy (note that this method becomes responsible for handling // errors and freeing up the memory if things go awry...) else return this->activate_svc_handler (svc_handler); } // Make a SVC_HANDLER, accept the connection into the SVC_HANDLER, and // then activate the SVC_HANDLER. Note that SVC_HANDLER::open() // decides what type of concurrency strategy to use. template int ACE_Oneshot_Acceptor::accept (SVC_HANDLER *svc_handler, typename PEER_ACCEPTOR::PEER_ADDR *remote_addr, const ACE_Synch_Options &synch_options, bool restart, bool reset_new_handle) { ACE_TRACE ("ACE_Oneshot_Acceptor::accept"); // Note that if timeout == ACE_Time_Value (x, y) where (x > 0 || y > // 0) then this->connector_.connect() will block synchronously. If // is set then we don't want this to happen (since we // want the ACE_Reactor to do the timeout asynchronously). // Therefore, we'll force this->connector_ to use ACE_Time_Value (0, // 0) in this case... ACE_Time_Value *timeout; int const use_reactor = synch_options[ACE_Synch_Options::USE_REACTOR]; if (use_reactor) timeout = (ACE_Time_Value *) &ACE_Time_Value::zero; else timeout = (ACE_Time_Value *) synch_options.time_value (); if (this->shared_accept (svc_handler, // stream remote_addr, // remote address timeout, // timeout restart, // restart reset_new_handle // reset new handler ) == -1) { if (use_reactor && errno == EWOULDBLOCK) // We couldn't accept right away, so let's wait in the // . this->register_handler (svc_handler, synch_options, restart); return -1; } return 0; } // Accepts one pending connection from a client (since we're the // "oneshot" Acceptor). template int ACE_Oneshot_Acceptor::handle_input (ACE_HANDLE) { ACE_TRACE ("ACE_Oneshot_Acceptor::handle_input"); int result = 0; // Cancel any timer that might be pending. this->cancel (); // Try to find out if the implementation of the reactor that we are // using requires us to reset the event association for the newly // created handle. This is because the newly created handle will // inherit the properties of the listen handle, including its event // associations. ACE_Reactor *reactor = this->reactor (); bool reset_new_handle = false; // There is a use-case whereby this object will be gone upon return // from shared_accept - if the Svc_Handler deletes this Oneshot_Acceptor // during the shared_accept/activation steps. So, do whatever we need // to do with this object before calling shared_accept. if (reactor) { reset_new_handle = reactor->uses_event_associations (); reactor->remove_handler (this, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); } if (this->shared_accept (this->svc_handler_, // stream 0, // remote address 0, // timeout this->restart_, // restart reset_new_handle // reset new handle ) == -1) result = -1; return result; } // Hook called by the explicit dynamic linking facility. template int ACE_Oneshot_Acceptor::init (int, ACE_TCHAR *[]) { ACE_TRACE ("ACE_Oneshot_Acceptor::init"); return -1; } template int ACE_Oneshot_Acceptor::fini () { ACE_TRACE ("ACE_Oneshot_Acceptor::fini"); return this->handle_close (); } template int ACE_Oneshot_Acceptor::info (ACE_TCHAR **strp, size_t length) const { ACE_TRACE ("ACE_Oneshot_Acceptor::info"); ACE_TCHAR buf[BUFSIZ]; ACE_TCHAR addr_str[BUFSIZ]; typename PEER_ACCEPTOR::PEER_ADDR addr; if (this->peer_acceptor_.get_local_addr (addr) == -1) return -1; else if (addr.addr_to_string (addr_str, sizeof addr_str) == -1) return -1; ACE_OS::snprintf (buf, BUFSIZ, ACE_TEXT ("%s\t %s %s"), ACE_TEXT ("ACE_Oneshot_Acceptor"), addr_str, ACE_TEXT ("#oneshot acceptor factory\n")); if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) return -1; else ACE_OS::strsncpy (*strp, buf, length); return static_cast (ACE_OS::strlen (buf)); } template int ACE_Oneshot_Acceptor::suspend () { ACE_TRACE ("ACE_Oneshot_Acceptor::suspend"); return this->reactor () && this->reactor ()->suspend_handler (this); } template int ACE_Oneshot_Acceptor::resume () { ACE_TRACE ("ACE_Oneshot_Acceptor::resume"); return this->reactor () && this->reactor ()->resume_handler (this); } // Returns ACE_HANDLE of the underlying peer_acceptor. template ACE_HANDLE ACE_Oneshot_Acceptor::get_handle () const { ACE_TRACE ("ACE_Oneshot_Acceptor::get_handle"); return this->peer_acceptor_.get_handle (); } template PEER_ACCEPTOR & ACE_Oneshot_Acceptor::acceptor () const { ACE_TRACE ("ACE_Oneshot_Acceptor::acceptor"); return (PEER_ACCEPTOR &) this->peer_acceptor_; } template ACE_Oneshot_Acceptor::operator PEER_ACCEPTOR & () const { ACE_TRACE ("ACE_Oneshot_Acceptor::operator PEER_ACCEPTOR &"); return (PEER_ACCEPTOR &) this->peer_acceptor_; } ACE_END_VERSIONED_NAMESPACE_DECL #endif /* ACE_ACCEPTOR_CPP */