// Connection_Handler.cpp,v 4.21 2003/11/05 02:04:53 dhinton Exp // ============================================================================ // // = FILENAME // Connection_Handler.cpp // // = DESCRIPTION // This test illustrates how to use the Acceptor pattern to // create multiple threads, each running its own Reactor. You // can connect to this via telnet and keep typing until you enter // '^D'. // // = AUTHOR // Doug Schmidt // // ============================================================================ #include "ace/Acceptor.h" #include "ace/SOCK_Acceptor.h" #include "ace/Service_Config.h" #include "ace/Thread.h" #include "ace/Signal.h" #include "Connection_Handler.h" ACE_RCSID(misc, Connection_Handler, "Connection_Handler.cpp,v 4.21 2003/11/05 02:04:53 dhinton Exp") int Connection_Handler::open (void *) { ACE_DEBUG ((LM_DEBUG, "(%P|%t) in open()\n")); // Make ourselves an Active Object. return this->activate (THR_NEW_LWP | THR_DETACHED); } int Connection_Handler::close (u_long) { ACE_DEBUG ((LM_DEBUG, "(%P|%t) in close()\n")); // Shut ourself down. Note that this doesn't destroy the thread, // just the state of the object. this->destroy (); return 0; } int Connection_Handler::svc (void) { ACE_DEBUG ((LM_DEBUG, "(%P|%t) in svc()\n")); this->finished_ = 0; // Create our own personal Reactor just for this thread. Note that // we create this on the stack of the thread since it's only used // for the duration of this connection! ACE_Reactor reactor; // Each <ACE_Svc_Handler> has its own <ACE_Reactor *>. By default, // this points to the <Acceptor's> Reactor. However, we can point // it to our local Reactor, which is what we do in this case. this->reactor (&reactor); // Register ourselves to handle input in this thread without // blocking. if (this->reactor ()->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) ACE_ERROR_RETURN ((LM_ERROR, "can' (%P|%t) t register with reactor\n"), -1); // Schedule a timer. else if (this->reactor ()->schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1) ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); else ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with client\n")); // Keep looping until we receive SIGQUIT or the client shutsdown. while (this->finished_ == 0) { ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling events\n")); this->reactor ()->handle_events (); } // Cancel all pending timeouts. this->reactor ()->cancel_timer (this); // Remove ourselves from the Reactor. this->reactor ()->remove_handler (this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL); // Zero-out the Reactor field so it isn't accessed later on. this->reactor (0); ACE_DEBUG ((LM_DEBUG, "(%P|%t) exiting svc\n")); return 0; } int Connection_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask) { ACE_DEBUG ((LM_DEBUG, "(%P|%t) in handle_close \n")); // Signal the svc() event loop to shut down. this->finished_ = 1; return 0; } int Connection_Handler::handle_input (ACE_HANDLE) { char buf[BUFSIZ]; ACE_DEBUG ((LM_DEBUG, "(%P|%t) handle_input\n")); switch (this->peer ().recv (buf, sizeof buf)) { case -1: ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); case 0: ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1); default: if (buf[0] == (char) EOF) ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1); else ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", buf)); } return 0; } int Connection_Handler::handle_signal (int signum, siginfo_t *, ucontext_t *) { // @@ Note that this code is not portable to all OS platforms since // it uses print statements within signal handler context. ACE_DEBUG ((LM_DEBUG, "received signal %S\n", signum)); this->finished_ = 1; return 0; } int Connection_Handler::handle_timeout (const ACE_Time_Value &tv, const void *arg) { ACE_UNUSED_ARG (tv); #if defined (ACE_NDEBUG) ACE_UNUSED_ARG (arg); #endif /* ACE_NDEBUG */ ACE_ASSERT (arg == this); ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this)); return 0; } // Define an Acceptor for the <Connection_Handler>. typedef ACE_Acceptor <Connection_Handler, ACE_SOCK_ACCEPTOR> Connection_Acceptor; int main (int argc, char *argv[]) { ACE_Service_Config daemon (argv[0]); u_short port = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; ACE_DEBUG ((LM_DEBUG, "(%P|%t) in main\n")); // Acceptor factory. Connection_Acceptor peer_acceptor; // Create an adapter to end the event loop. ACE_Sig_Adapter sa ((ACE_Sig_Handler_Ex) ACE_Reactor::end_event_loop); // Register the signal handler adapter. if (ACE_Reactor::instance ()->register_handler (SIGINT, &sa) == -1) ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "register_handler"), -1); // Open the Acceptor. else if (peer_acceptor.open (ACE_INET_Addr (port), ACE_Reactor::instance ()) == -1) ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up connection server\n")); // Perform connection service until we receive SIGINT. while (ACE_Reactor::event_loop_done() == 0) ACE_Reactor::run_event_loop (); ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down connection server\n")); return 0; } #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class ACE_Acceptor<Connection_Handler, ACE_SOCK_ACCEPTOR>; template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; #elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) #pragma instantiate ACE_Acceptor<Connection_Handler, ACE_SOCK_ACCEPTOR> #pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> #endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */