// $Id$ #define ACE_BUILD_SVC_DLL #include "ace/SString.h" #include "ace/Containers.h" #include "ace/Get_Opt.h" #include "TS_Server_Handler.h" #include "ace/OS_NS_time.h" #include "ace/Signal.h" ACE_RCSID(lib, TS_Server_Handler, "$Id$") #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class ACE_Accept_Strategy; template class ACE_Acceptor; template class ACE_Concurrency_Strategy; template class ACE_Creation_Strategy; template class ACE_Schedule_All_Reactive_Strategy; template class ACE_Scheduling_Strategy; template class ACE_Strategy_Acceptor; #if defined (ACE_HAS_STREAM_PIPES) template class ACE_Svc_Handler; // #else the instantiation in is Client_Logging_Handler.cpp #endif /* ACE_HAS_STREAM_PIPES */ #elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) #pragma instantiate ACE_Accept_Strategy #pragma instantiate ACE_Acceptor #pragma instantiate ACE_Concurrency_Strategy #pragma instantiate ACE_Creation_Strategy #pragma instantiate ACE_Schedule_All_Reactive_Strategy #pragma instantiate ACE_Scheduling_Strategy #pragma instantiate ACE_Strategy_Acceptor #if defined (ACE_HAS_STREAM_PIPES) #pragma instantiate ACE_Svc_Handler // #else the instantiation in is Client_Logging_Handler.cpp #endif /* ACE_HAS_STREAM_PIPES */ #endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ int ACE_TS_Server_Acceptor::parse_args (int argc, ACE_TCHAR *argv[]) { ACE_TRACE ("ACE_TS_Server_Acceptor::parse_args"); int service_port = ACE_DEFAULT_SERVER_PORT; ACE_LOG_MSG->open (ACE_TEXT ("Time Service")); ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:"), 0); for (int c; (c = get_opt ()) != -1; ) { switch (c) { case 'p': service_port = ACE_OS::atoi (get_opt.opt_arg ()); break; default: ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%n:\n[-p server-port]\n"), 1), -1); } } this->service_addr_.set (service_port); return 0; } int ACE_TS_Server_Acceptor::init (int argc, ACE_TCHAR *argv[]) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Acceptor::init")); // Use the options hook to parse the command line arguments and set // options. this->parse_args (argc, argv); // Set the acceptor endpoint into listen mode (use the Singleton // global Reactor...). if (this->open (this->service_addr_, ACE_Reactor::instance (), 0, 0, 0, &this->scheduling_strategy_, ACE_TEXT ("Time Server"), ACE_TEXT ("ACE time service")) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%n: %p on port %d\n"), ACE_TEXT ("acceptor::open failed"), this->service_addr_.get_port_number ()), -1); // Ignore SIGPIPE so that each can handle this on its // own. ACE_Sig_Action sig ((ACE_SignalHandler) SIG_IGN, SIGPIPE); ACE_UNUSED_ARG (sig); ACE_INET_Addr server_addr; // Figure out what port we're really bound to. if (this->acceptor ().get_local_addr (server_addr) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("get_local_addr")), -1); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("starting up Time Server at port %d on handle %d\n"), server_addr.get_port_number (), this->acceptor ().get_handle ())); return 0; } // The following is a "Factory" used by the ACE_Service_Config and // svc.conf file to dynamically initialize the state of the Time Server ACE_SVC_FACTORY_DEFINE (ACE_TS_Server_Acceptor) // Default constructor. ACE_TS_Server_Handler::ACE_TS_Server_Handler (ACE_Thread_Manager *tm) : ACE_Svc_Handler (tm) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::ACE_TS_Server_Handler")); } // Activate this instance of the ACE_TS_Server_Handler (called by the // ACE_TS_Server_Acceptor). /* VIRTUAL */ int ACE_TS_Server_Handler::open (void *) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::open")); ACE_INET_Addr client_addr; // Determine the address of the client and display it. if (this->peer ().get_remote_addr (client_addr) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("get_remote_addr")), -1); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) accepted connection from host %s on fd %d\n"), client_addr.get_host_name (), this->peer ().get_handle ())); // Call down to our parent to register ourselves with the Reactor. if (ACE_Svc_Handler::open (0) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("open")), -1); return 0; } /* VIRTUAL */ int ACE_TS_Server_Handler::send_request (ACE_Time_Request &request) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::send_request")); void *buffer; ssize_t length = request.encode (buffer); if (length == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("encode failed")), -1); // Transmit request via a blocking send. if (this->peer ().send_n (buffer, length) != length) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("send_n failed")), -1); return 0; } // Give up waiting (e.g., when a timeout occurs or a client shuts down // unexpectedly). /* VIRTUAL */ int ACE_TS_Server_Handler::abandon (void) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::abandon")); // Note we are using the time field to report the errno in case of // failure. ACE_Time_Request rq (-1, errno); return this->send_request (rq); } // Enable clients to limit the amount of time they'll wait /* VIRTUAL */ int ACE_TS_Server_Handler::handle_timeout (const ACE_Time_Value &, const void *) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::handle_timeout")); return this->abandon (); } // Return the underlying ACE_HANDLE. /* VIRTUAL */ ACE_HANDLE ACE_TS_Server_Handler::get_handle (void) const { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::get_handle")); return this->peer ().get_handle (); } // Dispatch the appropriate operation to handle the client request. /* VIRTUAL */ int ACE_TS_Server_Handler::dispatch (void) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::dispatch")); // Get the system time and then create an ACE_Time_Request time_t t = ACE_OS::time (0); ACE_Time_Request rq (ACE_Time_Request::TIME_UPDATE, t); return this->send_request (rq); } // Receive, frame, and decode the client's request. Note, this method // should use non-blocking I/O. /* VIRTUAL */ int ACE_TS_Server_Handler::recv_request (void) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::recv_request")); ssize_t bytes_expected = this->time_request_.size (); // Since Time_Request messages are fixed size, read the entire // message in one go. ssize_t n = this->peer ().recv ((void *) &this->time_request_, bytes_expected); if (n != bytes_expected) { switch (n) { case -1: /* FALLTHROUGH */ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("****************** recv_request returned -1\n"))); default: ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p got %d bytes, expected %d bytes\n"), ACE_TEXT ("recv failed"), n, bytes_expected)); /* FALLTHROUGH */ case 0: // We've shutdown unexpectedly, let's abandon the // connection. this->abandon (); return -1; /* NOTREACHED */ } } else { // Decode the request into host byte order. if (this->time_request_.decode () == -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("decode failed"))); return this->abandon (); } } return 0; } // Callback method invoked by the ACE_Reactor when events arrive from // the client. /* VIRTUAL */ int ACE_TS_Server_Handler::handle_input (ACE_HANDLE) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::handle_input")); if (this->recv_request () == -1) return -1; else return this->dispatch (); } ACE_TS_Server_Handler::~ACE_TS_Server_Handler (void) { ACE_TRACE (ACE_TEXT ("ACE_TS_Server_Handler::~ACE_TS_Server_Handler")); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("closing down Handle %d\n"), this->get_handle ())); }