/* Copyright (c) 2000 by Inria Lorraine.  All Rights Reserved */

#ifndef __JVM_UTILS
#define __JVM_UTILS
  
/*
 * Include 
 */
#include "jni.h"

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>	/* Defines TCP_NODELAY, needed for 2.6 */
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <arpa/inet.h>

#include "portability.h"

#if JDK_VERSION < 2
#include "java_options.h"
#endif



/*
 * Macros and misc constants
 */
#define MAX_PACKET_LEN 65536
#define MAX_BUFFER_LEN 2048
#define V6_SIZE 16
#define NET_ERROR(env, ex, msg) \
	if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg)
#define IS_NULL(obj) ((obj) == NULL)


/*
 * Cached field IDs
 *
 * The naming convention for field IDs is
 *      <class abbrv>_<fieldName>ID
 * i.e. psi_timeoutID is PlainSocketImpl's timeout field's ID.
 */
extern jfieldID ia_addressID;
extern jfieldID ia_familyID;

/* PlainSocketImpl fields */
extern jfieldID psi_timeoutID;
extern jfieldID psi_fdID;
extern jfieldID psi_addressID;
extern jfieldID psi_portID;
extern jfieldID psi_localportID;

/* DatagramPacket fields */
extern jfieldID dp_addressID;
extern jfieldID dp_portID;
extern jfieldID dp_bufID;
extern jfieldID dp_offsetID;
extern jfieldID dp_lengthID;

/* RawPacket fields */
extern jfieldID rp_addressID;
extern jfieldID rp_bufID;
extern jfieldID rp_offsetID;
extern jfieldID rp_lengthID;

/* 
 * JVM IO
 */
#define JVM_IO_ERR  (-1)
#define JVM_IO_INTR (-2)

JNIEXPORT jint JNICALL JVM_Bind(jint, struct sockaddr *, jint);
JNIEXPORT jint JNICALL JVM_GetSockName(jint, struct sockaddr *him, int *len);
JNIEXPORT jint JNICALL JVM_GetSockOpt(jint, int, int, char *, int *);
JNIEXPORT jint JNICALL JVM_SetSockOpt(jint, int, int, const char *, int);
JNIEXPORT jint JNICALL JVM_InitializeSocketLibrary();
JNIEXPORT jint JNICALL JVM_Timeout(jint, int);
JNIEXPORT jint JNICALL JVM_SendTo(jint,char *,int,int,struct sockaddr *,int);
JNIEXPORT jint JNICALL JVM_RecvFrom(jint,char*,int,int,struct sockaddr*,int*);
JNIEXPORT jint JNICALL JVM_Socket(jint,int, int); 
JNIEXPORT jint JNICALL JVM_Close(jint);
JNIEXPORT jint JNICALL JVM_Read(jint, char *, jint);
JNIEXPORT jint JNICALL JVM_Write(jint fd, char *, jint);
JNIEXPORT jint JNICALL JVM_Send(jint, char *, jint, jint); 
JNIEXPORT jint JNICALL JVM_Recv(jint, char *, jint, jint);
JNIEXPORT jint JNICALL JVM_Connect(jint, struct sockaddr *, jint);
JNIEXPORT jint JNICALL JVM_Listen(jint, jint);
JNIEXPORT jint JNICALL JVM_Accept(jint, struct sockaddr *, jint *);
JNIEXPORT jint JNICALL JVM_SocketAvailable(jint, jint *);
JNIEXPORT jint JNICALL JVM_SocketClose(jint);

#if JDK_VERSION < 3
#  if JDK_VERSION < 2
#    define CONVERT_TO_JVM_FD(fd)   ((fd) + 1)
#    define CONVERT_FROM_JVM_FD(fd) ((fd) - 1)
#  else
#    define CONVERT_TO_JVM_FD(fd)   (fd)
#    define CONVERT_FROM_JVM_FD(fd) (fd)
#  endif

#  define JVM_Bind(fd, in, len)                                             \
	bind(CONVERT_FROM_JVM_FD(fd), in, len)
#  define JVM_GetSockName(fd, in, len)                                      \
	getsockname(CONVERT_FROM_JVM_FD(fd), in, len)
#  define JVM_SetSockOpt(fd, type, optname, optval, len)                    \
	setsockopt(CONVERT_FROM_JVM_FD(fd), type, optname, optval, len)
#  define JVM_GetSockOpt(fd, type, optname, optval, len)                    \
	getsockopt(CONVERT_FROM_JVM_FD(fd), type, optname, optval, len)
#endif

#if JDK_VERSION >= 2
int jio_snprintf(char *, int, char *, ...);
#endif


/* 
 * Package shorthand for use by native libraries
 */
#define JNU_JAVAPKG         "java/lang/"
#define JNU_JAVAIOPKG       "java/io/"
#define JNU_JAVANETPKG      "java/net/"

/*
 * Exception handling
 */
#define SocketException           "java/net/SocketException"
#define RuntimeException          "java/lang/RuntimeException"
#define BindException             "java/net/BindException"
#define NullPointerException      "java/lang/NullPointerException"
#define OutOfMemoryError          "java/lang/OutOfMemoryError"
#define IOException               "java/io/IOException"
#define InterruptedIOException    "java/io/InterruptedIOException"
#define IllegalArgumentException  "java/lang/IllegalArgumentException"

#define THROW(env, name, msg, r...)                         \
	do {                                                \
	    jclass cls = (*env)->FindClass(env, name);      \
	    if (cls != 0)                                   \
	        (*env)->ThrowNew(env, cls, msg);            \
	    (*env)->DeleteLocalRef(env, cls);               \
	    return r;                                       \
	} while(0)

JNIEXPORT void JNICALL 
JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg);
JNIEXPORT void JNICALL 
JNU_ThrowNullPointerException(JNIEnv *env, const char *msg);
JNIEXPORT void JNICALL 
JNU_ThrowOutOfMemoryError(JNIEnv *env, const char *msg);
JNIEXPORT void JNICALL 
JNU_ThrowIOException(JNIEnv *env, const char *msg);

/* 
 * JNI utilities declaration
 */
#if JDK_VERSION >= 2
JNIEXPORT const char * JNICALL
JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy);
JNIEXPORT jclass JNICALL 
JNU_ClassString(JNIEnv *env);
JNIEXPORT jvalue JNICALL
JNU_CallStaticMethodByName(JNIEnv *env,
			   jboolean *hasException,
			   const char *class_name, 
			   const char *name, 
			   const char *signature,
			   ...);
#endif

/*
 *  Utilities
 */
void NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg);
void NET_ThrowCurrent(JNIEnv *env, char *msg);
jfieldID NET_GetFileDescriptorID(JNIEnv *env);

#endif /* __JVM_UTILS */
