// Max_Default_Port_Test_IPV6.cpp,v 4.5 2004/03/12 11:02:25 jwillemsen Exp
// ============================================================================
/**
 * @file Max_Default_Port_Test_IPV6.cpp
 *
 * @brief 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 300 port values and tested if the
 * highest port number used agrees with ACE_MAX_DEFAULT_PORT value.
 *
 * @author Chanaka Liyanaarachchi <chanaka@ociweb.com>
 *         Brian Buesker <bbuesker@qualcomm.com>
 */
// ============================================================================

#include "test_config.h"
#include "ace/Reactor.h"
#include "ace/SOCK_Connector.h"
#include "ace/Thread_Manager.h"

#include "Max_Default_Port_Test.h"

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;

#if defined (ACE_HAS_IPV6)
static void *
client (void *arg)
{
  ACE_INET_Addr *remote_addr = ACE_reinterpret_cast (ACE_INET_Addr *,
                                                     arg);

  ACE_INET_Addr server_addr (remote_addr->get_port_number (),
                             "::1");

  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)
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("(%P|%t) %p\n"),
                  ACE_TEXT ("connection failed")));

      return 0;
    }

  // 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;
}
#endif /*ACE_HAS_IPV6*/

int
run_main (int argc, ACE_TCHAR *argv[])
{
  ACE_START_TEST (ACE_TEXT ("Max_Default_Port_Test_IPV6"));

  ACE_UNUSED_ARG (argc);
  ACE_UNUSED_ARG (argv);

#if defined (ACE_HAS_IPV6)
  u_short max_listened_port = 0;

  //Ports beyond 65279 were said to bad on NT sp 3.
  for (u_short idx = USHRT_MAX; idx != USHRT_MAX - 300; --idx)
    {
      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),
           ACE_reinterpret_cast (void *, &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_HAS_IPV6 */

  ACE_END_TEST;
  return 0;
}
