/* Copyright (C) 2003  Free Software Foundation

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

#include <config.h>
#include <platform.h>

#undef STRICT

#include <java/net/InetAddress.h>
#include <java/net/UnknownHostException.h>
#include <java/lang/SecurityException.h>

jbyteArray
java::net::InetAddress::aton (jstring host)
{
  JV_TEMP_UTF_STRING (hostname, host);
  char* bytes = NULL;
  int blen = 0;
  unsigned long laddr = inet_addr (hostname);
  if (laddr != INADDR_NONE)
    {
      bytes = (char*) &laddr;
      blen = 4;
    }
  if (blen == 0)
    return NULL;
  jbyteArray result = JvNewByteArray (blen);
  memcpy (elements (result), bytes, blen);
  return result;
}

jint
java::net::InetAddress::getFamily (jbyteArray bytes)
{
  int len = bytes->length;
  if (len == 4)
    return AF_INET;
#ifdef HAVE_INET6
  else if (len == 16)
    return AF_INET6;
#endif /* HAVE_INET6 */
  else
    JvFail ("unrecognized size");
}


JArray<java::net::InetAddress*> *
java::net::InetAddress::lookup (jstring host, java::net::InetAddress* iaddr,
        jboolean all)
{
  struct hostent *hptr = NULL;
  if (host != NULL)
    {
      JV_TEMP_UTF_STRING (hostname, host);

      // FIXME: this is insufficient if some other piece of code calls
      // this gethostbyname.
      JvSynchronize sync (java::net::InetAddress::loopbackAddress);
      hptr = gethostbyname (hostname);
    }
  else
    {
      jbyteArray bytes = iaddr->addr;
      char *chars = (char*) elements (bytes);
      int len = bytes->length;
      int type;
      char *val;
      if (len == 4)
        {
          val = chars;
          type = iaddr->family = AF_INET;
        }
#ifdef HAVE_INET6
      else if (len == 16)
      {
        val = (char *) &chars;
        type = iaddr->family = AF_INET6;
      }
#endif /* HAVE_INET6 */
      else
        JvFail ("unrecognized size");

      // FIXME: this is insufficient if some other piece of code calls
      // this gethostbyaddr.
      JvSynchronize sync (java::net::InetAddress::loopbackAddress);
      hptr = gethostbyaddr (val, len, type);
    }
  if (hptr != NULL)
    {
      if (!all)
        host = JvNewStringUTF (hptr->h_name);
      java::lang::SecurityException *ex = checkConnect (host);
      if (ex != NULL)
        {
          if (iaddr == NULL || iaddr->addr == NULL)
            throw ex;
          hptr = NULL;
        }
    }
  if (hptr == NULL)
    {
      if (iaddr != NULL && iaddr->addr != NULL)
        {
          iaddr->hostName = iaddr->getHostAddress();
          return NULL;
        }
      else
        throw new java::net::UnknownHostException(host);
    }

  int count;
  if (all)
    {
      char** ptr = hptr->h_addr_list;
      count = 0;
      while (*ptr++)  count++;
    }
  else
    count = 1;

  JArray<java::net::InetAddress*> *result;
  java::net::InetAddress** iaddrs;
  if (all)
    {
      result = java::net::InetAddress::allocArray (count);
      iaddrs = elements (result);
    }
  else
    {
      result = NULL;
      iaddrs = &iaddr;
    }

  for (int i = 0;  i < count;  i++)
    {
      if (iaddrs[i] == NULL)
        iaddrs[i] = new java::net::InetAddress (NULL, NULL);
      if (iaddrs[i]->hostName == NULL)
        iaddrs[i]->hostName = host;
      if (iaddrs[i]->addr == NULL)
        {
          char *bytes = hptr->h_addr_list[i];
          iaddrs[i]->addr = JvNewByteArray (hptr->h_length);
          iaddrs[i]->family = getFamily (iaddrs[i]->addr);
          memcpy (elements (iaddrs[i]->addr), bytes, hptr->h_length);
        }
    }
    
  return result;
}

jstring
java::net::InetAddress::getLocalHostname ()
{
  char buffer[400];
  if (gethostname (buffer, sizeof(buffer)))
    return NULL;
  // It is admittedly non-optimal to convert the hostname to Unicode
  // only to convert it back in getByName, but simplicity wins.  Note
  // that unless there is a SecurityManager, we only get called once
  // anyway, thanks to the InetAddress.localhost cache.
  return JvNewStringUTF (buffer);
}
