summaryrefslogtreecommitdiff
path: root/native
diff options
context:
space:
mode:
Diffstat (limited to 'native')
-rw-r--r--native/fdlibm/mprec.c8
-rw-r--r--native/fdlibm/mprec.h2
-rw-r--r--native/jni/classpath/jcl.c131
-rw-r--r--native/jni/gconf-peer/GConfNativePeer.c117
-rw-r--r--native/jni/gconf-peer/Makefile.am2
-rw-r--r--native/jni/gtk-peer/cairographics2d.h3
-rw-r--r--native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c75
-rw-r--r--native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoSurface.c24
-rw-r--r--native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkVolatileImage.c22
-rw-r--r--native/jni/java-io/java_io_VMFile.c11
-rw-r--r--native/jni/java-lang/java_lang_VMDouble.c21
-rw-r--r--native/jni/java-lang/java_lang_VMProcess.c23
-rw-r--r--native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c875
-rw-r--r--native/jni/java-net/java_net_VMInetAddress.c87
-rw-r--r--native/jni/java-net/java_net_VMNetworkInterface.c204
-rw-r--r--native/jni/java-nio/Makefile.am10
-rw-r--r--native/jni/java-nio/gnu_java_nio_EpollSelectorImpl.c414
-rw-r--r--native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c387
-rw-r--r--native/jni/java-nio/gnu_java_nio_VMChannel.c1345
-rw-r--r--native/jni/java-nio/gnu_java_nio_VMPipe.c41
-rw-r--r--native/jni/java-nio/java_nio_MappedByteBufferImpl.c5
-rw-r--r--native/jni/java-nio/javanio.c122
-rw-r--r--native/jni/java-nio/javanio.h332
-rw-r--r--native/jni/native-lib/cpio.c20
-rw-r--r--native/jni/native-lib/cpio.h2
-rw-r--r--native/jni/native-lib/cpnet.c56
-rw-r--r--native/jni/native-lib/cpnet.h1
27 files changed, 3942 insertions, 398 deletions
diff --git a/native/fdlibm/mprec.c b/native/fdlibm/mprec.c
index e53722f7b..8a7cdc039 100644
--- a/native/fdlibm/mprec.c
+++ b/native/fdlibm/mprec.c
@@ -101,7 +101,7 @@ typedef unsigned long __ULong;
typedef long __Long;
static void *
-_calloc_r (void *ignore, size_t x1, size_t x2)
+mprec_calloc (void *ignore, size_t x1, size_t x2)
{
char *result = (char *) malloc (x1 * x2);
memset (result, 0, x1 * x2);
@@ -119,7 +119,7 @@ _DEFUN (Balloc, (ptr, k), struct _reent *ptr _AND int k)
if (_REENT_MP_FREELIST(ptr) == NULL)
{
/* Allocate a list of pointers to the mprec objects */
- _REENT_MP_FREELIST(ptr) = (struct _Bigint **) _calloc_r (ptr,
+ _REENT_MP_FREELIST(ptr) = (struct _Bigint **) mprec_calloc (ptr,
sizeof (struct _Bigint *),
new_k);
if (_REENT_MP_FREELIST(ptr) == NULL)
@@ -150,7 +150,7 @@ _DEFUN (Balloc, (ptr, k), struct _reent *ptr _AND int k)
{
x = 1 << k;
/* Allocate an mprec Bigint and stick in in the freelist */
- rv = (_Bigint *) _calloc_r (ptr,
+ rv = (_Bigint *) mprec_calloc (ptr,
1,
sizeof (_Bigint) +
(x-1) * sizeof(rv->_x));
@@ -666,7 +666,7 @@ double
_DEFUN (ulp, (_x), double _x)
{
union double_union x, a;
- register __Long L;
+ register int32_t L;
x.d = _x;
diff --git a/native/fdlibm/mprec.h b/native/fdlibm/mprec.h
index 7c7471bc8..0efa2d989 100644
--- a/native/fdlibm/mprec.h
+++ b/native/fdlibm/mprec.h
@@ -100,7 +100,7 @@ union double_union
* An alternative that might be better on some machines is
* #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
*/
-#if defined(IEEE_8087) + defined(VAX)
+#if defined(__IEEE_BYTES_LITTLE_ENDIAN) + defined(IEEE_8087) + defined(VAX)
#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
((unsigned short *)a)[0] = (unsigned short)c, a++)
#else
diff --git a/native/jni/classpath/jcl.c b/native/jni/classpath/jcl.c
index e28c6631b..607b54d57 100644
--- a/native/jni/classpath/jcl.c
+++ b/native/jni/classpath/jcl.c
@@ -1,5 +1,5 @@
/* jcl.c
- Copyright (C) 1998, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -48,6 +48,57 @@ exception statement from your version. */
#endif
#endif
+/*
+ * Cached Pointer class info.
+ */
+static jclass rawDataClass = NULL;
+static jfieldID rawData_fid = NULL;
+static jmethodID rawData_mid = NULL;
+
+/*
+ * JNI OnLoad constructor.
+ */
+jint
+JNI_OnLoad (JavaVM *vm, void *reserved __attribute__((unused)))
+{
+ JNIEnv *env;
+ void *envp;
+
+ if ((*vm)->GetEnv (vm, &envp, JNI_VERSION_1_4) != JNI_OK)
+ {
+ return JNI_VERSION_1_4;
+ }
+ env = (JNIEnv *) envp;
+#if SIZEOF_VOID_P == 8
+ rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer64");
+ if (rawDataClass != NULL)
+ rawDataClass = (*env)->NewGlobalRef (env, rawDataClass);
+
+ if (rawDataClass != NULL)
+ {
+ rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "J");
+ rawData_mid = (*env)->GetMethodID (env, rawDataClass, "<init>", "(J)V");
+ }
+#else
+#if SIZEOF_VOID_P == 4
+ rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer32");
+ if (rawDataClass != NULL)
+ rawDataClass = (*env)->NewGlobalRef (env, rawDataClass);
+
+ if (rawDataClass != NULL)
+ {
+ rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "I");
+ rawData_mid = (*env)->GetMethodID (env, rawDataClass, "<init>", "(I)V");
+ }
+#else
+#error "Pointer size is not supported."
+#endif /* SIZEOF_VOID_P == 4 */
+#endif /* SIZEOF_VOID_P == 8 */
+
+ return JNI_VERSION_1_4;
+}
+
+
JNIEXPORT void JNICALL
JCL_ThrowException (JNIEnv * env, const char *className, const char *errMsg)
{
@@ -183,78 +234,17 @@ JCL_FindClass (JNIEnv * env, const char *className)
/*
- * Build a Pointer object. The function caches the class type
+ * Build a Pointer object.
*/
-static jclass rawDataClass;
-static jfieldID rawData_fid;
-static jmethodID rawData_mid;
-
JNIEXPORT jobject JNICALL
JCL_NewRawDataObject (JNIEnv * env, void *data)
{
- if (rawDataClass == NULL)
+ if (rawDataClass == NULL || rawData_mid == NULL)
{
- jclass tmp;
-#if SIZEOF_VOID_P == 8
- rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer64");
- if (rawDataClass == NULL)
- {
- JCL_ThrowException (env, "java/lang/InternalError",
- "unable to find internal class");
- return NULL;
- }
-
- rawData_mid = (*env)->GetMethodID (env, rawDataClass, "<init>", "(J)V");
- if (rawData_mid == NULL)
- {
- JCL_ThrowException (env, "java/lang/InternalError",
- "unable to find internal constructor");
- return NULL;
- }
-
- rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "J");
- if (rawData_fid == NULL)
- {
- JCL_ThrowException (env, "java/lang/InternalError",
- "unable to find internal field");
- return NULL;
- }
-#else
- rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer32");
- if (rawDataClass == NULL)
- {
- JCL_ThrowException (env, "java/lang/InternalError",
- "unable to find internal class");
- return NULL;
- }
-
- rawData_mid = (*env)->GetMethodID (env, rawDataClass, "<init>", "(I)V");
- if (rawData_mid == NULL)
- {
- JCL_ThrowException (env, "java/lang/InternalError",
- "unable to find internal constructor");
- return NULL;
- }
-
- rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "I");
- if (rawData_fid == NULL)
- {
- JCL_ThrowException (env, "java/lang/InternalError",
- "unable to find internal field");
- return NULL;
- }
-
-#endif
- tmp = (*env)->NewGlobalRef (env, rawDataClass);
- if (tmp == NULL)
- {
- JCL_ThrowException (env, "java/lang/InternalError",
- "unable to create an internal global ref");
- return NULL;
- }
- (*env)->DeleteLocalRef(env, rawDataClass);
- rawDataClass = tmp;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "Pointer class was not properly initialized");
+ return NULL;
}
#if SIZEOF_VOID_P == 8
@@ -267,6 +257,13 @@ JCL_NewRawDataObject (JNIEnv * env, void *data)
JNIEXPORT void * JNICALL
JCL_GetRawData (JNIEnv * env, jobject rawdata)
{
+ if (rawData_fid == NULL)
+ {
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "Pointer class was not properly initialized");
+ return NULL;
+ }
+
#if SIZEOF_VOID_P == 8
return (void *) (*env)->GetLongField (env, rawdata, rawData_fid);
#else
diff --git a/native/jni/gconf-peer/GConfNativePeer.c b/native/jni/gconf-peer/GConfNativePeer.c
index a442226ca..42986c33a 100644
--- a/native/jni/gconf-peer/GConfNativePeer.c
+++ b/native/jni/gconf-peer/GConfNativePeer.c
@@ -108,8 +108,8 @@ static jclass get_jlist_reference (JNIEnv * env, jclass jlist_class);
* Method: init_class
* Signature: ()V
*/
-JNIEXPORT void
-JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1class
+JNIEXPORT void JNICALL
+Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1class
(JNIEnv *env, jclass clazz)
{
if (reference_count == 0)
@@ -127,8 +127,8 @@ JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1class
* Method: init_id_chache
* Signature: ()V
*/
-JNIEXPORT void
-JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1id_1cache
+JNIEXPORT void JNICALL
+Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1id_1cache
(JNIEnv *env, jclass clazz __attribute__ ((unused)))
{
reference_count++;
@@ -157,16 +157,19 @@ JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1id_1cache
/*
* Class: gnu_java_util_prefs_gconf_GConfNativePeer
- * Method: gconf_client_gconf_client_all_keys
+ * Method: gconf_client_all_keys
* Signature: (Ljava/lang/String;)Ljava/util/List;
*/
JNIEXPORT jobject JNICALL
-Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1gconf_1client_1all_1keys
+Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1all_1keys
(JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
{
/* TODO: check all the calls to gdk_threads_enter/leave */
const char *dir = NULL;
+ const char *_val = NULL;
+ const char *_val_unescaped = NULL;
+
GError *err = NULL;
GSList *entries = NULL;
GSList *tmp;
@@ -208,12 +211,18 @@ Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1gconf_1client_1all
tmp = entries;
while (tmp != NULL)
{
- const char *_val = gconf_entry_get_key (tmp->data);
+ _val = gconf_entry_get_key (tmp->data);
_val = strrchr (_val, '/');
++_val;
+
+ _val_unescaped = gconf_unescape_key (_val, strlen (_val));
+
(*env)->CallBooleanMethod (env, jlist, jlist_add_id,
- (*env)->NewStringUTF (env, _val));
+ (*env)->NewStringUTF (env, _val_unescaped));
+
tmp = g_slist_next (tmp);
+
+ g_free ((gpointer) _val_unescaped);
}
/* clean up things */
@@ -226,14 +235,17 @@ Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1gconf_1client_1all
/*
* Class: gnu_java_util_prefs_gconf_GConfNativePeer
- * Method: gconf_client_gconf_client_all_nodes
+ * Method: gconf_client_all_nodes
* Signature: (Ljava/lang/String;)Ljava/util/List;
*/
JNIEXPORT jobject JNICALL
-Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1gconf_1client_1all_1nodes
+Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1all_1nodes
(JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
{
const char *dir = NULL;
+ const char *_val = NULL;
+ const char *_val_unescaped = NULL;
+
GError *err = NULL;
GSList *entries = NULL;
GSList *tmp;
@@ -274,12 +286,19 @@ Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1gconf_1client_1all
tmp = entries;
while (tmp != NULL)
{
- const char *_val = tmp->data;
+ _val = tmp->data;
+
_val = strrchr (_val, '/');
++_val;
+
+ _val_unescaped = gconf_unescape_key (_val, strlen (_val));
+
(*env)->CallBooleanMethod (env, jlist, jlist_add_id,
- (*env)->NewStringUTF (env, _val));
+ (*env)->NewStringUTF (env, _val_unescaped));
+
tmp = g_slist_next (tmp);
+
+ g_free ((gpointer) _val_unescaped);
}
/* clean up things */
@@ -421,7 +440,7 @@ Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1set_1string
gdk_threads_leave ();
if (err != NULL)
{
- g_error_free (err);
+ g_error_free (err);
err = NULL;
result = JNI_FALSE;
}
@@ -511,8 +530,8 @@ Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1dir_1exists
* Method: finalize_class
* Signature: ()V
*/
-JNIEXPORT void
-JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_finalize_1class
+JNIEXPORT void JNICALL
+Java_gnu_java_util_prefs_gconf_GConfNativePeer_finalize_1class
(JNIEnv *env, jclass clazz __attribute__ ((unused)))
{
if (reference_count == 0)
@@ -534,6 +553,74 @@ JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_finalize_1class
reference_count--;
}
+/*
+ * Class: gnu_java_util_prefs_gconf_GConfNativePeer
+ * Method: Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1escape_1key
+ * Signature: (Ljava/lang/String;)Z
+ */
+JNIEXPORT jstring JNICALL
+Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1escape_1key
+ (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring plain)
+{
+ const char *escaped = NULL;
+ const char *_plain = NULL;
+ jstring result = NULL;
+
+ _plain = JCL_jstring_to_cstring (env, plain);
+ if (_plain == NULL)
+ {
+ return NULL;
+ }
+
+ gdk_threads_enter ();
+ escaped = gconf_escape_key (_plain, strlen (_plain));
+ gdk_threads_leave ();
+
+ JCL_free_cstring (env, plain, _plain);
+ /* check for NULL, if so prevent string creation */
+ if (escaped != NULL)
+ {
+ result = (*env)->NewStringUTF (env, escaped);
+ g_free ((gpointer) escaped);
+ }
+
+ return result;
+}
+
+/*
+ * Class: gnu_java_util_prefs_gconf_GConfNativePeer
+ * Method: Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unescape_1key
+ * Signature: (Ljava/lang/String;)Z
+ */
+JNIEXPORT jstring JNICALL
+Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unescape_1key
+ (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring escaped)
+{
+ const char *plain = NULL;
+ const char *_escaped = NULL;
+ jstring result = NULL;
+
+ _escaped = JCL_jstring_to_cstring (env, escaped);
+ if (_escaped == NULL)
+ {
+ return NULL;
+ }
+
+ gdk_threads_enter ();
+ plain = gconf_unescape_key (_escaped, strlen (_escaped));
+ gdk_threads_leave ();
+
+ JCL_free_cstring (env, escaped, _escaped);
+ /* check for NULL, if so prevent string creation */
+ if (plain != NULL)
+ {
+ result = (*env)->NewStringUTF (env, plain);
+ g_free ((gpointer) plain);
+ }
+
+ return result;
+}
+
/* ***** END: NATIVE FUNCTIONS ***** */
/* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
diff --git a/native/jni/gconf-peer/Makefile.am b/native/jni/gconf-peer/Makefile.am
index d88218326..1c8c4a147 100644
--- a/native/jni/gconf-peer/Makefile.am
+++ b/native/jni/gconf-peer/Makefile.am
@@ -5,6 +5,8 @@ libgconfpeer_la_SOURCES = GConfNativePeer.c
libgconfpeer_la_LIBADD = $(top_builddir)/native/jni/classpath/native_state.lo \
$(top_builddir)/native/jni/classpath/jcl.lo
+libgconfpeer_la_LDFLAGS = -avoid-version
+
AM_LDFLAGS = @CLASSPATH_MODULE@ @GCONF_LIBS@ @GDK_LIBS@
AM_CPPFLAGS = @CLASSPATH_INCLUDES@
diff --git a/native/jni/gtk-peer/cairographics2d.h b/native/jni/gtk-peer/cairographics2d.h
index 675bc0b17..fc564a86a 100644
--- a/native/jni/gtk-peer/cairographics2d.h
+++ b/native/jni/gtk-peer/cairographics2d.h
@@ -97,7 +97,8 @@ enum java_awt_rendering_hints_filter
java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR = 1,
java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED = 2,
java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY = 3,
- java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT = 4
+ java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT = 4,
+ java_awt_rendering_hints_VALUE_INTERPOLATION_BICUBIC = 5
};
diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c
index 45cf4fbda..0a35a3f18 100644
--- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c
+++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c
@@ -134,7 +134,11 @@ Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setGradient
cairo_pattern_add_color_stop_rgba(pattern, 1.0, r2 / 255.0, g2 / 255.0,
b2 / 255.0, a2 / 255.0);
- extend = (cyclic == JNI_TRUE) ? CAIRO_EXTEND_REFLECT : CAIRO_EXTEND_NONE;
+ #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 2, 0)
+ extend = (cyclic == JNI_TRUE) ? CAIRO_EXTEND_REFLECT : CAIRO_EXTEND_PAD;
+ #else
+ extend = (cyclic == JNI_TRUE) ? CAIRO_EXTEND_REFLECT : CAIRO_EXTEND_NONE;
+ #endif
cairo_pattern_set_extend( pattern, extend );
@@ -143,9 +147,9 @@ Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setGradient
}
JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setTexturePixels
+Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setPaintPixels
(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
- jlong pointer, jintArray jarr, jint w, jint h, jint stride)
+ jlong pointer, jintArray jarr, jint w, jint h, jint stride, jboolean repeat)
{
struct cairographics2d *gr = NULL;
jint *jpixels = NULL;
@@ -180,7 +184,12 @@ Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setTexturePixels
g_assert (gr->pattern_surface != NULL);
gr->pattern = cairo_pattern_create_for_surface (gr->pattern_surface);
g_assert (gr->pattern != NULL);
- cairo_pattern_set_extend (gr->pattern, CAIRO_EXTEND_REPEAT);
+
+ if (repeat)
+ cairo_pattern_set_extend (gr->pattern, CAIRO_EXTEND_REPEAT);
+ else
+ cairo_pattern_set_extend (gr->pattern, CAIRO_EXTEND_NONE);
+
cairo_set_source (gr->cr, gr->pattern);
}
@@ -188,7 +197,8 @@ JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoGraphics2D_drawPixels
(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
jlong pointer, jintArray java_pixels,
- jint w, jint h, jint stride, jdoubleArray java_matrix, jdouble alpha)
+ jint w, jint h, jint stride, jdoubleArray java_matrix, jdouble alpha,
+ jint interpolation)
{
jint *native_pixels = NULL;
jdouble *native_matrix = NULL;
@@ -215,8 +225,28 @@ Java_gnu_java_awt_peer_gtk_CairoGraphics2D_drawPixels
p = cairo_pattern_create_for_surface (surf);
cairo_pattern_set_matrix (p, &mat);
- if (gr->pattern)
- cairo_pattern_set_filter (p, cairo_pattern_get_filter (gr->pattern));
+ switch ((enum java_awt_rendering_hints_filter) interpolation)
+ {
+ case java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_NEAREST);
+ break;
+ case java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_BILINEAR);
+ break;
+ case java_awt_rendering_hints_VALUE_INTERPOLATION_BICUBIC:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_GAUSSIAN);
+ break;
+ case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_FAST);
+ break;
+ case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_NEAREST);
+ break;
+ case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_BEST);
+ break;
+ }
+
cairo_set_source (gr->cr, p);
if (alpha == 1.)
cairo_paint (gr->cr);
@@ -679,37 +709,6 @@ Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoPreserveClip
}
JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSurfaceSetFilter
-(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
- jlong pointer, jint filter)
-{
- struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer);
- g_assert (gr != NULL);
-
- if (gr->pattern == NULL)
- return;
-
- switch ((enum java_awt_rendering_hints_filter) filter)
- {
- case java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR:
- cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_NEAREST);
- break;
- case java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR:
- cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_BILINEAR);
- break;
- case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED:
- cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_FAST);
- break;
- case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT:
- cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_NEAREST);
- break;
- case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY:
- cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_BEST);
- break;
- }
-}
-
-JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoDrawLine
(JNIEnv *env __attribute__ ((unused)), jobject obj __attribute__ ((unused)),
jlong pointer, jdouble x1, jdouble y1, jdouble x2, jdouble y2)
diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoSurface.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoSurface.c
index a25f764b4..350cd345a 100644
--- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoSurface.c
+++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoSurface.c
@@ -181,7 +181,8 @@ Java_gnu_java_awt_peer_gtk_CairoSurface_nativeSetPixels
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_nativeDrawSurface
(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
- jlong surfacePointer, jlong context, jdoubleArray java_matrix, double alpha)
+ jlong surfacePointer, jlong context, jdoubleArray java_matrix, double alpha,
+ jint interpolation)
{
struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, context);
cairo_t *cr = gr->cr;
@@ -205,6 +206,27 @@ Java_gnu_java_awt_peer_gtk_CairoSurface_nativeDrawSurface
p = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_matrix (p, &mat);
+ switch ((enum java_awt_rendering_hints_filter) interpolation)
+ {
+ case java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_NEAREST);
+ break;
+ case java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_BILINEAR);
+ break;
+ case java_awt_rendering_hints_VALUE_INTERPOLATION_BICUBIC:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_GAUSSIAN);
+ break;
+ case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_FAST);
+ break;
+ case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_NEAREST);
+ break;
+ case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY:
+ cairo_pattern_set_filter (p, CAIRO_FILTER_BEST);
+ break;
+ }
cairo_set_source(cr, p);
if (alpha == 1.0)
diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkVolatileImage.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkVolatileImage.c
index e391d64ec..3fb5331a2 100644
--- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkVolatileImage.c
+++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkVolatileImage.c
@@ -88,7 +88,7 @@ Java_gnu_java_awt_peer_gtk_GtkVolatileImage_init (JNIEnv *env,
*/
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkVolatileImage_destroy
-(JNIEnv *env __attribute__((unused)), jobject obj __attribute((unused)),
+(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
jlong pointer)
{
GdkPixmap* pixmap = JLONG_TO_PTR(GdkPixmap, pointer);
@@ -110,10 +110,12 @@ Java_gnu_java_awt_peer_gtk_GtkVolatileImage_nativeGetPixels
/* jint *pixeldata, *jpixdata; */
jint *jpixdata;
GdkPixmap *pixmap;
+ GdkPixbuf *pixbuf;
jintArray jpixels;
int width, height, depth, size;
jclass cls;
jfieldID field;
+ guchar *pixels;
cls = (*env)->GetObjectClass (env, obj);
field = (*env)->GetFieldID (env, cls, "width", "I");
@@ -131,11 +133,19 @@ Java_gnu_java_awt_peer_gtk_GtkVolatileImage_nativeGetPixels
/* get depth in bytes */
depth = gdk_drawable_get_depth( pixmap ) >> 3;
- size = width * height * 4;
+ size = width * height;
jpixels = (*env)->NewIntArray ( env, size );
jpixdata = (*env)->GetIntArrayElements (env, jpixels, NULL);
- /* memcpy (jpixdata, pixeldata, size * sizeof( jint )); */
-
+
+ pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, TRUE, 8, width, height );
+ gdk_pixbuf_get_from_drawable( pixbuf, pixmap, NULL, 0, 0, 0, 0, width, height );
+
+ if (pixbuf != NULL)
+ {
+ pixels = gdk_pixbuf_get_pixels(pixbuf);
+ memcpy (jpixdata, pixels, size * sizeof(jint));
+ }
+
(*env)->ReleaseIntArrayElements (env, jpixels, jpixdata, 0);
gdk_threads_leave();
@@ -148,7 +158,7 @@ Java_gnu_java_awt_peer_gtk_GtkVolatileImage_nativeGetPixels
*/
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkVolatileImage_nativeCopyArea
-(JNIEnv *env __attribute__((unused)), jobject obj __attribute((unused)),
+(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
jlong pointer, jint x, jint y, jint w, jint h, jint dx, jint dy)
{
GdkPixbuf *pixbuf;
@@ -169,7 +179,7 @@ Java_gnu_java_awt_peer_gtk_GtkVolatileImage_nativeCopyArea
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkVolatileImage_nativeDrawVolatile
-(JNIEnv *env __attribute__((unused)), jobject obj __attribute((unused)),
+(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
jlong pointer, jlong srcptr, jint x, jint y, jint w, jint h)
{
GdkPixmap *dst, *src;
diff --git a/native/jni/java-io/java_io_VMFile.c b/native/jni/java-io/java_io_VMFile.c
index 3f9282049..de1320b0c 100644
--- a/native/jni/java-io/java_io_VMFile.c
+++ b/native/jni/java-io/java_io_VMFile.c
@@ -593,7 +593,7 @@ Java_java_io_VMFile_list (JNIEnv * env, jobject obj
int result;
char **filelist;
void *handle;
- const char *filename;
+ char *filename = (char *) JCL_malloc (env, FILENAME_MAX);
unsigned long int filelist_count, max_filelist_count;
char **tmp_filelist;
jclass str_clazz;
@@ -630,7 +630,7 @@ Java_java_io_VMFile_list (JNIEnv * env, jobject obj
max_filelist_count = REALLOC_SIZE;
/* read the files from the directory */
- result = cpio_readDir (handle, &filename);
+ result = cpio_readDir (handle, filename);
while (result == CPNATIVE_OK)
{
if ((strcmp (filename, ".") != 0) && (strcmp (filename, "..") != 0))
@@ -666,9 +666,11 @@ Java_java_io_VMFile_list (JNIEnv * env, jobject obj
}
/* read next directory entry */
- result = cpio_readDir (handle, &filename);
+ result = cpio_readDir (handle, filename);
}
+ JCL_free (env, filename);
+
/* close directory */
result = cpio_closeDir (handle);
@@ -693,6 +695,9 @@ Java_java_io_VMFile_list (JNIEnv * env, jobject obj
JCL_free (env, filelist);
return 0;
}
+
+ (*env)->DeleteLocalRef (env, str_clazz);
+
for (i = 0; i < filelist_count; i++)
{
/* create new string */
diff --git a/native/jni/java-lang/java_lang_VMDouble.c b/native/jni/java-lang/java_lang_VMDouble.c
index 8435c3fdb..f8c072192 100644
--- a/native/jni/java-lang/java_lang_VMDouble.c
+++ b/native/jni/java-lang/java_lang_VMDouble.c
@@ -121,17 +121,8 @@ Java_java_lang_VMDouble_doubleToLongBits
{
jvalue val;
jlong e, f;
- val.d = doubleValue;
-
-#if defined(__IEEE_BYTES_LITTLE_ENDIAN)
- /* On little endian ARM processors when using FPA, word order of
- doubles is still big endian. So take that into account here. When
- using VFP, word order of doubles follows byte order. */
-
-#define SWAP_DOUBLE(a) (((a) << 32) | (((a) >> 32) & 0x00000000ffffffff))
- val.j = SWAP_DOUBLE(val.j);
-#endif
+ val.d = doubleValue;
e = val.j & 0x7ff0000000000000LL;
f = val.j & 0x000fffffffffffffLL;
@@ -153,11 +144,8 @@ Java_java_lang_VMDouble_doubleToRawLongBits
jclass cls __attribute__ ((__unused__)), jdouble doubleValue)
{
jvalue val;
- val.d = doubleValue;
-#if defined(__IEEE_BYTES_LITTLE_ENDIAN)
- val.j = SWAP_DOUBLE(val.j);
-#endif
+ val.d = doubleValue;
return val.j;
}
@@ -173,11 +161,8 @@ Java_java_lang_VMDouble_longBitsToDouble
jclass cls __attribute__ ((__unused__)), jlong longValue)
{
jvalue val;
- val.j = longValue;
-#if defined(__IEEE_BYTES_LITTLE_ENDIAN)
- val.j = SWAP_DOUBLE(val.j);
-#endif
+ val.j = longValue;
return val.d;
}
diff --git a/native/jni/java-lang/java_lang_VMProcess.c b/native/jni/java-lang/java_lang_VMProcess.c
index e9d85fa65..a6076f2ae 100644
--- a/native/jni/java-lang/java_lang_VMProcess.c
+++ b/native/jni/java-lang/java_lang_VMProcess.c
@@ -38,7 +38,7 @@ exception statement from your version. */
#include <config.h>
#include "java_lang_VMProcess.h"
-#include "gnu_java_nio_channels_FileChannelImpl.h"
+#include "gnu_java_nio_FileChannelImpl.h"
#include <sys/types.h>
#include <sys/wait.h>
@@ -137,8 +137,8 @@ Java_java_lang_VMProcess_nativeSpawn (JNIEnv * env, jobject this,
char *dir = NULL;
pid_t pid = -1;
char errbuf[64];
- jmethodID method;
- jclass clazz;
+ jmethodID method, vmmethod;
+ jclass clazz, vmclazz;
int i;
int pipe_count = redirect ? 2 : 3;
int err;
@@ -214,10 +214,12 @@ Java_java_lang_VMProcess_nativeSpawn (JNIEnv * env, jobject this,
}
/* Create Input/OutputStream objects around parent file descriptors */
- clazz = (*env)->FindClass (env, "gnu/java/nio/channels/FileChannelImpl");
+ vmclazz = (*env)->FindClass (env, "gnu/java/nio/VMChannel");
+ clazz = (*env)->FindClass (env, "gnu/java/nio/FileChannelImpl");
if ((*env)->ExceptionOccurred (env))
goto done;
- method = (*env)->GetMethodID (env, clazz, "<init>", "(II)V");
+ vmmethod = (*env)->GetMethodID (env, vmclazz, "<init>", "(I)V");
+ method = (*env)->GetMethodID (env, clazz, "<init>", "(Lgnu/java/nio/VMChannel;I)V");
if ((*env)->ExceptionOccurred (env))
goto done;
for (i = 0; i < pipe_count; i++)
@@ -228,11 +230,16 @@ Java_java_lang_VMProcess_nativeSpawn (JNIEnv * env, jobject this,
jclass sclazz;
jmethodID smethod;
- jobject channel = (*env)->NewObject (env, clazz, method, fd, mode);
+ jobject vmchannel;
+ jobject channel;
+ vmchannel = (*env)->NewObject (env, vmclazz, vmmethod, fd);
+ if ((*env)->ExceptionOccurred (env))
+ goto done;
+ channel = (*env)->NewObject (env, clazz, method, vmchannel, mode);
if ((*env)->ExceptionOccurred (env))
goto done;
- if (mode == gnu_java_nio_channels_FileChannelImpl_WRITE)
+ if (mode == gnu_java_nio_FileChannelImpl_WRITE)
sclazz = (*env)->FindClass (env, "java/io/FileOutputStream");
else
sclazz = (*env)->FindClass (env, "java/io/FileInputStream");
@@ -240,7 +247,7 @@ Java_java_lang_VMProcess_nativeSpawn (JNIEnv * env, jobject this,
goto done;
smethod = (*env)->GetMethodID (env, sclazz, "<init>",
- "(Lgnu/java/nio/channels/FileChannelImpl;)V");
+ "(Lgnu/java/nio/FileChannelImpl;)V");
if ((*env)->ExceptionOccurred (env))
goto done;
diff --git a/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c b/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c
index fb9855908..6ebb64fa5 100644
--- a/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c
+++ b/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c
@@ -35,265 +35,800 @@ this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-/* do not move; needed here because of some macro definitions */
-#include <config.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <ifaddrs.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include <jni.h>
#include <jcl.h>
-#include <cpnative.h>
-#include <cpnet.h>
-#include "javanet.h"
+/* #include "javanet.h" */
#include "gnu_java_net_VMPlainSocketImpl.h"
-/*
- * Note that the functions in this module simply redirect to another
- * internal function. Why? Because many of these functions are shared
- * with PlainDatagramSocketImpl. The unshared ones were done the same
- * way for consistency.
- */
+#define IO_EXCEPTION "java/io/IOException"
+#define SOCKET_EXCEPTION "java/net/SocketException"
+#define BIND_EXCEPTION "java/net/BindException"
+
+#define THROW_NO_NETWORK(env) JCL_ThrowException (env, "java/lang/InternalError", "this platform not configured for network support")
-/*************************************************************************/
/*
- * Creates a new stream or datagram socket
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: bind
+ * Signature: (I[BI)V
*/
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_create(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj)
+Java_gnu_java_net_VMPlainSocketImpl_bind (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jint fd, jbyteArray addr, jint port)
{
-#ifndef WITHOUT_NETWORK
- _javanet_create(env, obj, JNI_TRUE);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+ struct sockaddr_in sockaddr;
+ jbyte *elems = NULL;
+ int ret;
+
+ if (addr != NULL)
+ elems = (*env)->GetByteArrayElements (env, addr, NULL);
+
+ memset(&sockaddr, 0, sizeof (struct sockaddr_in));
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_port = htons (port);
+ /* addr is already in network byte order. */
+ if (elems != NULL)
+ sockaddr.sin_addr.s_addr = *((uint32_t *) elems);
+ else
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+ /* bind(2) from BSD says bind will never return EINTR */
+ /* bind is not a blocking system call */
+ ret = bind (fd, (struct sockaddr *) &sockaddr, sizeof (struct sockaddr_in));
+
+ if (elems != NULL)
+ (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
+
+ if (-1 == ret)
+ JCL_ThrowException (env, BIND_EXCEPTION, strerror (errno));
}
-/*************************************************************************/
/*
- * Close the socket. Any underlying streams will be closed by this
- * action as well.
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: bind6
+ * Signature: (I[BI)V
*/
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_close(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj)
+Java_gnu_java_net_VMPlainSocketImpl_bind6 (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jbyteArray addr, jint port)
{
-#ifndef WITHOUT_NETWORK
- _javanet_close(env, obj, 1);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+ /* FIXME! Add check if we have IPv6! */
+ struct sockaddr_in6 sockaddr;
+ jbyte *elems;
+ int ret;
+
+ elems = (*env)->GetByteArrayElements (env, addr, NULL);
+
+ memset (&sockaddr, 0, sizeof (struct sockaddr_in6));
+ sockaddr.sin6_family = AF_INET6;
+ sockaddr.sin6_port = htons (port);
+ memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16);
+
+ /* bind(2) from BSD says bind will never return EINTR */
+ /* bind is not a blocking system call */
+ ret = bind (fd, (struct sockaddr *) &sockaddr,
+ sizeof (struct sockaddr_in6));
+
+ (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
+
+ if (-1 == ret)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
}
-/*************************************************************************/
/*
- * Connects to the specified destination.
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: listen
+ * Signature: (II)V
*/
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_connect(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj,
- jobject addr, jint port)
+Java_gnu_java_net_VMPlainSocketImpl_listen (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jint backlog)
{
-#ifndef WITHOUT_NETWORK
- _javanet_connect(env, obj, addr, port, 1);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+ int ret;
+
+ /* listen(2) says that this call will never return EINTR */
+ /* listen is not a blocking system call */
+ if ((ret = listen (fd, backlog)) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
}
-/*************************************************************************/
+
+/* These constants are also defined in java/net/SocketOptions.java */
+enum java_sockopt {
+ CPNET_SO_KEEPALIVE = 0x8,
+ CPNET_SO_LINGER = 0x80,
+ CPNET_SO_TIMEOUT = 0x1006,
+ CPNET_SO_BINDADDR = 0x0F,
+ CPNET_SO_SNDBUF = 0x1001,
+ CPNET_SO_RCVBUF = 0x1002,
+ CPNET_SO_REUSEADDR = 0x04,
+ CPNET_SO_BROADCAST = 0x20,
+ CPNET_SO_OOBINLINE = 0x1003,
+ CPNET_TCP_NODELAY = 0x01,
+ CPNET_IP_MULTICAST_IF = 0x10,
+ CPNET_IP_MULTICAST_IF2 = 0x1F,
+ CPNET_IP_MULTICAST_LOOP = 0x12,
+ CPNET_IP_TOS = 0x03
+};
+
/*
- * This method binds the specified address to the specified local port.
- * Note that we have to set the local address and local port public instance
- * variables.
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: setOption
+ * Signature: (III)V
*/
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_bind(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj, jobject addr,
- jint port)
+Java_gnu_java_net_VMPlainSocketImpl_setOption (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jint option, jint value)
{
-#ifndef WITHOUT_NETWORK
- _javanet_bind(env, obj, addr, port, 1);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+ enum java_sockopt joption = (enum java_sockopt) option;
+ int optname = -1;
+ int level = SOL_SOCKET;
+ const int _value = value;
+ struct linger _linger;
+ struct timeval _timeo;
+ void *optval = (void *) &_value;
+ socklen_t optlen = sizeof (int);
+
+ switch (joption)
+ {
+ case CPNET_IP_MULTICAST_LOOP:
+ level = IPPROTO_IP;
+ optname = IP_MULTICAST_LOOP;
+ break;
+
+ case CPNET_SO_KEEPALIVE:
+ optname = SO_KEEPALIVE;
+ break;
+
+ case CPNET_SO_LINGER:
+ optname = SO_LINGER;
+ if (_value == 0)
+ _linger.l_onoff = 0;
+ else
+ _linger.l_onoff = 1;
+ _linger.l_linger = _value;
+ optval = &_linger;
+ optlen = sizeof (struct linger);
+ break;
+
+ case CPNET_SO_TIMEOUT:
+ optname = SO_RCVTIMEO;
+ _timeo.tv_sec = value / 1000;
+ _timeo.tv_usec = (value % 1000) * 1000;
+ optval = &_timeo;
+ optlen = sizeof (struct timeval);
+ break;
+
+ case CPNET_SO_SNDBUF:
+ optname = SO_SNDBUF;
+ break;
+
+ case CPNET_SO_RCVBUF:
+ optname = SO_RCVBUF;
+ break;
+
+ case CPNET_SO_REUSEADDR:
+ optname = SO_REUSEADDR;
+ break;
+
+ case CPNET_SO_BROADCAST:
+ optname = SO_BROADCAST;
+ break;
+
+ case CPNET_SO_OOBINLINE:
+ optname = SO_OOBINLINE;
+ break;
+
+ case CPNET_TCP_NODELAY:
+ level = IPPROTO_TCP;
+ optname = TCP_NODELAY;
+ break;
+
+ case CPNET_IP_TOS:
+ level = IPPROTO_IP;
+ optname = IP_TOS;
+ break;
+
+ case CPNET_SO_BINDADDR:
+ case CPNET_IP_MULTICAST_IF:
+ case CPNET_IP_MULTICAST_IF2:
+ JCL_ThrowException (env, IO_EXCEPTION, "argument not a boolean or integer option");
+ return;
+ }
+
+ if (setsockopt (fd, level, optname, (const void *) optval, optlen) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+}
+
+/*
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: getOption
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_getOption (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jint option)
+{
+ enum java_sockopt joption = (enum java_sockopt) option;
+ int optname = -1;
+ int level = SOL_SOCKET;
+ int value;
+ struct linger linger;
+ struct timeval timeo;
+ void *optval = &value;
+ socklen_t optlen = sizeof (int);
+
+ switch (joption)
+ {
+ case CPNET_IP_MULTICAST_LOOP:
+ level = IPPROTO_IP;
+ optname = IP_MULTICAST_LOOP;
+ break;
+
+ case CPNET_SO_KEEPALIVE:
+ optname = SO_KEEPALIVE;
+ break;
+
+ case CPNET_SO_LINGER:
+ optname = SO_LINGER;
+ optval = &linger;
+ optlen = sizeof (struct linger);
+ break;
+
+ case CPNET_SO_TIMEOUT:
+ optname = SO_RCVTIMEO;
+ optval = &timeo;
+ optlen = sizeof (struct timeval);
+ break;
+
+ case CPNET_SO_SNDBUF:
+ optname = SO_SNDBUF;
+ break;
+
+ case CPNET_SO_RCVBUF:
+ optname = SO_RCVBUF;
+ break;
+
+ case CPNET_SO_REUSEADDR:
+ optname = SO_REUSEADDR;
+ break;
+
+ case CPNET_SO_BROADCAST:
+ optname = SO_BROADCAST;
+ break;
+
+ case CPNET_SO_OOBINLINE:
+ optname = SO_OOBINLINE;
+ break;
+
+ case CPNET_TCP_NODELAY:
+ level = IPPROTO_TCP;
+ optname = TCP_NODELAY;
+ break;
+
+ case CPNET_IP_TOS:
+ level = IPPROTO_IP;
+ optname = IP_TOS;
+ break;
+
+ case CPNET_SO_BINDADDR:
+ case CPNET_IP_MULTICAST_IF:
+ case CPNET_IP_MULTICAST_IF2:
+ JCL_ThrowException (env, IO_EXCEPTION, "argument not a boolean or integer option");
+ return -1;
+ }
+
+ if (getsockopt (fd, level, optname, optval, &optlen) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+
+ if (joption == CPNET_SO_LINGER)
+ return linger.l_linger;
+ if (joption == CPNET_SO_TIMEOUT)
+ return (timeo.tv_sec * 1000) + (timeo.tv_usec / 1000);
+
+ return value;
}
-/*************************************************************************/
/*
- * Starts listening on a socket with the specified number of pending
- * connections allowed.
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: shutdownInput
+ * Signature: (I)V
*/
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_listen(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj, jint queuelen)
+Java_gnu_java_net_VMPlainSocketImpl_shutdownInput (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd)
{
-#ifndef WITHOUT_NETWORK
- _javanet_listen(env, obj, queuelen);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+ if (shutdown (fd, SHUT_RD) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
}
-/*************************************************************************/
-
/*
- * Accepts a new connection and assigns it to the passed in SocketImpl
- * object. Note that we assume this is a PlainSocketImpl just like us.
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: shutdownOutput
+ * Signature: (I)V
*/
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_accept(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj, jobject impl)
+Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd)
{
-#ifndef WITHOUT_NETWORK
- _javanet_accept(env, obj, impl);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+ if (shutdown (fd, SHUT_WR) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
}
-/*************************************************************************/
-JNIEXPORT jint JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_available(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj)
+/*
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: sendUrgentData
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_sendUrgentData (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jint data)
{
-#ifndef WITHOUT_NETWORK
- jclass cls;
- jfieldID fid;
- int fd;
- int bytesAvailable;
- int result;
-
- cls = (*env)->GetObjectClass(env, obj);
- if (cls == 0)
- {
- JCL_ThrowException(env, IO_EXCEPTION, "internal error");
- return 0;
- }
-
- fid = (*env)->GetFieldID(env, cls, "native_fd", "I");
- if (fid == 0)
- {
- JCL_ThrowException(env, IO_EXCEPTION, "internal error");
- return 0;
- }
+ const char x = (char) data;
- fd = (*env)->GetIntField(env, obj, fid);
-
- result = cpnet_getAvailableBytes (env, fd, &bytesAvailable);
- if (result != CPNATIVE_OK)
- {
- JCL_ThrowException(env, IO_EXCEPTION, cpnative_getErrorString (result));
- return 0;
- }
-
- return bytesAvailable;
-#else /* not WITHOUT_NETWORK */
- return 0;
-#endif /* not WITHOUT_NETWORK */
+ if (send (fd, &x, 1, MSG_OOB) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
}
-/*************************************************************************/
/*
- * This method sets the specified option for a socket
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: join
+ * Signature: (I[B)V
*/
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_setOption(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj,
- jint option_id, jobject val)
+Java_gnu_java_net_VMPlainSocketImpl_join (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jint fd, jbyteArray addr)
{
-#ifndef WITHOUT_NETWORK
- _javanet_set_option(env, obj, option_id, val);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+#ifdef HAVE_SETSOCKOPT
+ struct ip_mreq maddr;
+ jbyte *addr_elems;
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+ if (addr_elems == NULL)
+ return;
+
+ maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems);
+ maddr.imr_interface.s_addr = INADDR_ANY;
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ if (-1 == setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &maddr, sizeof (struct ip_mreq)))
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
}
-/*************************************************************************/
/*
- * This method gets the specified option for a socket
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: join6
+ * Signature: (I[B)V
*/
-JNIEXPORT jobject JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_getOption(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj,
- jint option_id)
+JNIEXPORT void JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_join6 (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jint fd, jbyteArray addr)
{
-#ifndef WITHOUT_NETWORK
- return(_javanet_get_option(env, obj, option_id));
-#else /* not WITHOUT_NETWORK */
- return NULL;
-#endif /* not WITHOUT_NETWORK */
+#ifdef HAVE_SETSOCKOPT
+#ifdef HAVE_INET6
+ struct ipv6_mreq maddr;
+ jbyte *addr_elems;
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+ if (addr_elems == NULL)
+ return;
+
+ memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16);
+ maddr.ipv6mr_interface = 0;
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &maddr, sizeof (struct ipv6_mreq)))
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "IPv6 support not available");
+#endif /* HAVE_INET6 */
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
}
-/*************************************************************************/
+/*
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: leave
+ * Signature: (I[B)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_leave (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jbyteArray addr)
+{
+#ifdef HAVE_SETSOCKOPT
+ struct ip_mreq maddr;
+ jbyte *addr_elems;
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+ if (addr_elems == NULL)
+ return;
+
+ maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems);
+ maddr.imr_interface.s_addr = INADDR_ANY;
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ if (-1 == setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ &maddr, sizeof (struct ip_mreq)))
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
+}
/*
- * Reads a buffer from a remote host
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: leave6
+ * Signature: (I[B)V
*/
-JNIEXPORT jint JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_read(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj, jarray buf,
- jint offset, jint len)
+JNIEXPORT void JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_leave6 (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jbyteArray addr)
{
-#ifndef WITHOUT_NETWORK
- return(_javanet_recvfrom(env, obj, buf, offset, len, 0));
-#else /* not WITHOUT_NETWORK */
- return 0;
-#endif /* not WITHOUT_NETWORK */
+#ifdef HAVE_SETSOCKOPT
+#ifdef HAVE_INET6
+ struct ipv6_mreq maddr;
+ jbyte *addr_elems;
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+ if (addr_elems == NULL)
+ return;
+
+ memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16);
+ maddr.ipv6mr_interface = 0;
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &maddr, sizeof (struct ipv6_mreq)))
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "IPv6 support not available");
+#endif /* HAVE_INET6 */
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
}
-/*************************************************************************/
+static uint32_t getif_address (JNIEnv *env, char *ifname);
+static int getif_index (JNIEnv *env, char *ifname);
/*
- * Writes a buffer to the remote host
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: joinGroup
+ * Signature: (I[BILjava/lang/String;)V
*/
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_write(JNIEnv *env,
- jclass klass __attribute__ ((__unused__)),
- jobject obj, jarray buf,
- jint offset, jint len)
+Java_gnu_java_net_VMPlainSocketImpl_joinGroup (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jbyteArray addr,
+ jstring ifname)
{
-#ifndef WITHOUT_NETWORK
- _javanet_sendto(env, obj, buf, offset, len, 0);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+#ifdef HAVE_SETSOCKOPT
+ struct ip_mreq maddr;
+ jbyte *addr_elems;
+
+ if (ifname != NULL)
+ {
+ maddr.imr_interface.s_addr = getif_address (env, ifname);
+ if ((*env)->ExceptionCheck (env))
+ return;
+ }
+ else
+ maddr.imr_interface.s_addr = INADDR_ANY;
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+ if (addr_elems == NULL)
+ return;
+
+ maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems);
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ if (-1 == setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &maddr, sizeof (struct ip_mreq)))
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) addr;
+ (void) ifname;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
}
+/*
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: joinGroup6
+ * Signature: (I[BILjava/lang/String;)V
+ */
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_shutdownInput (JNIEnv * env,
- jclass klass __attribute__ ((__unused__)),
- jobject this)
+Java_gnu_java_net_VMPlainSocketImpl_joinGroup6 (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jbyteArray addr,
+ jstring ifname)
{
-#ifndef WITHOUT_NETWORK
- _javanet_shutdownInput (env, this);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+#ifdef HAVE_SETSOCKOPT
+#ifdef HAVE_INET6
+ struct ipv6_mreq maddr;
+ jbyte *addr_elems;
+
+ if (ifname == NULL)
+ {
+ maddr.ipv6mr_interface = getif_index (env, ifname);
+ if ((*env)->ExceptionCheck (env))
+ return;
+ }
+ else
+ maddr.ipv6mr_interface = 0;
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+ if (addr_elems == NULL)
+ return;
+
+ memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16);
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &maddr, sizeof (struct ipv6_mreq)))
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "IPv6 support not available");
+#endif /* HAVE_INET6 */
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
}
+/*
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: leaveGroup
+ * Signature: (I[BILjava/lang/String;)V
+ */
JNIEXPORT void JNICALL
-Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput (JNIEnv * env,
- jclass klass __attribute__ ((__unused__)),
- jobject this)
+Java_gnu_java_net_VMPlainSocketImpl_leaveGroup (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jbyteArray addr,
+ jstring ifname)
{
-#ifndef WITHOUT_NETWORK
- _javanet_shutdownOutput (env, this);
-#else /* not WITHOUT_NETWORK */
-#endif /* not WITHOUT_NETWORK */
+#ifdef HAVE_SETSOCKOPT
+ struct ip_mreq maddr;
+ jbyte *addr_elems;
+
+ if (ifname != NULL)
+ {
+ maddr.imr_interface.s_addr = getif_address (env, ifname);
+ if ((*env)->ExceptionCheck (env))
+ return;
+ }
+ else
+ maddr.imr_interface.s_addr = INADDR_ANY;
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+ if (addr_elems == NULL)
+ return;
+
+ maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems);
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ if (-1 == setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ &maddr, sizeof (struct ip_mreq)))
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) addr;
+ (void) ifname;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
+}
+
+/*
+ * Class: gnu_java_net_VMPlainSocketImpl
+ * Method: leaveGroup6
+ * Signature: (I[BILjava/lang/String;)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_leaveGroup6 (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jbyteArray addr,
+ jstring ifname)
+{
+#ifdef HAVE_SETSOCKOPT
+#ifdef HAVE_INET6
+ struct ipv6_mreq maddr;
+ jbyte *addr_elems;
+
+ if (ifname == NULL)
+ {
+ maddr.ipv6mr_interface = getif_index (env, ifname);
+ if ((*env)->ExceptionCheck (env))
+ return;
+ }
+ else
+ maddr.ipv6mr_interface = 0;
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+ if (addr_elems == NULL)
+ return;
+
+ memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16);
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+ &maddr, sizeof (struct ipv6_mreq)))
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "IPv6 support not available");
+#endif /* HAVE_INET6 */
+#else
+ (void) fd;
+ (void) addr;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
}
-/* end of file */
+static uint32_t
+getif_address (JNIEnv *env, char *ifname)
+{
+#ifdef HAVE_GETIFADDRS
+ struct ifaddrs *ifaddrs, *i;
+ uint32_t addr = 0;
+ int foundaddr = 0;
+
+ if (getifaddrs (&ifaddrs) == -1)
+ {
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+ return 0;
+ }
+
+ for (i = ifaddrs; i != NULL; i = i->ifa_next)
+ {
+ if (strcmp (ifname, i->ifa_name) == 0)
+ {
+ /* Matched the name; see if there is an IPv4 address. */
+ if (i->ifa_addr->sa_family == AF_INET)
+ {
+ foundaddr = 1;
+ addr = ((struct sockaddr_in *) i->ifa_addr)->sin_addr.s_addr;
+ break;
+ }
+ }
+ }
+
+ if (!foundaddr)
+ JCL_ThrowException (env, SOCKET_EXCEPTION, "interface has no IPv4 address");
+
+ freeifaddrs (ifaddrs);
+
+ return addr;
+#else
+ (void) ifname;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "getifaddrs not available");
+ return 0;
+#endif /* HAVE_GETIFADDRS */
+}
+
+static int
+getif_index (JNIEnv *env, char *ifname)
+{
+#ifdef HAVE_GETIFADDRS
+ struct ifaddrs *ifaddrs, *i;
+ char *lastname = NULL;
+ int index = 1;
+ int foundname = 0;
+
+ if (getifaddrs (&ifaddrs) == -1)
+ {
+ JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
+ return -1;
+ }
+
+ lastname = ifaddrs->ifa_name;
+ for (i = ifaddrs; i != NULL; i = i->ifa_next)
+ {
+ if (strcmp (lastname, ifaddrs->ifa_name) != 0)
+ {
+ lastname = ifaddrs->ifa_name;
+ index++;
+ }
+ if (strcmp (ifname, ifaddrs->ifa_name) == 0)
+ {
+ foundname = 1;
+ break;
+ }
+ }
+
+ if (!foundname)
+ JCL_ThrowException (env, SOCKET_EXCEPTION,
+ "no interface with that name");
+
+ freeifaddrs (ifaddrs);
+
+ return index;
+#else
+ (void) ifname;
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "getifaddrs not available");
+ return -1;
+#endif /* HAVE_GETIFADDRS */
+}
diff --git a/native/jni/java-net/java_net_VMInetAddress.c b/native/jni/java-net/java_net_VMInetAddress.c
index 2ca0545fe..fc921ecef 100644
--- a/native/jni/java-net/java_net_VMInetAddress.c
+++ b/native/jni/java-net/java_net_VMInetAddress.c
@@ -299,4 +299,91 @@ Java_java_net_VMInetAddress_getHostByName (JNIEnv * env,
#endif /* not WITHOUT_NETWORK */
}
+/*************************************************************************/
+
+/*
+ * Return the IP address represented by a literal address.
+ * Will return null if the literal address is not valid.
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_java_net_VMInetAddress_aton (JNIEnv *env,
+ jclass class
+ __attribute__ ((__unused__)),
+ jstring host)
+{
+#ifndef WITHOUT_NETWORK
+ const char *hostname;
+ cpnet_address *address;
+ int result;
+ jbyte *octets;
+ jbyteArray ret_octets;
+
+ hostname = (*env)->GetStringUTFChars (env, host, 0);
+ if (!hostname)
+ {
+ JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Null hostname");
+ return (jbyteArray) NULL;
+ }
+
+ result = cpnet_aton (env, hostname, &address);
+ if (result != CPNATIVE_OK)
+ {
+ JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error");
+ if (address)
+ cpnet_freeAddress (env, address);
+ return (jbyteArray) NULL;
+ }
+ if (!address)
+ return (jbyteArray) NULL;
+
+ if (cpnet_isIPV6Address (address))
+ {
+ ret_octets = (jbyteArray) (*env)->NewByteArray (env, 16);
+
+ if (!ret_octets)
+ {
+ JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error");
+ cpnet_freeAddress (env, address);
+ return (jbyteArray) NULL;
+ }
+
+ octets = (*env)->GetByteArrayElements (env, ret_octets, 0);
+
+ cpnet_IPV6AddressToBytes (address, octets);
+
+ (*env)->ReleaseByteArrayElements (env, ret_octets, octets, 0);
+ }
+ else if (cpnet_isIPV4Address (address))
+ {
+ ret_octets = (jbyteArray) (*env)->NewByteArray (env, 4);
+
+ if (!ret_octets)
+ {
+ JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error");
+ cpnet_freeAddress (env, address);
+ return (jbyteArray) NULL;
+ }
+
+ octets = (*env)->GetByteArrayElements (env, ret_octets, 0);
+
+ cpnet_IPV4AddressToBytes (address, octets);
+
+ (*env)->ReleaseByteArrayElements (env, ret_octets, octets, 0);
+ }
+ else
+ {
+ JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error");
+ cpnet_freeAddress (env, address);
+ return (jbyteArray) NULL;
+ }
+
+ cpnet_freeAddress (env, address);
+
+ return (ret_octets);
+
+#else /* not WITHOUT_NETWORK */
+ return (jbyteArray) NULL;
+#endif /* not WITHOUT_NETWORK */
+}
+
/* end of file */
diff --git a/native/jni/java-net/java_net_VMNetworkInterface.c b/native/jni/java-net/java_net_VMNetworkInterface.c
index f05e9fcc5..203f6acd0 100644
--- a/native/jni/java-net/java_net_VMNetworkInterface.c
+++ b/native/jni/java-net/java_net_VMNetworkInterface.c
@@ -35,9 +35,15 @@ this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-/* do not move; needed here because of some macro definitions */
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif /* HAVE_CONFIG_H */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+#include <netinet/in.h>
+#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -47,19 +53,197 @@ exception statement from your version. */
#include "java_net_VMNetworkInterface.h"
-#include "javanet.h"
+
+static jmethodID java_net_VMNetworkInterface_init;
+static jmethodID java_net_VMNetworkInterface_addAddress;
/*
- * Returns all local network interfaces as vector
+ * Initialize our static method ID's.
+ *
+ * Class: java_net_VMNetworkInterface
+ * Method: initIds
+ * Signature: ()V
*/
-JNIEXPORT jobject JNICALL
-Java_java_net_VMNetworkInterface_getInterfaces (JNIEnv * env,
- jclass class
- __attribute__ ((__unused__)))
+JNIEXPORT void JNICALL
+Java_java_net_VMNetworkInterface_initIds (JNIEnv *env, jclass clazz)
+{
+ java_net_VMNetworkInterface_init =
+ (*env)->GetMethodID (env, clazz, "<init>", "(Ljava/lang/String;)V");
+ if (java_net_VMNetworkInterface_init == NULL)
+ {
+ if (!(*env)->ExceptionCheck (env))
+ JCL_ThrowException (env, "java/lang/NoSuchMethodError",
+ "VMNetworkinterface.addAddress");
+ return;
+ }
+ java_net_VMNetworkInterface_addAddress =
+ (*env)->GetMethodID (env, clazz, "addAddress", "(Ljava/nio/ByteBuffer;)V");
+ if (java_net_VMNetworkInterface_addAddress == NULL)
+ {
+ if (!(*env)->ExceptionCheck (env))
+ JCL_ThrowException (env, "java/lang/NoSuchMethodError",
+ "VMNetworkinterface.addAddress");
+ }
+}
+
+struct netif_entry
+{
+ char *name;
+ jobject netif;
+ int numaddrs;
+ struct netif_entry *next;
+};
+
+static void
+free_netif_list (JNIEnv *env, struct netif_entry *list)
{
- JCL_ThrowException (env, IO_EXCEPTION,
- "java.net.VMNetworkInterface.getInterfaces(): not implemented");
- return 0;
+ while (list != NULL)
+ {
+ struct netif_entry *e = list->next;
+ JCL_free (env, list);
+ list = e;
+ }
+}
+
+/*
+ * Returns all local network interfaces as an array.
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_java_net_VMNetworkInterface_getVMInterfaces (JNIEnv * env, jclass clazz)
+{
+#ifdef HAVE_GETIFADDRS
+ struct ifaddrs *ifaddrs, *i;
+ struct netif_entry *iflist = NULL, *e;
+ jobjectArray netifs;
+ int numifs = 0;
+ int k;
+
+ if (getifaddrs (&ifaddrs) == -1)
+ {
+ JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
+ return NULL;
+ }
+
+ for (i = ifaddrs; i != NULL; i = i->ifa_next)
+ {
+ if (iflist == NULL)
+ {
+ iflist = JCL_malloc (env, sizeof (struct netif_entry));
+ if (iflist == NULL)
+ {
+ freeifaddrs (ifaddrs);
+ return NULL;
+ }
+ iflist->name = i->ifa_name;
+ iflist->numaddrs = 0;
+ iflist->next = NULL;
+ iflist->netif = (*env)->NewObject (env, clazz, java_net_VMNetworkInterface_init,
+ (*env)->NewStringUTF (env, i->ifa_name));
+ if (iflist->netif == NULL)
+ {
+ freeifaddrs (ifaddrs);
+ JCL_free (env, iflist);
+ return NULL;
+ }
+ e = iflist;
+ }
+ else
+ {
+ struct netif_entry *p = NULL;
+ for (e = iflist; e != NULL; e = e->next)
+ {
+ if (strcmp (e->name, i->ifa_name) == 0)
+ break;
+ p = e;
+ }
+
+ if (e == NULL)
+ {
+ p->next = (struct netif_entry *) JCL_malloc (env, sizeof (struct netif_entry));
+ if (p->next == NULL)
+ {
+ free_netif_list (env, iflist);
+ freeifaddrs (ifaddrs);
+ return NULL;
+ }
+ e = p->next;
+ e->name = i->ifa_name;
+ e->numaddrs = 0;
+ e->next = NULL;
+ e->netif = (*env)->NewObject (env, clazz, java_net_VMNetworkInterface_init,
+ (*env)->NewStringUTF (env, i->ifa_name));
+ if (e->netif == NULL)
+ {
+ free_netif_list (env, iflist);
+ freeifaddrs (ifaddrs);
+ return NULL;
+ }
+ }
+ }
+
+ if (i->ifa_addr == NULL)
+ continue;
+
+ if (i->ifa_addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *) i->ifa_addr;
+ jobject buffer = (*env)->NewDirectByteBuffer (env, &(sin->sin_addr.s_addr), 4);
+ (*env)->CallVoidMethod (env, e->netif, java_net_VMNetworkInterface_addAddress,
+ buffer);
+ if ((*env)->ExceptionCheck (env))
+ {
+ free_netif_list (env, iflist);
+ freeifaddrs (ifaddrs);
+ return NULL;
+ }
+ (*env)->DeleteLocalRef (env, buffer);
+ e->numaddrs++;
+ }
+#ifdef HAVE_INET6
+ else if (i->ifa_addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin = (struct sockaddr_in6 *) i->ifa_addr;
+ jobject buffer = (*env)->NewDirectByteBuffer (env, &(sin->sin6_addr.s6_addr), 16);
+ (*env)->CallVoidMethod (env, e->netif, java_net_VMNetworkInterface_addAddress,
+ buffer);
+ if ((*env)->ExceptionCheck (env))
+ {
+ free_netif_list (env, iflist);
+ freeifaddrs (ifaddrs);
+ return NULL;
+ }
+ (*env)->DeleteLocalRef (env, buffer);
+ e->numaddrs++;
+ }
+#endif /* HAVE_INET6 */
+ }
+
+ /* Count how many interfaces we have that have addresses. */
+ for (e = iflist; e != NULL; e = e->next)
+ {
+ if (e->numaddrs != 0)
+ numifs++;
+ }
+
+ netifs = (*env)->NewObjectArray (env, numifs, clazz, NULL);
+ k = 0;
+ for (e = iflist; e != NULL && k < numifs; e = e->next)
+ {
+ if (e->numaddrs != 0)
+ {
+ (*env)->SetObjectArrayElement (env, netifs, k, e->netif);
+ (*env)->DeleteLocalRef (env, e->netif);
+ k++;
+ }
+ }
+
+ free_netif_list (env, iflist);
+ freeifaddrs (ifaddrs);
+ return netifs;
+#else
+ JCL_ThrowException (env, "java/net/SocketException", "getifaddrs not supported");
+ return NULL;
+#endif /* HAVE_GETIFADDRS */
}
/* end of file */
diff --git a/native/jni/java-nio/Makefile.am b/native/jni/java-nio/Makefile.am
index 800d25be6..a4b830cd4 100644
--- a/native/jni/java-nio/Makefile.am
+++ b/native/jni/java-nio/Makefile.am
@@ -3,16 +3,22 @@ nativeexeclib_LTLIBRARIES = libjavanio.la
libjavanio_la_SOURCES = gnu_java_nio_VMPipe.c \
gnu_java_nio_VMChannel.c \
gnu_java_nio_VMSelector.c \
- gnu_java_nio_channels_FileChannelImpl.c \
gnu_java_nio_charset_iconv_IconvDecoder.c \
gnu_java_nio_charset_iconv_IconvEncoder.c \
+ gnu_java_nio_channels_FileChannelImpl.c \
java_nio_MappedByteBufferImpl.c \
- java_nio_VMDirectByteBuffer.c
+ java_nio_VMDirectByteBuffer.c \
+ gnu_java_nio_EpollSelectorImpl.c \
+ gnu_java_nio_KqueueSelectorImpl.c \
+ javanio.h
libjavanio_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo \
$(top_builddir)/native/jni/native-lib/libclasspathnative.la \
$(LTLIBICONV)
+# Directly included through javanio.h
+EXTRA_DIST = javanio.c
+
AM_LDFLAGS = @CLASSPATH_MODULE@
AM_CPPFLAGS = @CLASSPATH_INCLUDES@
AM_CFLAGS = @WARNING_CFLAGS@ @STRICT_WARNING_CFLAGS@ @ERROR_CFLAGS@
diff --git a/native/jni/java-nio/gnu_java_nio_EpollSelectorImpl.c b/native/jni/java-nio/gnu_java_nio_EpollSelectorImpl.c
new file mode 100644
index 000000000..d794e6d9f
--- /dev/null
+++ b/native/jni/java-nio/gnu_java_nio_EpollSelectorImpl.c
@@ -0,0 +1,414 @@
+/* gnu_java_nio_EpollSelectorImpl.c --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_SYS_EPOLL_H
+#include <sys/epoll.h>
+#endif /* HAVE_SYS_EPOLL_H */
+
+#include <gnu_java_nio_EpollSelectorImpl.h>
+#include <jcl.h>
+#include <errno.h>
+#include <string.h>
+
+#define IO_EXCEPTION "java/io/IOException"
+
+/* #define TRACE_EPOLL 1 */
+
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: epoll_supported
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_epoll_1supported (JNIEnv *e __attribute__((unused)),
+ jclass c __attribute__((unused)))
+{
+#ifdef HAVE_EPOLL_CREATE
+ return JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif /* HAVE_EPOLL_CREATE */
+}
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: sizeof_struct
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_sizeof_1struct (JNIEnv *env,
+ jclass c __attribute__((unused)))
+{
+#ifdef HAVE_EPOLL_CREATE
+ (void) env;
+#ifdef TRACE_EPOLL
+ fprintf (stderr, "%s: sizeof is %d\n", __FUNCTION__, sizeof (struct epoll_event));
+#endif /* TRACE_EPOLL */
+ return sizeof (struct epoll_event);
+#else
+ JCL_ThrowException (env, "java/lang/InternalError", "epoll support not available");
+ return -1;
+#endif /* HAVE_EPOLL_CREATE */
+}
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: epoll_create
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_epoll_1create (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint size)
+{
+#ifdef HAVE_EPOLL_CREATE
+ int fd = epoll_create (size);
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, "%s: epoll_create returns %d\n", __FUNCTION__, fd);
+#endif /* TRACE_EPOLL */
+
+ if (fd == -1)
+ {
+ if (ENOSYS == errno)
+ JCL_ThrowException (env, "java/lang/InternalError",
+ strerror (errno));
+ else
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ }
+ return fd;
+#else
+ (void) size;
+ JCL_ThrowException (env, "java/lang/InternalError", "epoll support not available");
+ return -1;
+#endif /* HAVE_EPOLL_CREATE */
+}
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: epoll_add
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_epoll_1add (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint efd, jint fd, jint ops)
+{
+#ifdef HAVE_EPOLL_CREATE
+ struct epoll_event event;
+
+ memset (&event, 0, sizeof (struct epoll_event));
+
+ if ((ops & gnu_java_nio_EpollSelectorImpl_OP_ACCEPT) != 0
+ || (ops & gnu_java_nio_EpollSelectorImpl_OP_READ) != 0)
+ event.events = EPOLLIN;
+
+ if ((ops & gnu_java_nio_EpollSelectorImpl_OP_CONNECT) != 0
+ || (ops & gnu_java_nio_EpollSelectorImpl_OP_WRITE) != 0)
+ event.events |= EPOLLOUT;
+
+ event.data.fd = fd;
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, "%s: adding struct epoll_event { events: %o; data.fd: %d } to %d\n",
+ __FUNCTION__, event.events, event.data.fd, efd);
+#endif /* TRACE_EPOLL */
+
+ if (epoll_ctl (efd, EPOLL_CTL_ADD, fd, &event) == -1)
+ {
+ if (ENOSYS == errno)
+ JCL_ThrowException (env, "java/lang/InternalError",
+ strerror (errno));
+ else
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ }
+#else
+ (void) efd;
+ (void) fd;
+ (void) ops;
+ JCL_ThrowException (env, "java/lang/InternalError", "epoll support not available");
+#endif /* HAVE_EPOLL_CREATE */
+}
+
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: epoll_modify
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_epoll_1modify (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint efd, jint fd, jint ops)
+{
+#ifdef HAVE_EPOLL_CREATE
+ struct epoll_event event;
+
+ memset (&event, 0, sizeof (struct epoll_event));
+
+ if ((ops & gnu_java_nio_EpollSelectorImpl_OP_ACCEPT) != 0
+ || (ops & gnu_java_nio_EpollSelectorImpl_OP_READ) != 0)
+ event.events = EPOLLIN;
+
+ if ((ops & gnu_java_nio_EpollSelectorImpl_OP_CONNECT) != 0
+ || (ops & gnu_java_nio_EpollSelectorImpl_OP_WRITE) != 0)
+ event.events |= EPOLLOUT;
+
+ event.data.fd = fd;
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, "%s: modding struct epoll_event { events: %o; data.fd: %d } on %d\n",
+ __FUNCTION__, event.events, event.data.fd, efd);
+#endif /* TRACE_EPOLL */
+
+ if (epoll_ctl (efd, EPOLL_CTL_MOD, fd, &event) == -1)
+ {
+ if (ENOSYS == errno)
+ JCL_ThrowException (env, "java/lang/InternalError",
+ strerror (errno));
+ else
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ }
+#else
+ (void) efd;
+ (void) fd;
+ (void) ops;
+ JCL_ThrowException (env, "java/lang/InternalError", "epoll support not available");
+#endif /* HAVE_EPOLL_CREATE */
+}
+
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: epoll_delete
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_epoll_1delete (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint efd, jint fd)
+{
+#ifdef HAVE_EPOLL_CREATE
+ struct epoll_event event;
+
+ memset (&event, 0, sizeof (struct epoll_event));
+ event.data.fd = fd;
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, "%s: delete events on fd %d for %d\n", __FUNCTION__, fd, efd);
+#endif /* TRACE_EPOLL */
+
+ /* Older kernel versions require a non-null `event' parameter,
+ * even though it is ignored by this call.
+ */
+ if (epoll_ctl (efd, EPOLL_CTL_DEL, fd, &event) == -1)
+ {
+ if (ENOSYS == errno)
+ JCL_ThrowException (env, "java/lang/InternalError",
+ strerror (errno));
+ /* XXX the docs here seem a little strange. If `fd' is closed,
+ epoll_ctl returns EBADF; but the docs say that this happens
+ only when efd is invalid. Go figure.
+ */
+ else if (ENOENT == errno || EBADF == errno)
+ return; /* fd is closed; it's already removed. */
+ else
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ }
+#else
+ (void) efd;
+ (void) fd;
+ JCL_ThrowException (env, "java/lang/InternalError", "epoll support not available");
+#endif /* HAVE_EPOLL_CREATE */
+}
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: epoll_wait
+ * Signature: (ILjava/nio/ByteBuffer;II)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_epoll_1wait (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint efd, jobject nstate,
+ jint num_events, jint timeout)
+{
+#ifdef HAVE_EPOLL_CREATE
+ void *p = (*env)->GetDirectBufferAddress (env, nstate);
+ struct epoll_event *events = (struct epoll_event *) p;
+ int ret;
+
+ if (p == NULL)
+ {
+ if (!(*env)->ExceptionCheck (env))
+ JCL_ThrowException (env, IO_EXCEPTION, "getting native state failed");
+ return -1;
+ }
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, "%s: events: %p; num_events: %d; timeout: %d; efd: %d\n",
+ __FUNCTION__, p, num_events, timeout, efd);
+#endif /* TRACE_EPOLL */
+
+ ret = epoll_wait (efd, events, num_events, timeout);
+
+ if (ret == -1)
+ {
+ if (ENOSYS == errno)
+ JCL_ThrowException (env, "java/lang/InternalError",
+ strerror (errno));
+ else if (EINTR == errno)
+ ret = 0;
+ else
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ }
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, " epoll_wait returns %d\n", ret);
+ {
+ int i;
+ for (i = 0; i < ret; i++)
+ {
+ fprintf (stderr, " [%4i]: events: %o; data.fd: %d\n", i, events[i].events,
+ events[i].data.fd);
+ }
+ }
+ fflush (stderr);
+#endif /* TRACE_EPOLL */
+
+ return ret;
+#else
+ (void) efd;
+ (void) nstate;
+ (void) num_events;
+ (void) timeout;
+ JCL_ThrowException (env, "java/lang/InternalError", "epoll support not available");
+ return -1;
+#endif /* HAVE_EPOLL_CREATE */
+}
+
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: selected_fd
+ * Signature: (Ljava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_selected_1fd (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jobject value)
+{
+#ifdef HAVE_EPOLL_CREATE
+ void *p = (*env)->GetDirectBufferAddress (env, value);
+ struct epoll_event *event = (struct epoll_event *) p;
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, "%s: event: %p\n", __FUNCTION__, p);
+#endif /* TRACE_EPOLL */
+
+ if (p == NULL)
+ {
+ if (!(*env)->ExceptionCheck (env))
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "getting native state failed");
+ return -1;
+ }
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, " data.fd: %d\n", event->data.fd);
+ fflush (stderr);
+#endif /* TRACE_EPOLL */
+
+ return event->data.fd;
+#else
+ (void) value;
+ JCL_ThrowException (env, "java/lang/InternalError", "epoll support not available");
+ return -1;
+#endif /* HAVE_EPOLL_CREATE */
+}
+
+
+/*
+ * Class: gnu_java_nio_EpollSelectorImpl
+ * Method: selected_ops
+ * Signature: (Ljava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_EpollSelectorImpl_selected_1ops (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jobject value)
+{
+#ifdef HAVE_EPOLL_CREATE
+ void *p = (*env)->GetDirectBufferAddress (env, value);
+ struct epoll_event *event = (struct epoll_event *) p;
+ int ret = 0;
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, "%s: event: %p\n", __FUNCTION__, p);
+#endif /* TRACE_EPOLL */
+
+ if (p == NULL)
+ {
+ if (!(*env)->ExceptionCheck (env))
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "getting native state failed");
+ return -1;
+ }
+
+ if ((event->events & EPOLLIN) != 0)
+ ret |= gnu_java_nio_EpollSelectorImpl_OP_ACCEPT | gnu_java_nio_EpollSelectorImpl_OP_READ;
+ if ((event->events & EPOLLOUT) != 0)
+ ret |= gnu_java_nio_EpollSelectorImpl_OP_CONNECT | gnu_java_nio_EpollSelectorImpl_OP_WRITE;
+
+#ifdef TRACE_EPOLL
+ fprintf (stderr, " events: %o\n", event->events);
+ fflush (stderr);
+#endif /* TRACE_EPOLL */
+
+ return ret;
+#else
+ (void) value;
+ JCL_ThrowException (env, "java/lang/InternalError", "epoll support not available");
+ return -1;
+#endif /* HAVE_EPOLL_CREATE */
+}
diff --git a/native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c b/native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c
new file mode 100644
index 000000000..94e6db7f8
--- /dev/null
+++ b/native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c
@@ -0,0 +1,387 @@
+/* gnu_java_nio_channel_KqueueSelectorImpl.c --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#if HAVE_SYS_EVENT_H
+#include <sys/event.h>
+#endif /* HAVE_SYS_EVENT_H */
+#include <sys/time.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <jni.h>
+#include <gnu_java_nio_KqueueSelectorImpl.h>
+
+#include <jcl.h>
+
+#define KEY_OP_ACCEPT 16
+#define KEY_OP_CONNECT 8
+#define KEY_OP_READ 1
+#define KEY_OP_WRITE 4
+
+/* XXX this requires -std=gnu99 or c99 */
+/* #ifdef TRACE_KQUEUE */
+/* #define TRACE(fmt, ...) fprintf (stderr, "%s: " fmt "\n", __FUNCTION__, __VA_ARGS__); */
+/* #else */
+/* #define TRACE(fmt, ...) */
+/* #endif */
+
+/* #define TRACE_KQUEUE 1 */
+
+
+#define throw_not_supported(env) JCL_ThrowException (env, "java/lang/UnsupportedOperationException", "kqueue/kevent support not available")
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: kqueue_supported
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_kqueue_1supported (JNIEnv *env __attribute__((unused)),
+ jclass clazz __attribute__((unused)))
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+ return JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif /* HAVE_KQUEUE && HAVE_KEVENT */
+}
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: sizeof_struct_kevent
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_sizeof_1struct_1kevent
+(JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused)))
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+/* TRACE("return sizeof %lu", sizeof (struct kevent)); */
+ return sizeof (struct kevent);
+#else
+ throw_not_supported (env);
+ return -1;
+#endif /* HAVE_KQUEUE && HAVE_KEVENT */
+}
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: implOpen
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_implOpen
+(JNIEnv *env, jclass clazz __attribute__((unused)))
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+ int kq = kqueue ();
+/* TRACE("kqueue returns %d", kq); */
+ if (kq == -1)
+ JCL_ThrowException (env, "java/io/IOException", strerror (errno));
+ return kq;
+#else
+ throw_not_supported (env);
+ return -1;
+#endif
+}
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: implClose
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_implClose (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jint kq)
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+/* TRACE("closing %d", kq); */
+ if (close (kq) != 0)
+ JCL_ThrowException (env, "java/io/IOException", strerror (errno));
+#else
+ (void) kq;
+ throw_not_supported (env);
+#endif /* HAVE_KQUEUE && HAVE_KEVENT */
+}
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: kevent_set
+ * Signature: (Ljava/nio/ByteBuffer;IIIZ)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_kevent_1set (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jobject nstate, jint i, jint fd,
+ jint ops, jint active, jint key)
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+ struct kevent *kev;
+ short ident;
+
+ kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
+
+#ifdef TRACE_KQUEUE
+ printf ("kevent_set fd:%d p:%p i:%d ops:%x active:%x key:%x\n",
+ fd, (void *) kev, i, ops, active, key);
+#endif /* TRACE_KQUEUE */
+
+ if (kev == NULL)
+ {
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "GetDirectBufferAddress returned NULL!");
+ return;
+ }
+
+ ident = fd;
+ memset (&kev[i], 0, sizeof (struct kevent));
+
+ if ((ops & KEY_OP_READ) || (ops & KEY_OP_ACCEPT))
+ {
+ /* Add event if it wasn't previously added. */
+ if (!(active & KEY_OP_READ) && !(active & KEY_OP_ACCEPT))
+ EV_SET(&kev[i], ident, EVFILT_READ, EV_ADD, 0, 0, (void *) key);
+ }
+ else
+ {
+ /* Delete event if it was previously added */
+ if ((active & KEY_OP_READ) || (active & KEY_OP_ACCEPT))
+ EV_SET(&kev[i], ident, EVFILT_READ, EV_DELETE, 0, 0, (void *) key);
+ }
+
+ /* Do the same thing for the write filter. */
+ if ((ops & KEY_OP_WRITE) || (ops & KEY_OP_CONNECT))
+ {
+ if (!(active & KEY_OP_WRITE) && !(active & KEY_OP_CONNECT))
+ EV_SET(&kev[i], ident, EVFILT_WRITE, EV_ADD, 0, 0, (void *) key);
+ }
+ else
+ {
+ if ((active & KEY_OP_WRITE) || (active & KEY_OP_CONNECT))
+ EV_SET(&kev[i], ident, EVFILT_WRITE, EV_DELETE, 0, 0, (void *) key);
+ }
+
+#ifdef TRACE_KQUEUE
+ printf (" set kevent %2d: ident:%u filter:%x flags:%o fflags:%o data:%p udata:%p\n",
+ i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, kev[i].fflags,
+ (void *) kev[i].data, kev[i].udata);
+#endif /* TRACE_KQUEUE */
+#else
+ (void) nstate;
+ (void) i;
+ (void) fd;
+ (void) ops;
+ (void) key;
+ (void) active;
+ throw_not_supported (env);
+#endif /* HAVE_KQUEUE && HAVE_KEVENT */
+}
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: kevent
+ * Signature: (ILjava/nio/ByteBuffer;IJ)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_kevent (JNIEnv *env,
+ jobject this __attribute__((unused)),
+ jint kq, jobject nstate, jint nevents,
+ jint maxevents, jlong timeout)
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+ struct timespec tv;
+ struct timespec *t = NULL;
+ struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
+ int ret;
+
+#ifdef TRACE_KQUEUE
+ int i;
+
+ printf ("[%d] kevent nevents:%d maxevents:%d timeout:%lld\n", kq, nevents, maxevents, timeout);
+ printf ("[%d] addding/deleting %d events\n", kq, nevents);
+ for (i = 0; i < nevents; i++)
+ {
+ printf ("[%d] kevent input [%d]: ident:%u filter:%x flags:%o fflags:%o data:%p udata:%p\n",
+ kq, i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, kev[i].fflags,
+ (void *) kev[i].data, kev[i].udata);
+ }
+#endif
+
+/* TRACE("events: %p; nevents: %d; timeout: %lld", (void *) kev, nevents, timeout); */
+
+ if (timeout != -1)
+ {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_nsec = (timeout % 1000) * 1000;
+ t = &tv;
+ }
+
+ ret = kevent (kq, (const struct kevent *) kev, nevents, kev, maxevents, t);
+
+ if (ret == -1)
+ {
+ if (errno == EINTR)
+ ret = 0;
+ else
+ JCL_ThrowException (env, "java/io/IOException", strerror (errno));
+ }
+
+#ifdef TRACE_KQUEUE
+ for (i = 0; i < ret; i++)
+ {
+ printf ("[%d] kevent output [%d]: ident:%u filter:%x flags:%o fflags:%o data:%p udata:%p\n",
+ kq, i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, kev[i].fflags,
+ (void *) kev[i].data, kev[i].udata);
+ }
+#endif
+
+ return ret;
+#else
+ (void) kq;
+ (void) nstate;
+ (void) nevents;
+ (void) maxevents;
+ (void) timeout;
+ throw_not_supported (env);
+ return -1;
+#endif /* HAVE_KQUEUE && HAVE_KEVENT */
+}
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: fetch_key
+ * Signature: (Ljava/nio/ByteBuffer;)I;
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_fetch_1key (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jobject nstate)
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+ struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
+/* TRACE("return key %p\n", kev->udata); */
+ return (jint) kev->udata;
+#else
+ (void) nstate;
+ throw_not_supported (env);
+ return -1;
+#endif /* HAVE_KQUEUE && HAVE_KEVENT */
+}
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: ready_ops
+ * Signature: (Ljava/nio/ByteBuffer;I)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_ready_1ops (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jobject nstate, jint interest)
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+ struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
+ jint ready = 0;
+
+ if ((kev->flags & EV_ERROR) == EV_ERROR)
+ {
+ printf ("!!! error selecting fd %d: %s", (int) (kev->ident), strerror ((int) (kev->data)));
+ return 0;
+ }
+
+ /* We poll for READ for OP_READ and OP_ACCEPT. */
+ if (kev->filter == EVFILT_READ)
+ {
+ ready = (interest & KEY_OP_READ) | (interest & KEY_OP_ACCEPT);
+/* TRACE("filter EVFILT_READ. Ready ops set to %x", ready); */
+ }
+
+ /* Poll for WRITE for OP_WRITE and OP_CONNECT; I guess we *should*
+ get a WRITE event if we are connected, but I don't know if we do
+ for real. FIXME */
+ if (kev->filter == EVFILT_WRITE)
+ {
+ ready = (interest & KEY_OP_WRITE) | (interest & KEY_OP_CONNECT);
+/* TRACE("filter EVFILT_WRITE. Ready ops set to %x", ready); */
+ }
+
+ return ready;
+#else
+ (void) nstate;
+ (void) interest;
+ throw_not_supported (env);
+ return -1;
+#endif /* HAVE_KQUEUE && HAVE_KEVENT */
+}
+
+
+/*
+ * Class: gnu_java_nio_KqueueSelectorImpl
+ * Method: check_eof
+ * Signature: (Ljava/nio/ByteBuffer;)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_nio_KqueueSelectorImpl_check_1eof (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jobject nstate)
+{
+#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
+ struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
+ if ((kev->flags & EV_EOF) == EV_EOF)
+ return JNI_TRUE;
+ return JNI_FALSE;
+#else
+ (void) nstate;
+ throw_not_supported (env);
+ return JNI_FALSE;
+#endif
+}
diff --git a/native/jni/java-nio/gnu_java_nio_VMChannel.c b/native/jni/java-nio/gnu_java_nio_VMChannel.c
index 5571bed27..b4f444361 100644
--- a/native/jni/java-nio/gnu_java_nio_VMChannel.c
+++ b/native/jni/java-nio/gnu_java_nio_VMChannel.c
@@ -36,25 +36,43 @@ obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
-#include <sys/uio.h>
#include <string.h>
#include <jni.h>
#include <jcl.h>
#include "gnu_java_nio_VMChannel.h"
+#include "javanio.h"
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#define IO_EXCEPTION "java/io/IOException"
+#define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException"
#define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException"
#define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException"
+#define SOCKET_TIMEOUT_EXCEPTION "java/net/SocketTimeoutException"
+
+/* Align a value up or down to a multiple of the pagesize. */
+#define ALIGN_DOWN(p,s) ((p) - ((p) % (s)))
+#define ALIGN_UP(p,s) ((p) + ((s) - ((p) % (s))))
/*
* Limit to maximum of 16 buffers
@@ -66,7 +84,7 @@ extern "C"
{
#endif
-enum JCL_buffer_type { DIRECT, ARRAY, UNKNOWN };
+enum JCL_buffer_type { DIRECT, HEAP, ARRAY, UNKNOWN };
struct JCL_buffer
{
@@ -98,6 +116,7 @@ get_method_id(JNIEnv *env, jclass clazz, const char *name,
const char *sig)
{
jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig);
+/* NIODBG("name: %s; sig: %s", name, sig); */
if (mid == NULL)
{
JCL_ThrowException(env, "java/lang/InternalError", name);
@@ -107,18 +126,19 @@ get_method_id(JNIEnv *env, jclass clazz, const char *name,
return mid;
}
-void
+inline void
JCL_print_buffer(JNIEnv *env __attribute__((__unused__)), struct JCL_buffer *buf)
{
- fprintf(stdout, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr);
- fflush(stdout);
+ fprintf (stderr, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr);
}
int
JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
{
- jobject address = (*env)->GetObjectField(env, bbuf, address_fid);
+ void *addr = (*env)->GetDirectBufferAddress (env, bbuf);
+
+/* NIODBG("buf: %p; bbuf: %p; addr: %p", (void *) buf, bbuf, addr); */
buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid);
buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid);
@@ -126,11 +146,10 @@ JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
buf->count = 0;
buf->type = UNKNOWN;
- if (address != NULL)
+ if (addr != NULL)
{
- buf->ptr = (jbyte *) JCL_GetRawData(env, address);
+ buf->ptr = (jbyte *) addr;
buf->type = DIRECT;
- (*env)->DeleteLocalRef(env, address);
}
else
{
@@ -148,7 +167,12 @@ JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
}
else
{
- return -1;
+ jobject address = (*env)->GetObjectField (env, bbuf, address_fid);
+ if (address == NULL)
+ return -1; /* XXX handle non-array, non-native buffers? */
+ buf->ptr = (jbyte *) JCL_GetRawData(env, address);
+ buf->type = HEAP;
+ (*env)->DeleteLocalRef(env, address);
}
}
@@ -160,6 +184,8 @@ JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf,
jint action)
{
jbyteArray arr;
+
+/* NIODBG("buf: %p; bbuf: %p; action: %x", (void *) buf, bbuf, action); */
/* Set the position to the appropriate value */
if (buf->count > 0)
@@ -173,6 +199,7 @@ JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf,
switch (buf->type)
{
case DIRECT:
+ case HEAP:
break;
case ARRAY:
arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
@@ -194,6 +221,9 @@ JCL_cleanup_buffers(JNIEnv *env,
jlong num_bytes)
{
jint i;
+
+/* NIODBG("bi_list: %p; vec_len: %d; bbufs: %p; offset: %d; num_bytes: %lld", */
+/* (void *) bi_list, vec_len, bbufs, offset, num_bytes); */
/* Update all of the bbufs with the approriate information */
for (i = 0; i < vec_len; i++)
@@ -217,13 +247,57 @@ JCL_cleanup_buffers(JNIEnv *env,
}
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: stdin_fd
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_stdin_1fd (JNIEnv *env __attribute__((unused)),
+ jclass c __attribute__((unused)))
+{
+/* NIODBG("%d", fileno (stdin)); */
+ return fileno (stdin);
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: stdout_fd
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_stdout_1fd (JNIEnv *env __attribute__((unused)),
+ jclass c __attribute__((unused)))
+{
+/* NIODBG("%d", fileno (stdout)); */
+ return fileno (stdout);
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: stderr_fd
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_stderr_1fd (JNIEnv *env __attribute__((unused)),
+ jclass c __attribute__((unused)))
+{
+/* NIODBG("%d", fileno (stderr)); */
+ return fileno (stderr);
+}
+
+
JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env,
jclass clazz __attribute__ ((__unused__)))
{
jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer");
jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer");
-
+
+/* NIODBG("%s", "..."); */
+
address_fid = (*env)->GetFieldID(env, bufferClass, "address",
"Lgnu/classpath/Pointer;");
if (address_fid == NULL)
@@ -252,6 +326,8 @@ Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env,
{
int opts;
+/* NIODBG("fd: %d; blocking: %d", fd, blocking); */
+
opts = fcntl(fd, F_GETFL);
if (opts < 0)
{
@@ -260,10 +336,10 @@ Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env,
return;
}
- if (blocking)
- opts |= O_NONBLOCK;
- else
+ if (blocking == JNI_TRUE)
opts &= ~(O_NONBLOCK);
+ else
+ opts |= O_NONBLOCK;
opts = fcntl(fd, F_SETFL, opts);
@@ -277,14 +353,17 @@ Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env,
JNIEXPORT jint JNICALL
-Java_gnu_java_nio_VMChannel_read (JNIEnv *env,
- jobject o __attribute__ ((__unused__)),
- jint fd,
- jobject bbuf)
+Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
+ jobject o __attribute__ ((__unused__)),
+ jint fd,
+ jobject bbuf)
{
+#ifdef HAVE_READ
jint len;
ssize_t result;
struct JCL_buffer buf;
+
+/* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
if (JCL_init_buffer(env, &buf, bbuf) < 0)
{
@@ -292,14 +371,22 @@ Java_gnu_java_nio_VMChannel_read (JNIEnv *env,
JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
return -1;
}
-
+
len = buf.limit - buf.position;
+
+ if (len == 0)
+ {
+ JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
+ return 0;
+ }
- result = read(fd, &(buf.ptr[buf.position + buf.offset]), len);
- buf.count = result;
+ result = cpnio_read (fd, &(buf.ptr[buf.position + buf.offset]), len);
if (result == 0)
- result = -1; /* End Of File */
+ {
+ result = -1;
+ buf.count = 0;
+ }
else if (result == -1)
{
buf.count = 0;
@@ -311,7 +398,13 @@ Java_gnu_java_nio_VMChannel_read (JNIEnv *env,
JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
strerror(errno));
return -1;
- }
+ }
+ else if (EINTR == errno) /* read interrupted */
+ {
+ JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
+ JCL_ThrowException(env, INTERRUPTED_IO_EXCEPTION, strerror (errno));
+ return -1;
+ }
else
{
JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
@@ -320,21 +413,31 @@ Java_gnu_java_nio_VMChannel_read (JNIEnv *env,
}
}
else
-
- JCL_release_buffer(env, &buf, bbuf, JNI_COMMIT);
+ buf.count = result;
+
+ JCL_release_buffer(env, &buf, bbuf, 0);
return result;
+#else
+ (void) fd;
+ (void) bbuf;
+ JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
+ return -1;
+#endif /* HAVE_READ */
}
JNIEXPORT jint JNICALL
-Java_gnu_java_nio_VMChannel_write (JNIEnv *env,
- jobject o __attribute__ ((__unused__)),
- jint fd,
- jobject bbuf)
+Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
+ jobject o __attribute__ ((__unused__)),
+ jint fd,
+ jobject bbuf)
{
+#ifdef HAVE_WRITE
jint len;
ssize_t result;
struct JCL_buffer buf;
+
+/* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
if (JCL_init_buffer(env, &buf, bbuf) < 0)
{
@@ -342,16 +445,24 @@ Java_gnu_java_nio_VMChannel_write (JNIEnv *env,
JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
return -1;
}
-
+
len = buf.limit - buf.position;
+
+ if (len == 0)
+ {
+ JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
+ return 0;
+ }
- result = write(fd, &(buf.ptr[buf.position + buf.offset]), len);
+ result = cpnio_write (fd, &(buf.ptr[buf.position + buf.offset]), len);
buf.count = result;
-
+
if (result == -1)
{
if (errno == EAGAIN) /* Non-blocking */
+ {
result = 0;
+ }
else
{
JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
@@ -362,7 +473,13 @@ Java_gnu_java_nio_VMChannel_write (JNIEnv *env,
JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
- return result;
+ return result;
+#else
+ (void) fd;
+ (void) bbuf;
+ JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
+ return -1;
+#endif /* HAVE_WRITE */
}
@@ -390,7 +507,10 @@ Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env,
struct JCL_buffer bi_list[JCL_IOV_MAX];
ssize_t result;
jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
- jlong bytes_read = 0;
+ jlong bytes_read = 0;
+
+/* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
+/* fd, bbufs, offset, length); */
/* Build the vector of buffers to read into */
for (i = 0; i < vec_len; i++)
@@ -401,7 +521,9 @@ Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env,
buf = &bi_list[i];
bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
- JCL_init_buffer(env, buf, bbuf);
+ JCL_init_buffer(env, buf, bbuf);
+
+/* JCL_print_buffer (env, buf); */
buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
buffers[i].iov_len = buf->limit - buf->position;
@@ -409,7 +531,7 @@ Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env,
}
/* Work the scattering magic */
- result = readv(fd, buffers, vec_len);
+ result = cpnio_readv (fd, buffers, vec_len);
bytes_read = (jlong) result;
/* Handle the response */
@@ -442,6 +564,7 @@ Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env,
return (jlong) result;
}
+
/*
* Implementation of a gathering write. Will use the appropriate
* vector based read call (currently readv on Linux).
@@ -468,6 +591,8 @@ Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env,
jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
jlong bytes_written;
+/* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
+/* fd, bbufs, offset, length); */
/* Build the vector of buffers to read into */
for (i = 0; i < vec_len; i++)
@@ -480,13 +605,15 @@ Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env,
JCL_init_buffer(env, buf, bbuf);
+/* JCL_print_buffer(env, buf); */
+
buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
buffers[i].iov_len = buf->limit - buf->position;
(*env)->DeleteLocalRef(env, bbuf);
}
/* Work the gathering magic */
- result = writev(fd, buffers, vec_len);
+ result = cpnio_writev (fd, buffers, vec_len);
bytes_written = (jlong) result;
if (result < 0)
@@ -518,6 +645,1150 @@ Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env,
}
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: receive
+ * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_receive (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jobject dst, jobject addrPort)
+{
+#ifdef HAVE_RECVFROM
+ char *addrPortPtr = (*env)->GetDirectBufferAddress (env, addrPort);
+ struct JCL_buffer buf;
+#ifdef HAVE_INET6
+ struct sockaddr_in6 sock_storage;
+ struct sockaddr_in6 *sock6;
+ socklen_t slen = sizeof (struct sockaddr_in6);
+#else
+ struct sockaddr_in sock_storage;
+ socklen_t slen = sizeof (struct sockaddr_in);
+#endif /* HAVE_INET6 */
+ struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
+ struct sockaddr_in *sock4;
+ int ret;
+ jint result = -1;
+
+ if (JCL_init_buffer (env, &buf, dst) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
+
+ ret = cpnio_recvfrom (fd, &(buf.ptr[buf.position + buf.offset]),
+ buf.limit - buf.position, MSG_WAITALL,
+ sockaddr, &slen);
+
+ if (-1 == ret)
+ {
+ JCL_release_buffer (env, &buf, dst, JNI_ABORT);
+ if (EINTR == errno)
+ JCL_ThrowException (env, "java/io/InterruptedIOException", strerror (errno));
+ else if (EAGAIN == errno)
+ {
+ /* If the socket is in blocking mode, our timeout expired. */
+ int val = fcntl (fd, F_GETFL, 0);
+ if (val == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ else if ((val & O_NONBLOCK) == 0)
+ JCL_ThrowException (env, "java/net/SocketTimeoutException",
+ "read timed out");
+ }
+ else
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return 0;
+ }
+
+ if (sockaddr->sa_family == AF_INET)
+ {
+ sock4 = (struct sockaddr_in *) sockaddr;
+ memcpy (addrPortPtr, &(sock4->sin_addr.s_addr), 4);
+ ;memcpy (addrPortPtr + 4, &(sock4->sin_port), 2);
+ result = 4;
+ }
+#ifdef HAVE_INET6
+ else if (sockaddr->sa_family == AF_INET6)
+ {
+ sock6 = (struct sockaddr_in6 *) sockaddr;
+ memcpy (addrPortPtr, &(sock6->sin6_addr.s6_addr), 16);
+ memcpy (addrPortPtr + 16, &(sock6->sin6_port), 2);
+ result = 16;
+ }
+#endif /* HAVE_INET6 */
+ else if (ret == 0)
+ {
+ result = 0;
+ }
+ else
+ {
+ JCL_ThrowException (env, "java/net/SocketException",
+ "unsupported address type returned");
+ }
+
+ buf.count += ret;
+ JCL_release_buffer (env, &buf, dst, 0);
+ return result;
+#else
+ (void) fd;
+ (void) dst;
+ (void) addrPort;
+ JCL_ThrowException (env, IO_EXCEPTION, "recvfrom not supported");
+#endif /* HAVE_RECVFROM */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: send
+ * Signature: (Ljava/nio/ByteBuffer;[BI)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_send (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ int fd, jobject src, jbyteArray addr, jint port)
+{
+#ifdef HAVE_SENDTO
+ struct sockaddr_in sockaddr;
+ jbyte *elems;
+ struct JCL_buffer buf;
+ int ret;
+
+/* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
+/* fd, src, addr, port); */
+
+ if (JCL_init_buffer (env, &buf, src) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
+ return -1;
+ }
+
+/* JCL_print_buffer (env, &buf); */
+
+ elems = (*env)->GetByteArrayElements (env, addr, NULL);
+
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_addr.s_addr = *((uint32_t *) elems);
+ sockaddr.sin_port = htons (port);
+
+ do
+ {
+ ret = cpnio_sendto (fd, &(buf.ptr[buf.position + buf.offset]),
+ buf.limit - buf.position,
+ 0, (const struct sockaddr *) &sockaddr,
+ sizeof (struct sockaddr_in));
+ }
+ while (-1 == ret && EINTR == errno);
+
+ (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
+
+ if (-1 == ret)
+ {
+ if (errno != EAGAIN)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ JCL_release_buffer (env, &buf, src, JNI_ABORT);
+ return 0;
+ }
+
+ buf.count += ret;
+ JCL_release_buffer (env, &buf, src, JNI_ABORT);
+ return ret;
+#else
+ (void) fd;
+ (void) src;
+ (void) addr;
+ (void) port;
+#endif /* HAVE_SENDTO */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: send6
+ * Signature: (Ljava/nio/ByteBuffer;[BI)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_send6 (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ int fd, jobject src, jbyteArray addr, jint port)
+{
+#if defined(HAVE_SENDTO) && defined(HAVE_INET6)
+ struct sockaddr_in6 sockaddr;
+ jbyte *elems;
+ struct JCL_buffer buf;
+ int ret;
+
+/* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
+/* fd, src, addr, port); */
+
+ if (JCL_init_buffer (env, &buf, src) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
+ return -1;
+ }
+
+/* JCL_print_buffer (env, &buf); */
+
+ elems = (*env)->GetByteArrayElements (env, addr, NULL);
+
+ sockaddr.sin6_family = AF_INET6;
+ memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16);
+ sockaddr.sin6_port = htons (port);
+
+ do
+ {
+ ret = cpnio_sendto (fd, (const void *) (buf.ptr + buf.offset),
+ buf.limit - buf.position,
+ 0, (const struct sockaddr *) &sockaddr,
+ sizeof (struct sockaddr_in6));
+ }
+ while (-1 == ret && EINTR == errno);
+
+ (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
+
+ if (-1 == ret)
+ {
+ if (errno != EAGAIN)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ JCL_release_buffer (env, &buf, src, JNI_ABORT);
+ return 0;
+ }
+
+ buf.count += ret;
+ JCL_release_buffer (env, &buf, src, JNI_ABORT);
+ return ret;
+#else
+ (void) fd;
+ (void) src;
+ (void) addr;
+ (void) port;
+ JCL_ThrowException (env, IO_EXCEPTION, "IPv6 sendto not supported");
+ return -1;
+#endif /* HAVE_SENDTO && HAVE_INET6 */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: read
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_read__I (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd)
+{
+#ifdef HAVE_READ
+ char in;
+ int ret;
+
+/* NIODBG("fd: %d", fd); */
+
+ ret = cpnio_read (fd, &in, 1);
+ if (-1 == ret)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ if (0 == ret)
+ return -1;
+
+ return (in & 0xFF);
+#else
+ (void) fd;
+ JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
+#endif /* HAVE_READ */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: write
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_VMChannel_write__II (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jint data)
+{
+#ifdef HAVE_WRITE
+ char out = (char) data;
+ int ret;
+
+/* NIODBG("fd: %d; data: %d", fd, data); */
+
+ ret = cpnio_write (fd, &out, 1);
+
+ if (-1 == ret)
+ JCL_ThrowException(env, IO_EXCEPTION, strerror (errno));
+#else
+ (void) fd;
+ (void) data;
+ JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
+#endif /* HAVE_WRITE */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: socket
+ * Signature: (Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_socket (JNIEnv *env, jclass clazz __attribute__((unused)),
+ jboolean stream)
+{
+#ifdef HAVE_SOCKET
+ int ret;
+
+ do
+ {
+ ret = cpnio_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
+ }
+ while (-1 == ret && EINTR == errno);
+
+ if (ret == -1)
+ JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
+/* NIODBG("created socket %d", ret); */
+
+ return ret;
+#else
+ (void) stream;
+ JCL_ThrowException (env, IO_EXCEPTION, "socket not supported");
+ return -1;
+#endif /* HAVE_SOCKET */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: connect
+ * Signature: (I[BI)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_nio_VMChannel_connect (JNIEnv *env, jclass clazz __attribute__((unused)),
+ jint fd, jbyteArray addr, jint port, jint timeout)
+{
+#ifdef HAVE_CONNECT
+ struct sockaddr_in sockaddr;
+ struct timeval timeo;
+ int origflags = 0, flags;
+ jbyte *addr_elems;
+ int ret;
+
+ if ((*env)->GetArrayLength (env, addr) != 4)
+ {
+ JCL_ThrowException (env, "java/io/IOException", "expecting 4-byte address");
+ return JNI_FALSE;
+ }
+
+ if (timeout > 0)
+ {
+ timeo.tv_sec = timeout / 1000;
+ timeo.tv_usec = (timeout % 1000) * 1000;
+ origflags = fcntl (fd, F_GETFL, 0);
+ if (origflags == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ /* Set nonblocking mode, if not already set. */
+ if (!(origflags & O_NONBLOCK))
+ {
+ flags = origflags | O_NONBLOCK;
+ if (fcntl (fd, F_SETFL, flags) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ }
+ }
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+
+ memset (&sockaddr, 0, sizeof (struct sockaddr_in));
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_port = htons (port);
+ sockaddr.sin_addr.s_addr = *((uint32_t *) addr_elems);
+
+
+ ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
+ sizeof (struct sockaddr_in));
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ /* If a timeout was specified, select on the file descriptor with
+ the timeout. */
+ if (timeout > 0 && ret == -1)
+ {
+ /* Reset the non-blocking flag, if needed. */
+ if (!(origflags & O_NONBLOCK))
+ {
+ if (fcntl (fd, F_SETFL, origflags) == -1)
+ {
+ /* oops */
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ }
+ if (EINPROGRESS == errno)
+ {
+ fd_set wrfds;
+ FD_SET(fd, &wrfds);
+ ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
+ if (ret == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ if (ret == 0) /* connect timed out */
+ {
+ JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
+ "connect timed out");
+ return JNI_FALSE;
+ }
+ return JNI_TRUE; /* Connected! */
+ }
+ else if (ECONNREFUSED == errno)
+ {
+ JCL_ThrowException (env, "java/net/ConnectException",
+ strerror (errno));
+ return JNI_FALSE;
+ }
+ else
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ }
+
+ if (ret == -1)
+ {
+ if (EINPROGRESS == errno)
+ return JNI_FALSE;
+ else if (ECONNREFUSED == errno)
+ {
+ JCL_ThrowException (env, "java/net/ConnectException",
+ strerror (errno));
+ return JNI_FALSE;
+ }
+ else
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ }
+
+ return JNI_TRUE;
+#else
+ (void) fd;
+ (void) addr;
+ (void) port;
+ (void) timeout;
+ JCL_ThrowException (env, IO_EXCEPTION, "connect not supported");
+ return JNI_FALSE;
+#endif /* HAVE_CONNECT */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: connect6
+ * Signature: (I[BI)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_nio_VMChannel_connect6 (JNIEnv *env, jclass clazz __attribute__((unused)),
+ jint fd, jbyteArray addr, jint port, int timeout)
+{
+#if defined(HAVE_CONNECT) && defined(HAVE_INET6)
+ struct sockaddr_in6 sockaddr;
+ struct timeval timeo;
+ int flags, origflags = 0;
+ jbyte *addr_elems;
+ int ret;
+
+ if (timeout > 0)
+ {
+ timeo.tv_sec = timeout / 1000;
+ timeo.tv_usec = (timeout % 1000) * 1000;
+ origflags = fcntl (fd, F_GETFL, 0);
+ if (origflags == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ /* Set nonblocking mode, if not already set. */
+ if (!(origflags & O_NONBLOCK))
+ {
+ flags = origflags | O_NONBLOCK;
+ if (fcntl (fd, F_SETFL, flags) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ }
+ }
+
+ addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
+
+ memset (&sockaddr, 0, sizeof (struct sockaddr_in6));
+ sockaddr.sin6_family = AF_INET6;
+ sockaddr.sin6_port = htons (port);
+ memcpy (&sockaddr.sin6_addr.s6_addr, addr_elems, 16);
+
+ ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
+ sizeof (struct sockaddr_in6));
+
+ (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
+
+ /* If a timeout was specified, select on the file descriptor with
+ the timeout. */
+ if (timeout > 0 && ret == -1)
+ {
+ /* Reset the non-blocking flag, if needed. */
+ if (!(origflags & O_NONBLOCK))
+ {
+ if (fcntl (fd, F_SETFL, origflags) == -1)
+ {
+ /* oops */
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ }
+ if (EINPROGRESS == errno)
+ {
+ fd_set wrfds;
+ FD_SET(fd, &wrfds);
+ ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
+ if (ret == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ if (ret == 0) /* connect timed out */
+ {
+ JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
+ "connect timed out");
+ return JNI_FALSE;
+ }
+ return JNI_TRUE; /* Connected! */
+ }
+ else if (ECONNREFUSED == errno)
+ {
+ JCL_ThrowException (env, "java/net/ConnectException",
+ strerror (errno));
+ return JNI_FALSE;
+ }
+ else
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ }
+
+ if (ret == -1)
+ {
+ if (EAGAIN == errno)
+ return JNI_FALSE;
+ else if (ECONNREFUSED == errno)
+ {
+ JCL_ThrowException (env, "java/net/ConnectException",
+ strerror (errno));
+ return JNI_FALSE;
+ }
+ else
+ {
+ JCL_ThrowException (env, "java/io/IOException", strerror (errno));
+ return JNI_FALSE;
+ }
+ }
+
+ return JNI_TRUE;
+#else
+ (void) fd;
+ (void) addr;
+ (void) port;
+ (void) timeout;
+ JCL_ThrowException (env, IO_EXCEPTION, "IPv6 connect not supported");
+ return JNI_FALSE;
+#endif /* HAVE_CONNECT && HAVE_INET6 */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: getsockname
+ * Signature: (ILjava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_getsockname (JNIEnv *env, jclass clazz __attribute__((unused)),
+ jint fd, jobject name)
+{
+#ifdef HAVE_GETSOCKNAME
+#ifdef HAVE_INET6
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in6 sock_storage;
+ socklen_t socklen = sizeof (struct sockaddr_in6);
+#else
+ struct sockaddr_in sock_storage;
+ socklen_t socklen = sizeof (struct sockaddr_in);
+#endif /* HAVE_INET6 */
+
+ struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
+ struct sockaddr_in *addr4;
+ int ret;
+ char *nameptr = (*env)->GetDirectBufferAddress (env, name);
+
+ ret = getsockname (fd, sockaddr, &socklen);
+ if (ret == -1)
+ {
+ JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
+ return 0;
+ }
+
+ if (sockaddr->sa_family == AF_INET)
+ {
+ addr4 = (struct sockaddr_in *) sockaddr;
+ memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
+ memcpy (nameptr + 4, &(addr4->sin_port), 2);
+ return 4;
+ }
+
+#ifdef HAVE_INET6
+ /* IPv6 */
+ if (sockaddr->sa_family == AF_INET6)
+ {
+ addr6 = (struct sockaddr_in6 *) sockaddr;
+ memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
+ memcpy (nameptr, &(addr6->sin6_port), 2);
+ return 16;
+ }
+#endif /* HAVE_INET6 */
+ JCL_ThrowException (env, IO_EXCEPTION, "unsupported address format");
+ return -1;
+#else
+ (void) fd;
+ (void) name;
+ JCL_ThrowException (env, IO_EXCEPTION, "getsockname not supported");
+ return -1;
+#endif /* HAVE_GETSOCKNAME */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: getpeername
+ * Signature: (ILjava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_getpeername (JNIEnv *env, jclass clazz __attribute__((unused)),
+ jint fd, jobject name)
+{
+#ifdef HAVE_GETPEERNAME
+#ifdef HAVE_INET6
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in6 sock_storage;
+ socklen_t socklen = sizeof (struct sockaddr_in6);
+#else
+ struct sockaddr_in sock_storage;
+ socklen_t socklen = sizeof (struct sockaddr_in);
+#endif /* HAVE_INET6 */
+
+ struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
+ struct sockaddr_in *addr4;
+ int ret;
+ char *nameptr = (*env)->GetDirectBufferAddress (env, name);
+
+ ret = getpeername (fd, sockaddr, &socklen);
+ if (ret == -1)
+ {
+ if (ENOTCONN != errno)
+ JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
+ return 0;
+ }
+
+ if (sockaddr->sa_family == AF_INET)
+ {
+ addr4 = (struct sockaddr_in *) sockaddr;
+ memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
+ memcpy (nameptr + 4, &(addr4->sin_port), 2);
+ return 4;
+ }
+#ifdef HAVE_INET6
+ else if (sockaddr->sa_family == AF_INET6)
+ {
+ addr6 = (struct sockaddr_in6 *) sockaddr;
+ memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
+ memcpy (nameptr, &(addr6->sin6_port), 2);
+ return 16;
+ }
+#endif /* HAVE_INET6 */
+
+ JCL_ThrowException (env, "java/net/SocketException",
+ "unsupported address type");
+ return -1;
+#else
+ (void) fd;
+ (void) name;
+ JCL_ThrowException (env, IO_EXCEPTION, "getpeername not supported");
+ return -1;
+#endif /* HAVE_GETPEERNAME */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: accept
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_accept (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jint fd)
+{
+#ifdef HAVE_ACCEPT
+ int ret;
+
+#ifdef HAVE_INET6
+ struct sockaddr_in6 addr;
+ socklen_t alen = sizeof (struct sockaddr_in6);
+#else
+ struct sockaddr_in addr;
+ socklen_t alen = sizeof (struct sockaddr_in);
+#endif /* HAVE_INET6 */
+
+ do
+ {
+ ret = cpnio_accept (fd, (struct sockaddr *) &addr, &alen);
+ }
+ while (ret == -1 && EINTR == errno);
+
+ if (ret == -1)
+ {
+ if (EWOULDBLOCK != ret && EAGAIN != ret)
+ JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
+ }
+
+ return ret;
+#else
+ (void) fd;
+ JCL_ThrowException (env, IO_EXCEPTION, "accept not supported");
+ return -1;
+#endif /* HAVE_ACCEPT */
+}
+
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: disconnect
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_VMChannel_disconnect (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd)
+{
+ struct sockaddr sockaddr;
+
+ sockaddr.sa_family = AF_UNSPEC;
+ if (connect (fd, &sockaddr, sizeof (struct sockaddr)) == -1)
+ {
+ /* The expected error for a successful disconnect is EAFNOSUPPORT. */
+ if (errno != EAFNOSUPPORT)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ }
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: close
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_VMChannel_close (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd)
+{
+ if (close (fd) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: available
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_available (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd)
+{
+ jint avail = 0;
+
+/* NIODBG("fd: %d", fd); */
+ if (ioctl (fd, FIONREAD, &avail) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+/* NIODBG("avail: %d", avail); */
+
+ return avail;
+}
+
+
+enum FileChannel_mode {
+ CPNIO_READ = 1,
+ CPNIO_WRITE = 2,
+ CPNIO_APPEND = 4,
+ CPNIO_EXCL = 8,
+ CPNIO_SYNC = 16,
+ CPNIO_DSYNC = 32
+};
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: open
+ * Signature: (Ljava/lang/String;I)I
+ */
+JNIEXPORT jint JNICALL
+Java_gnu_java_nio_VMChannel_open (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jstring path, jint mode)
+{
+ int nmode = 0;
+ int ret;
+ const char *npath;
+ mode_t mask = umask (0);
+ umask (mask);
+
+ if ((mode & CPNIO_READ) && (mode & CPNIO_WRITE))
+ nmode = O_RDWR;
+ else if (mode & CPNIO_WRITE)
+ nmode = O_WRONLY;
+ else
+ nmode = O_RDONLY;
+
+ nmode = (nmode
+ | ((nmode == O_RDWR || nmode == O_WRONLY) ? O_CREAT : 0)
+ | ((mode & CPNIO_APPEND) ? O_APPEND :
+ ((nmode == O_RDWR || nmode == O_WRONLY) ? O_TRUNC : 0))
+ | ((mode & CPNIO_EXCL) ? O_EXCL : 0)
+ | ((mode & CPNIO_SYNC) ? O_SYNC : 0));
+
+ npath = JCL_jstring_to_cstring (env, path);
+
+/* NIODBG("path: %s; mode: %x", npath, nmode); */
+
+ ret = open (npath, nmode, 0777 & ~mask);
+
+/* NIODBG("ret: %d\n", ret); */
+
+ JCL_free_cstring (env, path, npath);
+
+ if (-1 == ret)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+
+ return ret;
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: position
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+Java_gnu_java_nio_VMChannel_position (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd)
+{
+#ifdef HAVE_LSEEK
+ off_t ret;
+
+ ret = lseek (fd, 0, SEEK_CUR);
+
+ if (-1 == ret)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+
+ return (jlong) ret;
+#else
+ JCL_ThrowException (env, IO_EXCEPTION, "position not supported");
+ return -1;
+#endif /* HAVE_LSEEK */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: seek
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_VMChannel_seek (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jlong pos)
+{
+#ifdef HAVE_LSEEK
+ if (lseek (fd, (off_t) pos, SEEK_SET) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+#else
+ JCL_ThrowException (env, IO_EXCEPTION, "seek not supported");
+#endif /* HAVE_LSEEK */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: truncate
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_VMChannel_truncate (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jlong len)
+{
+#if defined(HAVE_FTRUNCATE) && defined(HAVE_LSEEK)
+ off_t pos = lseek (fd, 0, SEEK_CUR);
+ if (pos == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return;
+ }
+ if (ftruncate (fd, (off_t) len) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return;
+ }
+ if (pos > len)
+ {
+ if (lseek (fd, len, SEEK_SET) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ }
+#else
+ JCL_ThrowException (env, IO_EXCEPTION, "truncate not supported");
+#endif /* HAVE_FTRUNCATE && HAVE_LSEEK */
+}
+
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: lock
+ * Signature: (IJJZZ)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_nio_VMChannel_lock (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jlong pos, jlong len,
+ jboolean shared, jboolean wait)
+{
+#if HAVE_FCNTL
+ struct flock fl;
+
+ fl.l_start = (off_t) pos;
+ fl.l_len = (off_t) len;
+ fl.l_pid = getpid ();
+ fl.l_type = (shared ? F_RDLCK : F_WRLCK);
+ fl.l_whence = SEEK_SET;
+
+ if (cpnio_fcntl (fd, (wait ? F_SETLKW : F_SETLK), (long) &fl) == -1)
+ {
+ if (errno != EAGAIN)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+#else
+ JCL_ThrowException (env, IO_EXCEPTION, "lock not supported");
+ return JNI_FALSE;
+#endif /* HAVE_FCNTL */
+}
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: unlock
+ * Signature: (IJJ)V
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_nio_VMChannel_unlock (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jlong pos, jlong len)
+{
+#if HAVE_FCNTL
+ struct flock fl;
+
+ fl.l_start = (off_t) pos;
+ fl.l_len = (off_t) len;
+ fl.l_pid = getpid ();
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+
+ if (cpnio_fcntl (fd, F_SETLK, (long) &fl) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ }
+#else
+ JCL_ThrowException (env, IO_EXCEPTION, "unlock not supported");
+#endif /* HAVE_FCNTL */
+}
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: size
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+Java_gnu_java_nio_VMChannel_size (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd)
+{
+#ifdef HAVE_FSTAT
+ struct stat st;
+
+ if (fstat (fd, &st) == -1)
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+
+ return (jlong) st.st_size;
+#else
+ JCL_ThrowException (env, IO_EXCEPTION, "size not supported");
+ return 0;
+#endif
+}
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: map
+ * Signature: (ICJI)Lgnu/classpath/Pointer;
+ */
+JNIEXPORT jobject JNICALL
+Java_gnu_java_nio_VMChannel_map (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jint fd, jchar mode, jlong position, jint size)
+{
+#ifdef HAVE_MMAP
+ jclass MappedByteBufferImpl_class;
+ jmethodID MappedByteBufferImpl_init = NULL;
+ jobject Pointer_instance;
+ volatile jobject buffer;
+ long pagesize;
+ int prot, flags;
+ void *p;
+ void *address;
+
+/* NIODBG("fd: %d; mode: %x; position: %lld; size: %d", */
+/* fd, mode, position, size); */
+
+ /* FIXME: should we just assume we're on an OS modern enough to
+ have 'sysconf'? And not check for 'getpagesize'? */
+#if defined(HAVE_GETPAGESIZE)
+ pagesize = getpagesize ();
+#elif defined(HAVE_SYSCONF)
+ pagesize = sysconf (_SC_PAGESIZE);
+#else
+ JCL_ThrowException (env, IO_EXCEPTION,
+ "can't determine memory page size");
+ return NULL;
+#endif /* HAVE_GETPAGESIZE/HAVE_SYSCONF */
+
+ if ((*env)->ExceptionOccurred (env))
+ {
+ return NULL;
+ }
+
+ prot = PROT_READ;
+ if (mode == '+' || mode == 'c')
+ {
+ /* When writing we need to make sure the file is big enough,
+ otherwise the result of mmap is undefined. */
+ struct stat st;
+ if (fstat (fd, &st) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return NULL;
+ }
+ if (position + size > st.st_size)
+ {
+ if (ftruncate(fd, position + size) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return NULL;
+ }
+ }
+ prot |= PROT_WRITE;
+ }
+
+ flags = (mode == 'c' ? MAP_PRIVATE : MAP_SHARED);
+ p = mmap (NULL, (size_t) ALIGN_UP (size, pagesize), prot, flags,
+ fd, ALIGN_DOWN (position, pagesize));
+ if (p == MAP_FAILED)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return NULL;
+ }
+
+ /* Unalign the mapped value back up, since we aligned offset
+ down to a multiple of the page size. */
+ address = (void *) ((char *) p + (position % pagesize));
+
+ Pointer_instance = JCL_NewRawDataObject(env, address);
+
+ MappedByteBufferImpl_class = (*env)->FindClass (env,
+ "java/nio/MappedByteBufferImpl");
+ if (MappedByteBufferImpl_class != NULL)
+ {
+ MappedByteBufferImpl_init =
+ (*env)->GetMethodID (env, MappedByteBufferImpl_class,
+ "<init>", "(Lgnu/classpath/Pointer;IZ)V");
+ }
+
+ if ((*env)->ExceptionOccurred (env))
+ {
+ munmap (p, ALIGN_UP (size, pagesize));
+ return NULL;
+ }
+ if (MappedByteBufferImpl_init == NULL)
+ {
+ JCL_ThrowException (env, "java/lang/InternalError",
+ "could not get MappedByteBufferImpl constructor");
+ munmap (p, ALIGN_UP (size, pagesize));
+ return NULL;
+ }
+
+ buffer = (*env)->NewObject (env, MappedByteBufferImpl_class,
+ MappedByteBufferImpl_init, Pointer_instance,
+ (jint) size, mode == 'r');
+ return buffer;
+#else
+ (void) fd;
+ (void) mode;
+ (void) position;
+ (void) size;
+ JCL_ThrowException (env, IO_EXCEPTION,
+ "memory-mapped files not implemented");
+ return 0;
+#endif /* HAVE_MMAP */
+}
+
+/*
+ * Class: gnu_java_nio_VMChannel
+ * Method: flush
+ * Signature: (IZ)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_nio_VMChannel_flush (JNIEnv *env,
+ jclass c __attribute__((unused)),
+ jint fd, jboolean metadata __attribute__((unused)))
+{
+#ifdef HAVE_FSYNC
+ /* XXX blocking? */
+ if (fsync (fd) == -1)
+ {
+ JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+#else
+ JCL_ThrowException (env, IO_EXCEPTION, "flush not implemented");
+ return JNI_TRUE;
+#endif /* HAVE_FSYNC */
+}
#ifdef __cplusplus
diff --git a/native/jni/java-nio/gnu_java_nio_VMPipe.c b/native/jni/java-nio/gnu_java_nio_VMPipe.c
index 369c5a3d6..cbaaa0834 100644
--- a/native/jni/java-nio/gnu_java_nio_VMPipe.c
+++ b/native/jni/java-nio/gnu_java_nio_VMPipe.c
@@ -35,8 +35,14 @@ this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
+
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
#include <errno.h>
+#include <string.h>
+#include <unistd.h>
#include <jni.h>
#include <jcl.h>
@@ -45,12 +51,33 @@ exception statement from your version. */
#define IO_EXCEPTION "java/io/IOException"
-JNIEXPORT void JNICALL
-Java_gnu_java_nio_VMPipe_init (JNIEnv * env,
- jclass cls __attribute__ ((__unused__)),
- jobject self __attribute__ ((__unused__)),
- jobject provider __attribute__ ((__unused__)))
+/*
+ * Class: gnu_java_nio_VMPipe
+ * Method: pipe0
+ * Signature: ()[I
+ */
+JNIEXPORT jintArray JNICALL
+Java_gnu_java_nio_VMPipe_pipe0 (JNIEnv *env,
+ jclass c __attribute__((unused)))
{
- JCL_ThrowException (env, IO_EXCEPTION,
- "gnu.java.nio.VMPipe.init(): not implemented");
+ int fd[2];
+ jintArray array;
+ jint* elem;
+ int ret;
+
+ /* FIXME: autoconf this? */
+ ret = pipe (fd);
+
+ if (ret == -1)
+ {
+ JCL_ThrowException (env, "java/io/IOException", strerror (errno));
+ return NULL;
+ }
+
+ array = (*env)->NewIntArray (env, 2);
+ elem = (*env)->GetIntArrayElements (env, array, NULL);
+ elem[0] = fd[0];
+ elem[1] = fd[1];
+ (*env)->ReleaseIntArrayElements (env, array, elem, 0);
+ return array;
}
diff --git a/native/jni/java-nio/java_nio_MappedByteBufferImpl.c b/native/jni/java-nio/java_nio_MappedByteBufferImpl.c
index b49091982..2a87d2950 100644
--- a/native/jni/java-nio/java_nio_MappedByteBufferImpl.c
+++ b/native/jni/java-nio/java_nio_MappedByteBufferImpl.c
@@ -1,5 +1,5 @@
/* java_nio_MappedByteBufferImpl.c - Native methods for MappedByteBufferImpl
- Copyright (C) 2004,2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -43,7 +43,6 @@ exception statement from your version. */
#include "java_nio_MappedByteBufferImpl.h"
-#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
diff --git a/native/jni/java-nio/javanio.c b/native/jni/java-nio/javanio.c
new file mode 100644
index 000000000..d9e4d4f1d
--- /dev/null
+++ b/native/jni/java-nio/javanio.c
@@ -0,0 +1,122 @@
+/* javanio.c -- implementations of functions in javanio.h.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+/*
+ * Note, because these functions are trivial, and should be inlined,
+ * we include this file in the header, and do not compile it.
+ */
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+CPNIO_EXPORT ssize_t
+cpnio_read (int fd, void *buf, size_t nbytes)
+{
+ return read (fd, buf, nbytes);
+}
+
+CPNIO_EXPORT ssize_t
+cpnio_readv (int fd, const struct iovec *iov, int iovcnt)
+{
+ return readv (fd, iov, iovcnt);
+}
+
+CPNIO_EXPORT ssize_t
+cpnio_write (int fd, const void *buf, size_t nbytes)
+{
+ return write (fd, buf, nbytes);
+}
+
+CPNIO_EXPORT ssize_t
+cpnio_writev (int fd, const struct iovec *iov, size_t iovcnt)
+{
+ return writev (fd, iov, iovcnt);
+}
+
+CPNIO_EXPORT int
+cpnio_socket (int domain, int type, int protocol)
+{
+ return socket (domain, type, protocol);
+}
+
+CPNIO_EXPORT int
+cpnio_connect (int fd, const struct sockaddr *addr, socklen_t addrlen)
+{
+ return connect (fd, addr, addrlen);
+}
+
+CPNIO_EXPORT int
+cpnio_accept (int fd, struct sockaddr *addr, socklen_t *addrlen)
+{
+ return accept (fd, addr, addrlen);
+}
+
+CPNIO_EXPORT ssize_t
+cpnio_sendto (int fd, const void *msg, size_t len, int flags,
+ const struct sockaddr *to, socklen_t tolen)
+{
+ return sendto (fd, msg, len, flags, to, tolen);
+}
+
+CPNIO_EXPORT ssize_t
+cpnio_recvfrom (int fd, void *buf, size_t len, int flags,
+ struct sockaddr *from, socklen_t *fromlen)
+{
+ return recvfrom (fd, buf, len, flags, from, fromlen);
+}
+
+CPNIO_EXPORT int
+cpnio_fcntl (int fd, int cmd, long arg)
+{
+#ifdef HAVE_FCNTL
+ return fcntl (fd, cmd, arg);
+#else
+ errno = ENOSUP;
+ return -1;
+#endif /* HAVE_FCNTL */
+}
+
+CPNIO_EXPORT int
+cpnio_select (int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *excepfds, struct timeval *timeo)
+{
+ return select (nfds, readfds, writefds, excepfds, timeo);
+}
diff --git a/native/jni/java-nio/javanio.h b/native/jni/java-nio/javanio.h
new file mode 100644
index 000000000..bdd11055e
--- /dev/null
+++ b/native/jni/java-nio/javanio.h
@@ -0,0 +1,332 @@
+/* javanio.h -- reference implementation of native functions.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+#ifndef __JAVANIO_H__
+#define __JAVANIO_H__
+
+/**
+ * This header defines functions that are called by our JNI reference
+ * implementation of java.nio.*. In our reference implementation, these
+ * functions map exactly to their counterparts in POSIX; in implementations
+ * that can't use these functions directly (such as systems that use user-land
+ * threads, and thus can't call blocking system calls directly) can provide
+ * their own implementations suitable for their system.
+ */
+
+/**
+ * This macro is used in all function prototypes below; if any additional
+ * keywords need to be added to a prototype, declare them in this macro.
+ */
+#define CPNIO_EXPORT static inline
+
+/**
+ * Read bytes from the given file descriptor into the given memory address, which
+ * has sufficient space for NBYTES bytes.
+ *
+ * \param fd The file descriptor to read from.
+ * \param buf The memory address to read bytes into.
+ * \param nbytes The number of bytes available to store in BUF.
+ * \return The number of bytes read, possibly zero, on success; return -1 on failure,
+ * and set ERRNO to an appropriate value.
+ * \see read(2)
+ *
+ * Allowed errno values:
+ * [EBADF] If FD is not a valid file descriptor, or is not open for reading.
+ * [EFAULT] If BUF points outside the process's address space.
+ * [EIO] An I/O error occurrs.
+ * [EINTR] If the read is interrupted by a signal.
+ * [EINVAL] If FD is negative.
+ * [EAGAIN] If FD was marked for non-blocking I/O, and no data were ready to
+ * be read.
+ */
+CPNIO_EXPORT ssize_t cpnio_read (int fd, void *buf, size_t nbytes);
+
+/*
+ * Read bytes from a file descriptor into a sequence of IO buffers.
+ *
+ * The iovec structure is defined as:
+ *
+ * struct iovec {
+ * char *iov_base;
+ * size_t iov_len;
+ * };
+ *
+ * The call to _cp_readv should do a scattering read, where for each struct iovec
+ * in the supplied list, up to IOV_LEN bytes are read into IOV_BASE. The function
+ * returns the total number of bytes read into all supplied buffers.
+ *
+ * \param fd The file descriptor.
+ * \param iov A pointer to the head of a list of iovec structures.
+ * \param iovcnt The number of iovec structures pointed to by IOV.
+ * \return The total number of bytes read accross all buffers, possibly zero. On
+ * error, -1 is returned and ERRNO is set.
+ * \see readv(2)
+ *
+ * Allowed ERRNO values include all of those listed for _cp_read, as well as the
+ * following:
+ * [EINVAL] If IOVCNT overflows the maximum number of iovec structures
+ * this platform supports (usually 16), if any IOV_LEN value
+ * is negative, or if the sum of all IOV_LEN values is too
+ * large to be stored in a ssize_t (usually a 32-bit integer).
+ * [EFAULT] If part of IOV points outside the process's address space.
+ */
+CPNIO_EXPORT ssize_t cpnio_readv (int fd, const struct iovec *iov, int iovcnt);
+
+/*
+ * Write NBYTES bytes from BUF to the file descriptor FD, returning the number
+ * of bytes successfully written.
+ *
+ * \param fd The file descriptor.
+ * \param buf A pointer to the bytes to write.
+ * \param nbytes The maximum number of bytes to write.
+ * \return The number of bytes written to the file descriptor, possibly zero. -1
+ * is returned if an error is encountered, and ERRNO will be set.
+ * \see write(2)
+ *
+ * Allowed ERRNO values:
+ * [EBADF] If FD is not a valid file descriptor or is not open for writing.
+ * [EPIPE] If FD is a pipe, when the other side is disconnected; if FD is a
+ * socket, when the peer is not connected.
+ * [EFBIG] When FD is a file, and writing to it overflows the process's
+ * or the system's maximim file size.
+ * [EFAULT] If the buffer to write points outside the process's address
+ * space.
+ * [EINVAL] If the descriptor FD is negative.
+ * [ENOSPC] If FD is a file, and there is insufficient space on the
+ * filesystem.
+ * [EDQUOT] If FD is a file, and the user's disk quota has been exceeded.
+ * [EIO] If an I/O error occurs.
+ * [EINTR] If the call is interrupted by a signal.
+ * [EAGAIN] If FD is in non-blocking mode, and no bytes could be immediately
+ * written.
+ */
+CPNIO_EXPORT ssize_t cpnio_write (int fd, const void *buf, size_t nbytes);
+
+/*
+ * Write data from a sequence of IOVCNT buffers IOV to a file descriptor FD.
+ *
+ * \param fd The file descriptor.
+ * \param iov The list of buffers to write.
+ * \param iovcnt The number of iovec structures pointed to by IOV.
+ * \return The total number of bytes written from the given buffers, possibly
+ * zero. -1 if an error occurs, and ERRNO will be set.
+ * \see writev(2)
+ *
+ * Allowed ERRNO values include those mentioned in _cp_write, as well as:
+ * [EDESTADDRREQ] If the descriptor is a datagram socket, and the peer is
+ * no longer available.
+ * [EINVAL] If IOVCNT is out of range, if any IOV_LEN value is
+ * negative, or if the sum of all IOVCNT IOV_LEN values
+ * will overflow a ssize_t.
+ * [ENOBUFS] If the mbuf pool is exhausted (???).
+ */
+CPNIO_EXPORT ssize_t cpnio_writev (int fd, const struct iovec *iov, size_t iovcnt);
+
+/**
+ * Open a new, unbound and unconnected socket.
+ *
+ * \param domain The socket domain. Implementations need only handle AF_INET.
+ * \param type The socket type; implementations need only handle types
+ * SOCK_STREAM (for streaming sockets) and SOCK_DGRAM (for datagram sockets).
+ * \param protocol This should always be 0. It can be ignored.
+ * \return A new file descriptor pointing to a newly created socket, or -1 on
+ * error, and ERRNO set.
+ *
+ * Allowed ERRNO values:
+ * [EPROTONOSUPPORT] If TYPE is unrecognized.
+ * [EMFILE] If a new file descriptor cannot be allocated, because
+ * the process's descriptor table is full.
+ * [ENFILE] Likewise, but when the system table is full.
+ * [EACCES] If this operation is not allowed.
+ * [ENOBUFS] If there is not enough buffer space available for the
+ * new socket.
+ */
+CPNIO_EXPORT int cpnio_socket (int domain, int type, int protocol);
+
+/**
+ * Connect a socket to a remote address.
+ *
+ * \param fd The file descriptor of the socket to connect.
+ * \param addr The address to connect to. In practice, this should be
+ * either a `struct sockaddr_in' or a `struct sockaddr_in6'.
+ * \param addrlen The size of the address structure passed by ADDR.
+ * \return Zero if the connect succeeds. -1 on error, and ERRNO should be set.
+ *
+ * Allowed ERRNO values:
+ * [EBADF] If FD is not a valid file descriptor.
+ * [ENOTSOCK] If FD is not a socket descriptor.
+ * [EADDRNOTAVAIL] If ADDR is not available for use to this process.
+ * [EAFNOSUPPORT] If the address family of ADDR is not supported.
+ * [EISCONN] If the socket is already connected.
+ * [ETIMEDOUT] If the connection could not be made in a reasonable
+ * amount of time.
+ * [ECONNREFUSED] If the connection attempt was rejected.
+ * [ENETUNREACH] If the network ADDR is on is unreachable.
+ * [EADDRINUSE] If the address is already in use.
+ * [EFAULT] If ADDR points outside the addressable space.
+ * [EINPROGRESS] If FD is in non-blocking mode, and the connection could
+ * not be completed immediately.
+ * [EALREADY] If FD is in non-blocking mode, and a connection attempt
+ * is still pending.
+ * [EACCESS] If ADDR is the broadcast address, and the socket option
+ * SO_BROADCAST is not set.
+ */
+CPNIO_EXPORT int cpnio_connect (int fd, const struct sockaddr *addr, socklen_t addrlen);
+
+/**
+ * Accept an incoming connection on a socket, returning a new socket for
+ * the connection, and storing the peer address in ADDR.
+ *
+ * \param fd The socket file descriptor.
+ * \param addr The structure to store the peer address in.
+ * \param addrlen The size of the data available in ADDR; upon return, the
+ * number of bytes stored in ADDR will be placed here.
+ * \return The new socket file descriptor, or -1 on error, and ERRNO set.
+ *
+ * Allowed ERRNO values:
+ * [EBADF] If FD is not a valid file descriptor.
+ * [ENOTSOCK] If FD in not a socket descriptor.
+ * [EOPNOTSUPP] If the socket is not a SOCK_STREAM socket.
+ * [EFAULT] If ADDR points outside the process's addressable space.
+ * [EWOULDBLOCK] If the socket is in non-blocking mode, and no connection
+ * attempt is currently ready.
+ * [EMFILE] If the process's descriptor table is full.
+ * [ENFILE] If the system's descriptor table is full.
+ */
+CPNIO_EXPORT int cpnio_accept (int fd, struct sockaddr *addr, socklen_t *addrlen);
+
+/**
+ * Send a datagram to the given address.
+ *
+ * \param fd The socket file descriptor.
+ * \param msg A pointer to the message to send.
+ * \param len The size of the message to send.
+ * \param flags Flags for sending.
+ * \param to The remote address to send the message to.
+ * \param tolen The size of the TO address structure.
+ * \return The number of bytes written, possibly zero, on success. Returns
+ * -1 on failure, and sets ERRNO.
+ * \see sendto(2)
+ *
+ * Allowed ERRNO values:
+ * [EBADF]
+ * [ENOTSOCK]
+ * [EFAULT]
+ * [EMSGSIZE]
+ * [EAGAIN]
+ * [ENOBUFS]
+ * [EACCES]
+ * [EHOSTUNREACH]
+ */
+CPNIO_EXPORT ssize_t cpnio_sendto (int fd, const void *msg, size_t len, int flags,
+ const struct sockaddr *to, socklen_t tolen);
+
+/**
+ * Receive a message on a socket, storing the remote host's address in
+ * FROM.
+ *
+ * \param fd The socket file descriptor.
+ * \param buf The buffer to store received bytes in.
+ * \param flags Flags to control the receive.
+ * \param from Where to store the remote address.
+ * \param fromlen Pointer to the size of FROM; on return, it will contain the
+ * size of the structure placed in FROM.
+ * \return The number of bytes received on success. -1 on error, and ERRNO will
+ * be set.
+ * \see recvfrom(2)
+ *
+ * Allewed ERRNO values:
+ * [EBADF] FD is not a valid file descriptor.
+ * [ENOTCONN] If the socket is stream-oriented, and no prior call to
+ * connect(2) was made.
+ * [ENOTSOCK] FD is not a socket.
+ * [EAGAIN] FD is in non-blocking mode, and no message was
+ * immediately available.
+ * [EINTR] The system call was interrupted by a signal.
+ * [EFAULT] BUF, FROM, or FROMLEN lie outside the process's address
+ * space.
+ */
+CPNIO_EXPORT ssize_t cpnio_recvfrom (int fd, void *buf, size_t len, int flags,
+ struct sockaddr *from, socklen_t *fromlen);
+
+
+/**
+ * Control file descriptor properties.
+ *
+ * \param fd The file descriptor to control.
+ * \param cmd The command to execute.
+ * \param arg The command argument.
+ * \return A value other than -1, specific to CMD. On error, -1 is
+ * returned, and ERRNO is set.
+ *
+ * Allowed ERRNO values:
+ * FIXME
+ */
+CPNIO_EXPORT int cpnio_fcntl (int fd, int cmd, long arg);
+
+
+/**
+ * Select from one of the given file descriptor sets a descriptor that
+ * is ready for the given operation (read, write, etc.).
+ *
+ * \param nfds A value one larger than the largest file
+ * descriptor.
+ * \param readfds A set of file descriptors to select for
+ * readability.
+ * \param writefds A set of file descriptors to select for
+ * writability.
+ * \param exceptfds A set of file descriptors to select for
+ * exceptional conditions.
+ * \param tm The selection timeout.
+ * \return The number of file descriptors selected, possibly zero, or
+ * -1 on error (and with ERRNO set).
+ */
+CPNIO_EXPORT int cpnio_select (int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *tm);
+
+/*
+ * We include the implementation file here, because our reference
+ * implementation is trivial, and the functions are declared extern
+ * inline.
+ *
+ * Implementations that need different implementations of these functions
+ * SHOULD remove this line, and compile javanio.c as a separate unit.
+ */
+#include "javanio.c"
+
+#endif /* __JAVANIO_H__ */
diff --git a/native/jni/native-lib/cpio.c b/native/jni/native-lib/cpio.c
index eb544dc83..4d23b7a1f 100644
--- a/native/jni/native-lib/cpio.c
+++ b/native/jni/native-lib/cpio.c
@@ -448,14 +448,28 @@ int cpio_closeDir (void *handle)
}
-int cpio_readDir (void *handle, const char **filename)
+int cpio_readDir (void *handle, char *filename)
{
+#ifdef HAVE_READDIR_R
+ struct dirent dent;
+#endif /* HAVE_READDIR_R */
struct dirent *dBuf;
+#ifdef HAVE_READDIR_R
+ readdir_r ((DIR *) handle, &dent, &dBuf);
+#else
dBuf = readdir((DIR *)handle);
+#endif /* HAVE_READDIR_R */
+
if (dBuf == NULL)
- return errno;
+ {
+ /* Some OS's (OS X) return NULL on end-of-dir, but
+ don't set errno to anything. */
+ if (errno == 0)
+ return ENOENT; /* Whatever. */
+ return errno;
+ }
- *filename = dBuf->d_name;
+ strncpy (filename, dBuf->d_name, FILENAME_MAX);
return 0;
}
diff --git a/native/jni/native-lib/cpio.h b/native/jni/native-lib/cpio.h
index 1776b199d..97483d294 100644
--- a/native/jni/native-lib/cpio.h
+++ b/native/jni/native-lib/cpio.h
@@ -79,6 +79,6 @@ JNIEXPORT int cpio_rename (const char *old_name, const char *new_name);
JNIEXPORT int cpio_openDir (const char *dirname, void **handle);
JNIEXPORT int cpio_closeDir (void *handle);
-JNIEXPORT int cpio_readDir (void *handle, const char **filename);
+JNIEXPORT int cpio_readDir (void *handle, char *filename);
#endif
diff --git a/native/jni/native-lib/cpnet.c b/native/jni/native-lib/cpnet.c
index c112ac2a7..85c4640e1 100644
--- a/native/jni/native-lib/cpnet.c
+++ b/native/jni/native-lib/cpnet.c
@@ -49,6 +49,7 @@ exception statement from your version. */
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h>
+#include <arpa/inet.h>
#include "cpnet.h"
@@ -597,8 +598,8 @@ jint cpnet_getHostByName (JNIEnv *env, const char *hostname, cpnet_address ***ad
struct hostent hret;
struct hostent *result;
jint buflen = 1024;
- int herr;
- int ret;
+ int herr = 0;
+ int ret = 0;
int counter = 0;
cpnet_address **addr_arr;
int i;
@@ -610,7 +611,13 @@ jint cpnet_getHostByName (JNIEnv *env, const char *hostname, cpnet_address ***ad
#ifdef HAVE_GETHOSTBYNAME_R
ret = gethostbyname_r (hostname, &hret, buf, buflen, &result, &herr);
#else
- ret = gethostbyname (hostname);
+ hret.h_addr_list = NULL;
+ hret.h_addrtype = 0;
+
+ result = gethostbyname (hostname);
+ if (result == NULL)
+ return -errno;
+ memcpy (&hret, result, sizeof (struct hostent));
#endif
if (ret != 0 || result == NULL)
{
@@ -709,6 +716,49 @@ jint cpnet_getHostByAddr (JNIEnv *env UNUSED, cpnet_address *addr, char *hostnam
return 0;
}
+jint cpnet_aton (JNIEnv *env, const char *hostname, cpnet_address **addr)
+{
+ jbyte *bytes = NULL;
+#ifdef HAVE_INET_PTON
+ jbyte inet6_addr[16];
+#endif
+
+#ifdef HAVE_INET_ATON
+ struct in_addr laddr;
+ if (inet_aton (hostname, &laddr))
+ {
+ bytes = (jbyte *) &laddr;
+ }
+#elif defined(HAVE_INET_ADDR)
+#if ! HAVE_IN_ADDR_T
+ typedef jint in_addr_t;
+#endif
+ in_addr_t laddr = inet_addr (hostname);
+ if (laddr != (in_addr_t)(-1))
+ {
+ bytes = (jbyte *) &laddr;
+ }
+#endif
+ if (bytes)
+ {
+ *addr = cpnet_newIPV4Address(env);
+ cpnet_bytesToIPV4Address(*addr, bytes);
+ return 0;
+ }
+
+#ifdef HAVE_INET_PTON
+ if (inet_pton (AF_INET6, hostname, inet6_addr) > 0)
+ {
+ *addr = cpnet_newIPV6Address(env);
+ cpnet_bytesToIPV6Address(*addr, inet6_addr);
+ return 0;
+ }
+#endif
+
+ *addr = NULL;
+ return 0;
+}
+
void cpnet_freeAddresses(JNIEnv * env, cpnet_address **addr, jint addresses_count)
{
jint i;
diff --git a/native/jni/native-lib/cpnet.h b/native/jni/native-lib/cpnet.h
index 0c7c215f8..3705c76ec 100644
--- a/native/jni/native-lib/cpnet.h
+++ b/native/jni/native-lib/cpnet.h
@@ -94,6 +94,7 @@ JNIEXPORT jint cpnet_getAvailableBytes (JNIEnv *env, jint fd, jint *availableByt
JNIEXPORT jint cpnet_getHostname (JNIEnv *env, char *hostname, jint hostname_len);
JNIEXPORT jint cpnet_getHostByName (JNIEnv *env, const char *hostname, cpnet_address ***adresses, jint *addresses_count);
JNIEXPORT jint cpnet_getHostByAddr (JNIEnv *env, cpnet_address *addr, char *hostname, jint hostname_len);
+JNIEXPORT jint cpnet_aton (JNIEnv *env, const char *hostname, cpnet_address **addr);
JNIEXPORT void cpnet_freeAddresses(JNIEnv * env, cpnet_address **addr, jint addresses_count);
static inline cpnet_address *cpnet_newIPV4Address(JNIEnv * env)