#include <string.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>

#include "toba.h"
#include "runtime.h"
#include "java_net_InetAddress.h"

/* java/net/InetAddress getLocalHostName ()Ljava/lang/String; */
Object getLocalHostName__gguOm() 
{
    struct utsname uts;

    /* STATIC Method */
    init_java_net_InetAddress();

    if(uname(&uts) == -1)
        throwUnknownHostException("getLocalHostName");
    return javastring(uts.nodename);
}

/* java/net/InetAddress makeAnyLocalAddress (Ljava/net/InetAddress;)V */
Void makeAnyLocalAddress_I_JDvzQ(Object Harg1) 
{
    struct in_java_net_InetAddress *arg1 = 
        (struct in_java_net_InetAddress *)Harg1;

    /* STATIC Method */
    init_java_net_InetAddress();

    if(!arg1)
        throwNullPointerException("makeAnyLocalAddress");

    arg1->address = INADDR_ANY;
}

/* java/net/InetAddress lookupHostAddr (Ljava/lang/String;)[B */
Object lookupHostAddr_S_s7j35(Object Harg1) 
{
    struct in_java_lang_String *arg1 = (struct in_java_lang_String *)Harg1;
    struct barray *res;
    struct hostent *hp;
    char *hostname;

    /* STATIC Method */
    init_java_net_InetAddress();

    hostname = cstring(arg1);
    hp = gethostbyname(hostname);
    if(!hp || hp->h_addrtype != AF_INET)
        throwUnknownHostException("lookupHostAddr");

    res = (struct barray *)anewarray(&cl_byte, 4);
    memcpy(res->data, hp->h_addr, 4);

    return res;
}

/* java/net/InetAddress lookupAllHostAddr (Ljava/lang/String;)[[B */
Object lookupAllHostAddr_S_kZ9BK(Object Harg1) 
{
    struct in_java_lang_String *arg1 = (struct in_java_lang_String *)Harg1;
    struct aarray *res;
    struct barray *addr;
    struct hostent *hp;
    char *hostname;
    int count, i;

    /* STATIC Method */
    init_java_net_InetAddress();

    hostname = cstring(arg1);
    hp = gethostbyname(hostname);
    if(!hp || hp->h_addrtype != AF_INET)
        throwUnknownHostException("lookupHostAddr");

    count = 0;
    for(i = 0; hp->h_addr_list[i]; i++)
        count++;

    addr = anewarray(&cl_byte, 4);
    res = anewarray(addr->class, count);
    for(i = 0; i < count; i++) {
        if(i == 0)
            res->data[i] = addr;
        else
            res->data[i] = anewarray(&cl_byte, 4);
        addr = (struct barray *)res->data[i];
        memcpy(addr->data, hp->h_addr_list[i], 4);
    }

    return res;
}


struct ghba_state {
#ifdef _REENTRANT
#ifdef sun
#define GETHOSTBUFSIZE 		(MAXHOSTNAMELEN * 8)
    char buf[GETHOSTBUFSIZE];
#else
    struct hostent_data hed;
#endif
#else
    int dummy;
#endif
};

static struct hostent *
portable_gethostbyaddr_r(char *data, int len, int family, 
                         struct hostent *hep, struct ghba_state *state)
/*ARGSUSED*/
{
    struct hostent *hp;
    int err;

#ifdef _REENTRANT
#ifdef sun
    /* sun botched gethostbyaddr_r */
    hp = gethostbyaddr_r(data, len, family, 
                         hep, state->buf, GETHOSTBUFSIZE, &err);
#else
    err = gethostbyaddr_r(data, len, family, hep, &state->hed);
    hp = (err == -1) ? 0 : hep;
#endif
#else
    hp = gethostbyaddr(data, len, family);
#endif

    return hp;
}

/* java/net/InetAddress getHostByAddr (I)Ljava/lang/String; */
Object getHostByAddr_i_ZxQD9(Int arg1) 
{
    struct in_java_lang_String *res;
    struct hostent h, *hp;
    struct ghba_state state;

    /* STATIC Method */
    init_java_net_InetAddress();

    /* we're not synchronized - must use re-entrant version */
    hp = portable_gethostbyaddr_r((char *)&arg1, 4, AF_INET, &h, &state);
    if(!hp)
        throwUnknownHostException("getHostByAddr");
    res = javastring(hp->h_name);

    return res;
}

/* java/net/InetAddress getInetFamily ()I */
Int getInetFamily__XVxvA() 
{
    /* STATIC Method */
    init_java_net_InetAddress();

    return AF_INET;
}

