//============================================================================= /** * @file Max_Default_Port_Test.cpp * * This is a test for ACE_MAX_DEFAULT_PORT value. The test tests the * highest value of the port number at which an event handler can be * registered and a Connector can be connected to. * * Some weird behaviour has been reported on Windows NT (sp 3) when * the port number exceeds 65279 resulting ACE_MAX_DEFAULT_PORT to set * to zero on that platform. * * In this test, the event handler is started at the port value * USHRT_MAX and decremented for 'ports_to_test' port values and tested * if the highest port number used agrees with ACE_MAX_DEFAULT_PORT value. * * @author Chanaka Liyanaarachchi */ //============================================================================= #include "test_config.h" #include "ace/Reactor.h" #include "ace/SOCK_Connector.h" #include "ace/Thread_Manager.h" #include "ace/OS_NS_unistd.h" #include "ace/Time_Value.h" #include "Max_Default_Port_Test.h" // implement a retry and recuperation mechanism for VxWorks because test will otherwise fail // on a non-optimized kernel with several ETIME errors on the client connects. #if defined (ACE_VXWORKS) int retry_port_ = 0; #endif My_Accept_Handler::My_Accept_Handler (ACE_INET_Addr &addr) : addr_ (addr) { if (addr.get_port_number() != 0) this->open (addr); } My_Accept_Handler::~My_Accept_Handler () { this->peer_acceptor_.close (); // Prevent handle leaks } int My_Accept_Handler::open (ACE_INET_Addr &addr) { if (this->peer_acceptor_.open (addr, 1) == -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("My_Accept_Handler open"))); ACE_OS::exit (1); } return 0; } ACE_HANDLE My_Accept_Handler::get_handle () const { return this->peer_acceptor_.get_handle (); } int My_Accept_Handler::handle_input (ACE_HANDLE) { if (this->peer_acceptor_.accept(this->stream_, 0) == -1) { ACE_ERROR((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("peer_acceptor.accept"))); ACE_OS::exit(1); } ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("My_Accept_Handler::handle_input\n"))); // Close the opened stream, else it'll leak a handle. Don't close // the acceptor here, though, because get_handle() needs it to // correctly allow removal from the reactor later. It gets closed // in the destructor. this->stream_.close (); return 0; } u_short My_Accept_Handler::port () { return this->addr_.get_port_number(); } long max_connected_port = 0; void * client (void *arg) { ACE_INET_Addr *remote_addr = reinterpret_cast (arg); ACE_INET_Addr server_addr (remote_addr->get_port_number (), ACE_LOCALHOST, AF_INET); ACE_SOCK_Stream cli_stream; ACE_SOCK_Connector con; ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Connecting to port %d\n"), server_addr.get_port_number())); // Initiate connection with server; don't wait forever if (con.connect (cli_stream, server_addr, &timeout) == -1) { #if defined (ACE_VXWORKS) if (errno == ETIME) { if ( ++retry_port_<6 ) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Going to retry port %d\n"), server_addr.get_port_number())); } } if ( retry_port_>5 ) { retry_port_ = 0; #endif ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("connection failed"))); #if defined (ACE_VXWORKS) } #endif return 0; } #if defined (ACE_VXWORKS) retry_port_ = 0; #endif // if connect succesful, what is the max port number we connected // up to now. int connected_port = server_addr.get_port_number (); if (connected_port > max_connected_port) max_connected_port = connected_port; cli_stream.close (); return 0; } int run_main (int argc, ACE_TCHAR *argv[]) { ACE_START_TEST (ACE_TEXT ("Max_Default_Port_Test")); ACE_UNUSED_ARG (argc); ACE_UNUSED_ARG (argv); #ifndef ACE_LACKS_ACCEPT u_short max_listened_port = 0; #if defined (__Lynx__) // LynxOS can handle only 80 test iterations. // This needs to be investigated further -- olli 12.11.2007 const u_short ports_to_test = 80; #else const u_short ports_to_test = 300; #endif //Ports beyond 65279 were said to bad on NT sp 3. for (u_short idx = USHRT_MAX; idx != USHRT_MAX - ports_to_test; --idx) { #if defined (ACE_VXWORKS) if (retry_port_>0) { ++idx; ACE_OS::sleep (ACE_Time_Value (2*ACE_DEFAULT_TIMEOUT)); } #endif ACE_INET_Addr addr (idx); My_Accept_Handler *eh = new My_Accept_Handler (addr); if ( ACE_Reactor::instance()->register_handler ( eh, ACE_Event_Handler::ACCEPT_MASK) == -1) { ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Failed to register event handler")), 1); } ACE_DEBUG ((LM_DEBUG, "Registered event handler at %d\n", idx)); ACE_Time_Value tv (1); #if defined (ACE_HAS_THREADS) if (ACE_Thread_Manager::instance ()->spawn_n (1, ACE_THR_FUNC (client), reinterpret_cast (&addr), THR_NEW_LWP | THR_DETACHED) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("thread create failed")), 1); ACE_Thread_Manager::instance ()->wait (); #else ACE_UNUSED_ARG (client); ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) only one thread may be run in a process on this platform\n%a"), 1)); #endif //ACE_HAS_THREADS if (ACE_Reactor::instance()->handle_events (tv) == -1 ) { ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Reactor::handle_events")), 1); } // see if I can register a reactor at this port. if (eh->port () == idx) { if (idx > max_listened_port) max_listened_port = idx; } else { ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Test Fail, listening port %d\n"), eh->port()), 1); } ACE_Reactor::instance()->remove_handler ( eh, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); delete eh; } ACE_DEBUG ((LM_DEBUG, "Value of ACE_MAX_DEFAULT_PORT %d\n", ACE_MAX_DEFAULT_PORT)); ACE_DEBUG ((LM_DEBUG, "Highest port value I can listen at %d\n", max_listened_port)); ACE_DEBUG ((LM_DEBUG, "Highest port value I can connect to %d\n", max_connected_port)); if ((max_listened_port == ACE_MAX_DEFAULT_PORT) && (max_connected_port == ACE_MAX_DEFAULT_PORT)) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Valid ACE_MAX_DEFAULT_PORT value: %d\n"), max_listened_port)); } else { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Invalid ACE_MAX_DEFAULT_PORT ") ACE_TEXT ("or %d port may be busy; got to %d\n"), ACE_MAX_DEFAULT_PORT, max_listened_port)); } #endif // ACE_LACKS_ACCEPT ACE_END_TEST; return 0; }