| /* javanet.c - Common internal functions for the java.net package |
| Copyright (C) 1998, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. |
| |
| This file is 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, 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; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, 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. */ |
| |
| /* do not move; needed here because of some macro definitions */ |
| #include <config.h> |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include <jni.h> |
| #include <jcl.h> |
| |
| #include "javanet.h" |
| |
| #include "target_native.h" |
| #ifndef WITHOUT_NETWORK |
| #include "target_native_network.h" |
| #endif /* WITHOUT_NETWORK */ |
| |
| #ifndef WITHOUT_NETWORK |
| /* Need to have some value for SO_TIMEOUT */ |
| #ifndef SO_TIMEOUT |
| #ifndef SO_RCVTIMEO |
| #warning Neither SO_TIMEOUT or SO_RCVTIMEO are defined! |
| #warning This will cause all get/setOption calls with that value to throw an exception |
| #else |
| #define SO_TIMEOUT SO_RCVTIMEO |
| #endif /* not SO_RCVTIMEO */ |
| #endif /* not SO_TIMEOUT */ |
| #endif /* WITHOUT_NETWORK */ |
| |
| /*************************************************************************/ |
| |
| /* |
| * Sets an integer field in the specified object. |
| */ |
| static void |
| _javanet_set_int_field (JNIEnv * env, jobject obj, |
| const char *class, const char *field, int val) |
| { |
| jclass cls; |
| jfieldID fid; |
| |
| cls = (*env)->FindClass (env, class); |
| if (cls == NULL) |
| return; |
| |
| fid = (*env)->GetFieldID (env, cls, field, "I"); |
| if (fid == NULL) |
| return; |
| |
| (*env)->SetIntField (env, obj, fid, val); |
| |
| return; |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Returns the value of the specified integer instance variable field or |
| * -1 if an error occurs. |
| */ |
| int |
| _javanet_get_int_field (JNIEnv * env, jobject obj, const char *field) |
| { |
| jclass cls = 0; |
| jfieldID fid; |
| int fd; |
| |
| DBG ("_javanet_get_int_field(): Entered _javanet_get_int_field\n"); |
| |
| cls = (*env)->GetObjectClass (env, obj); |
| if (cls == NULL) |
| return -1; |
| |
| fid = (*env)->GetFieldID (env, cls, field, "I"); |
| if (fid == NULL) |
| return -1; |
| DBG ("_javanet_get_int_field(): Found field id\n"); |
| |
| fd = (*env)->GetIntField (env, obj, fid); |
| |
| return fd; |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Creates a FileDescriptor object in the parent class. It is not used |
| * by this implementation, but the docs list it as a variable, so we |
| * need to include it. |
| */ |
| static void |
| _javanet_create_localfd (JNIEnv * env, jobject this, jboolean stream) |
| { |
| jclass this_cls, fd_cls; |
| jfieldID fid; |
| jmethodID mid; |
| jobject fd_obj; |
| |
| DBG ("_javanet_create_localfd(): Entered _javanet_create_localfd\n"); |
| |
| /* Look up the fd field */ |
| if (stream) |
| this_cls = (*env)->FindClass(env, "java/net/SocketImpl"); |
| else |
| this_cls = (*env)->FindClass(env, "java/net/DatagramSocketImpl"); |
| if (this_cls == NULL) |
| return; |
| |
| fid = (*env)->GetFieldID (env, this_cls, "fd", "Ljava/io/FileDescriptor;"); |
| if (fid == NULL) |
| return; |
| |
| DBG ("_javanet_create_localfd(): Found fd variable\n"); |
| |
| /* Create a FileDescriptor */ |
| fd_cls = (*env)->FindClass (env, "java/io/FileDescriptor"); |
| if (fd_cls == NULL) |
| return; |
| |
| DBG ("_javanet_create_localfd(): Found FileDescriptor class\n"); |
| |
| mid = (*env)->GetMethodID (env, fd_cls, "<init>", "()V"); |
| if (mid == NULL) |
| return; |
| |
| DBG ("_javanet_create_localfd(): Found FileDescriptor constructor\n"); |
| |
| fd_obj = (*env)->NewObject (env, fd_cls, mid); |
| if (fd_obj == NULL) |
| return; |
| |
| DBG ("_javanet_create_localfd(): Created FileDescriptor\n"); |
| |
| /* Now set the pointer to the new FileDescriptor */ |
| (*env)->SetObjectField (env, this, fid, fd_obj); |
| DBG ("_javanet_create_localfd(): Set fd field\n"); |
| |
| return; |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Returns a Boolean object with the specfied value |
| */ |
| static jobject |
| _javanet_create_boolean (JNIEnv * env, jboolean val) |
| { |
| jclass cls; |
| jmethodID mid; |
| jobject obj; |
| |
| cls = (*env)->FindClass (env, "java/lang/Boolean"); |
| if (cls == NULL) |
| return NULL; |
| |
| mid = (*env)->GetMethodID (env, cls, "<init>", "(Z)V"); |
| if (mid == NULL) |
| return NULL; |
| |
| obj = (*env)->NewObject (env, cls, mid, val); |
| if (obj == NULL) |
| return NULL; |
| |
| return obj; |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Returns an Integer object with the specfied value |
| */ |
| static jobject |
| _javanet_create_integer (JNIEnv * env, jint val) |
| { |
| jclass cls; |
| jmethodID mid; |
| jobject obj; |
| |
| cls = (*env)->FindClass (env, "java/lang/Integer"); |
| if (cls == NULL) |
| return NULL; |
| |
| mid = (*env)->GetMethodID (env, cls, "<init>", "(I)V"); |
| if (mid == NULL) |
| return NULL; |
| |
| obj = (*env)->NewObject (env, cls, mid, val); |
| if (obj == NULL) |
| return NULL; |
| |
| return obj; |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Builds an InetAddress object from a 32 bit address in host byte order |
| */ |
| static jobject |
| _javanet_create_inetaddress (JNIEnv * env, int netaddr) |
| { |
| #ifndef WITHOUT_NETWORK |
| unsigned char octets[4]; |
| char buf[16]; |
| jclass ia_cls; |
| jmethodID mid; |
| jstring ip_str; |
| jobject ia; |
| |
| /* Build a string IP address */ |
| TARGET_NATIVE_NETWORK_INT_TO_IPADDRESS_BYTES (netaddr, |
| octets[0], |
| octets[1], |
| octets[2], octets[3]); |
| sprintf (buf, "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); |
| DBG ("_javanet_create_inetaddress(): Created ip addr string\n"); |
| |
| /* Get an InetAddress object for this IP */ |
| ia_cls = (*env)->FindClass (env, "java/net/InetAddress"); |
| if (ia_cls == NULL) |
| { |
| return NULL; |
| } |
| |
| DBG ("_javanet_create_inetaddress(): Found InetAddress class\n"); |
| |
| mid = (*env)->GetStaticMethodID (env, ia_cls, "getByName", |
| "(Ljava/lang/String;)Ljava/net/InetAddress;"); |
| if (mid == NULL) |
| { |
| return NULL; |
| } |
| |
| DBG ("_javanet_create_inetaddress(): Found getByName method\n"); |
| |
| ip_str = (*env)->NewStringUTF (env, buf); |
| if (ip_str == NULL) |
| { |
| return NULL; |
| } |
| |
| ia = (*env)->CallStaticObjectMethod (env, ia_cls, mid, ip_str); |
| if (ia == NULL) |
| { |
| return NULL; |
| } |
| |
| DBG ("_javanet_create_inetaddress(): Called getByName method\n"); |
| |
| return ia; |
| #else /* not WITHOUT_NETWORK */ |
| return NULL; |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| static void |
| _javanet_set_remhost_addr (JNIEnv * env, jobject this, jobject ia) |
| { |
| jclass this_cls; |
| jfieldID fid; |
| |
| /* Set the variable in the object */ |
| this_cls = (*env)->FindClass (env, "java/net/SocketImpl"); |
| if (this_cls == NULL) |
| return; |
| |
| fid = |
| (*env)->GetFieldID (env, this_cls, "address", "Ljava/net/InetAddress;"); |
| if (fid == NULL) |
| return; |
| |
| DBG ("_javanet_set_remhost_addr(): Found address field\n"); |
| |
| (*env)->SetObjectField (env, this, fid, ia); |
| DBG ("_javanet_set_remhost_addr(): Set field\n"); |
| } |
| |
| /* |
| * Set's the value of the "addr" field in PlainSocketImpl with a new |
| * InetAddress for the specified addr |
| */ |
| static void |
| _javanet_set_remhost (JNIEnv * env, jobject this, int netaddr) |
| { |
| jobject ia; |
| |
| DBG ("_javanet_set_remhost(): Entered _javanet_set_remhost\n"); |
| |
| /* Get an InetAddress object */ |
| ia = _javanet_create_inetaddress (env, netaddr); |
| if (ia == NULL) |
| return; |
| |
| _javanet_set_remhost_addr (env, this, ia); |
| } |
| |
| |
| /*************************************************************************/ |
| |
| /* |
| * Returns a 32 bit Internet address for the passed in InetAddress object |
| */ |
| int |
| _javanet_get_netaddr (JNIEnv * env, jobject addr) |
| { |
| #ifndef WITHOUT_NETWORK |
| jclass cls = 0; |
| jmethodID mid; |
| jarray arr = 0; |
| jbyte *octets; |
| int netaddr, len; |
| |
| DBG ("_javanet_get_netaddr(): Entered _javanet_get_netaddr\n"); |
| |
| if (addr == NULL) |
| { |
| JCL_ThrowException (env, "java/lang/NullPointerException", |
| "Null address"); |
| return 0; |
| } |
| |
| /* Call the getAddress method on the object to retrieve the IP address */ |
| cls = (*env)->GetObjectClass (env, addr); |
| if (cls == NULL) |
| return 0; |
| |
| mid = (*env)->GetMethodID (env, cls, "getAddress", "()[B"); |
| if (mid == NULL) |
| return 0; |
| |
| DBG ("_javanet_get_netaddr(): Got getAddress method\n"); |
| |
| arr = (*env)->CallObjectMethod (env, addr, mid); |
| if (arr == NULL) |
| return 0; |
| |
| DBG ("_javanet_get_netaddr(): Got the address\n"); |
| |
| /* Turn the IP address into a 32 bit Internet address in network byte order */ |
| len = (*env)->GetArrayLength (env, arr); |
| if (len != 4) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, "Internal Error"); |
| return 0; |
| } |
| DBG ("_javanet_get_netaddr(): Length ok\n"); |
| |
| octets = (*env)->GetByteArrayElements (env, arr, 0); |
| if (octets == NULL) |
| return 0; |
| |
| DBG ("_javanet_get_netaddr(): Grabbed bytes\n"); |
| |
| TARGET_NATIVE_NETWORK_IPADDRESS_BYTES_TO_INT (octets[0], |
| octets[1], |
| octets[2], |
| octets[3], netaddr); |
| |
| (*env)->ReleaseByteArrayElements (env, arr, octets, 0); |
| DBG ("_javanet_get_netaddr(): Done getting addr\n"); |
| |
| return netaddr; |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Creates a new stream or datagram socket |
| */ |
| void |
| _javanet_create (JNIEnv * env, jobject this, jboolean stream) |
| { |
| #ifndef WITHOUT_NETWORK |
| int fd; |
| int result; |
| |
| if (stream) |
| { |
| /* create a stream socket */ |
| TARGET_NATIVE_NETWORK_SOCKET_OPEN_STREAM (fd, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| } |
| else |
| { |
| /* create a datagram socket, set broadcast option */ |
| TARGET_NATIVE_NETWORK_SOCKET_OPEN_DATAGRAM (fd, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_BROADCAST (fd, 1, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| } |
| |
| if (stream) |
| _javanet_set_int_field (env, this, "gnu/java/net/PlainSocketImpl", |
| "native_fd", fd); |
| else |
| _javanet_set_int_field (env, this, "gnu/java/net/PlainDatagramSocketImpl", |
| "native_fd", fd); |
| |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* Try to make sure we close the socket since close() won't work. */ |
| do |
| { |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); |
| if (result != TARGET_NATIVE_OK |
| && (TARGET_NATIVE_LAST_ERROR () |
| != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) |
| return; |
| } |
| while (result != TARGET_NATIVE_OK); |
| return; |
| } |
| |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Close the socket. Any underlying streams will be closed by this |
| * action as well. |
| */ |
| void |
| _javanet_close (JNIEnv * env, jobject this, int stream) |
| { |
| #ifndef WITHOUT_NETWORK |
| int fd; |
| int result; |
| int error = 0; |
| |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| return; |
| |
| if (stream) |
| _javanet_set_int_field (env, this, "gnu/java/net/PlainSocketImpl", |
| "native_fd", -1); |
| else |
| _javanet_set_int_field (env, this, "gnu/java/net/PlainDatagramSocketImpl", |
| "native_fd", -1); |
| do |
| { |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| /* Only throw an error when a "real" error occurs. */ |
| error = TARGET_NATIVE_LAST_ERROR (); |
| if (error != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL |
| && error != ENOTCONN && error != ECONNRESET && error != EBADF) |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| } |
| } |
| while (error == TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL); |
| |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Connects to the specified destination. |
| */ |
| void |
| _javanet_connect (JNIEnv * env, jobject this, jobject addr, jint port, |
| jboolean stream) |
| { |
| #ifndef WITHOUT_NETWORK |
| int netaddr, fd; |
| int result; |
| int local_address, local_port; |
| int remote_address, remote_port; |
| |
| DBG ("_javanet_connect(): Entered _javanet_connect\n"); |
| |
| /* Pre-process input variables */ |
| netaddr = _javanet_get_netaddr (env, addr); |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| if (port == -1) |
| port = 0; |
| DBG ("_javanet_connect(): Got network address\n"); |
| |
| /* Grab the real socket file descriptor */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_connect(): no native file descriptor"); |
| return; |
| } |
| DBG ("_javanet_connect(): Got native fd\n"); |
| |
| /* Connect up */ |
| do |
| { |
| TARGET_NATIVE_NETWORK_SOCKET_CONNECT (fd, netaddr, port, result); |
| if (result != TARGET_NATIVE_OK |
| && (TARGET_NATIVE_LAST_ERROR () |
| != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) |
| { |
| JCL_ThrowException (env, CONNECT_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| } |
| while (result != TARGET_NATIVE_OK); |
| |
| DBG ("_javanet_connect(): Connected successfully\n"); |
| |
| /* Populate instance variables */ |
| TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (fd, local_address, local_port, |
| result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); |
| return; |
| } |
| |
| _javanet_create_localfd (env, this, stream); |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); |
| return; |
| } |
| DBG ("_javanet_connect(): Created fd\n"); |
| |
| if (stream) |
| _javanet_set_int_field (env, this, "java/net/SocketImpl", "localport", |
| local_port); |
| else |
| _javanet_set_int_field (env, this, "java/net/DatagramSocketImpl", |
| "localPort", local_port); |
| |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); |
| return; |
| } |
| DBG ("_javanet_connect(): Set the local port\n"); |
| |
| TARGET_NATIVE_NETWORK_SOCKET_GET_REMOTE_INFO (fd, remote_address, |
| remote_port, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); |
| return; |
| } |
| |
| if (stream) |
| { |
| if (remote_address == netaddr) |
| { |
| _javanet_set_remhost_addr (env, this, addr); |
| } |
| else |
| { |
| _javanet_set_remhost (env, this, remote_address); |
| } |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. |
| */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); |
| return; |
| } |
| DBG ("_javanet_connect(): Set the remote host\n"); |
| |
| _javanet_set_int_field (env, this, "java/net/SocketImpl", "port", |
| remote_port); |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. |
| */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); |
| return; |
| } |
| DBG ("_javanet_connect(): Set the remote port\n"); |
| } |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * 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. |
| */ |
| void |
| _javanet_bind (JNIEnv * env, jobject this, jobject addr, jint port, |
| int stream) |
| { |
| #ifndef WITHOUT_NETWORK |
| jclass cls; |
| jmethodID mid; |
| jbyteArray arr = 0; |
| jbyte *octets; |
| jint fd; |
| int tmpaddr; |
| int result; |
| int local_address, local_port; |
| |
| DBG ("_javanet_bind(): Entering native bind()\n"); |
| |
| /* Get the address to connect to */ |
| cls = (*env)->GetObjectClass (env, addr); |
| if (cls == NULL) |
| return; |
| |
| mid = (*env)->GetMethodID (env, cls, "getAddress", "()[B"); |
| if (mid == NULL) |
| return; |
| |
| DBG ("_javanet_bind(): Past getAddress method id\n"); |
| |
| arr = (*env)->CallObjectMethod (env, addr, mid); |
| if ((arr == NULL) || (*env)->ExceptionOccurred (env)) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_bind()"); |
| return; |
| } |
| |
| DBG ("_javanet_bind(): Past call object method\n"); |
| |
| octets = (*env)->GetByteArrayElements (env, arr, 0); |
| if (octets == NULL) |
| return; |
| |
| DBG ("_javanet_bind(): Past grab array\n"); |
| |
| /* Get the native socket file descriptor */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| (*env)->ReleaseByteArrayElements (env, arr, octets, 0); |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_bind(): no native file descriptor"); |
| return; |
| } |
| DBG ("_javanet_bind(): Past native_fd lookup\n"); |
| |
| /* XXX NYI ??? */ |
| _javanet_set_option (env, this, SOCKOPT_SO_REUSEADDR, |
| _javanet_create_boolean (env, JNI_TRUE)); |
| |
| |
| /* Bind the socket */ |
| TARGET_NATIVE_NETWORK_IPADDRESS_BYTES_TO_INT (octets[0], |
| octets[1], |
| octets[2], |
| octets[3], tmpaddr); |
| TARGET_NATIVE_NETWORK_SOCKET_BIND (fd, tmpaddr, port, result); |
| |
| if (result != TARGET_NATIVE_OK) |
| { |
| char *errorstr = TARGET_NATIVE_LAST_ERROR_STRING (); |
| (*env)->ReleaseByteArrayElements (env, arr, octets, 0); |
| |
| JCL_ThrowException (env, BIND_EXCEPTION, |
| errorstr); |
| return; |
| } |
| DBG ("_javanet_bind(): Past bind\n"); |
| |
| (*env)->ReleaseByteArrayElements (env, arr, octets, 0); |
| |
| /* Update instance variables, specifically the local port number */ |
| TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (fd, local_address, local_port, |
| result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| |
| if (stream) |
| _javanet_set_int_field (env, this, "java/net/SocketImpl", |
| "localport", local_port); |
| else |
| _javanet_set_int_field (env, this, "java/net/DatagramSocketImpl", |
| "localPort", local_port); |
| DBG ("_javanet_bind(): Past update port number\n"); |
| |
| return; |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Starts listening on a socket with the specified number of pending |
| * connections allowed. |
| */ |
| void |
| _javanet_listen (JNIEnv * env, jobject this, jint queuelen) |
| { |
| #ifndef WITHOUT_NETWORK |
| int fd; |
| int result; |
| |
| /* Get the real file descriptor */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_listen(): no native file descriptor"); |
| return; |
| } |
| |
| /* Start listening */ |
| TARGET_NATIVE_NETWORK_SOCKET_LISTEN (fd, queuelen, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Accepts a new connection and assigns it to the passed in SocketImpl |
| * object. Note that we assume this is a PlainSocketImpl just like us |
| */ |
| void |
| _javanet_accept (JNIEnv * env, jobject this, jobject impl) |
| { |
| #ifndef WITHOUT_NETWORK |
| int fd, newfd; |
| int result; |
| int local_address, local_port; |
| int remote_address, remote_port; |
| |
| /* Get the real file descriptor */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_accept(): no native file descriptor"); |
| return; |
| } |
| |
| /* Accept the connection */ |
| do |
| { |
| TARGET_NATIVE_NETWORK_SOCKET_ACCEPT (fd, newfd, result); |
| if (result != TARGET_NATIVE_OK |
| && (TARGET_NATIVE_LAST_ERROR () |
| != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) |
| { |
| if (TARGET_NATIVE_LAST_ERROR () == EAGAIN) |
| JCL_ThrowException (env, "java/net/SocketTimeoutException", |
| "Timeout"); |
| else |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| } |
| while (result != TARGET_NATIVE_OK); |
| |
| /* Reset the inherited timeout. */ |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_TIMEOUT (newfd, 0, result); |
| |
| /* Populate instance variables */ |
| _javanet_set_int_field (env, impl, "gnu/java/net/PlainSocketImpl", |
| "native_fd", newfd); |
| |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* Try to make sure we close the socket since close() won't work. */ |
| do |
| { |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); |
| if (result != TARGET_NATIVE_OK |
| && (TARGET_NATIVE_LAST_ERROR () |
| != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) |
| return; |
| } |
| while (result != TARGET_NATIVE_OK); |
| return; |
| } |
| |
| TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (newfd, local_address, |
| local_port, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| |
| _javanet_create_localfd (env, impl, 1); |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); |
| return; |
| } |
| |
| _javanet_set_int_field (env, impl, "java/net/SocketImpl", "localport", |
| local_port); |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); |
| return; |
| } |
| |
| TARGET_NATIVE_NETWORK_SOCKET_GET_REMOTE_INFO (newfd, remote_address, |
| remote_port, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); |
| return; |
| } |
| |
| _javanet_set_remhost (env, impl, remote_address); |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); |
| return; |
| } |
| |
| _javanet_set_int_field (env, impl, "java/net/SocketImpl", "port", |
| remote_port); |
| if ((*env)->ExceptionOccurred (env)) |
| { |
| /* We don't care whether this succeeds. close() will cleanup later. */ |
| TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); |
| return; |
| } |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Receives a buffer from a remote host. The args are: |
| * |
| * buf - The byte array into which the data received will be written |
| * offset - Offset into the byte array to start writing |
| * len - The number of bytes to read. |
| * addr - Pointer to 32 bit net address of host to receive from. If null, |
| * this parm is ignored. If pointing to an address of 0, the |
| * actual address read is stored here |
| * port - Pointer to the port to receive from. If null, this parm is ignored. |
| * If it is 0, the actual remote port received from is stored here |
| * |
| * The actual number of bytes read is returned. |
| */ |
| int |
| _javanet_recvfrom (JNIEnv * env, jobject this, jarray buf, int offset, |
| int len, int *addr, int *port) |
| { |
| #ifndef WITHOUT_NETWORK |
| int fd; |
| jbyte *p; |
| int from_address, from_port; |
| int received_bytes; |
| |
| DBG ("_javanet_recvfrom(): Entered _javanet_recvfrom\n"); |
| |
| /* Get the real file descriptor */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_recvfrom(): no native file descriptor"); |
| return 0; |
| } |
| DBG ("_javanet_recvfrom(): Got native_fd\n"); |
| |
| /* Get a pointer to the buffer */ |
| p = (*env)->GetByteArrayElements (env, buf, 0); |
| if (p == NULL) |
| return 0; |
| |
| DBG ("_javanet_recvfrom(): Got buffer\n"); |
| |
| /* Read the data */ |
| from_address = 0; |
| from_port = 0; |
| do |
| { |
| if (addr != NULL) |
| { |
| TARGET_NATIVE_NETWORK_SOCKET_RECEIVE_WITH_ADDRESS_PORT (fd, |
| p + offset, |
| len, |
| from_address, |
| from_port, |
| received_bytes); |
| } |
| else |
| { |
| TARGET_NATIVE_NETWORK_SOCKET_RECEIVE (fd, p + offset, len, |
| received_bytes); |
| } |
| } |
| while ((received_bytes == -1) && |
| (TARGET_NATIVE_LAST_ERROR () == |
| TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)); |
| |
| if (received_bytes == -1) |
| { |
| if (TARGET_NATIVE_LAST_ERROR () == EAGAIN) |
| JCL_ThrowException (env, "java/net/SocketTimeoutException", "Timeout"); |
| else |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| |
| /* Cleanup and return. */ |
| (*env)->ReleaseByteArrayElements (env, buf, p, 0); |
| return 0; |
| } |
| |
| (*env)->ReleaseByteArrayElements (env, buf, p, 0); |
| |
| /* Handle return addr case */ |
| if (addr != NULL) |
| { |
| (*addr) = from_address; |
| if (port != NULL) |
| (*port) = from_port; |
| } |
| |
| /* zero bytes received means recv() noticed the other side orderly |
| closing the connection. */ |
| if (received_bytes == 0) |
| received_bytes = -1; |
| |
| return (received_bytes); |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Sends a buffer to a remote host. The args are: |
| * |
| * buf - A byte array |
| * offset - Index into the byte array to start sendign |
| * len - The number of bytes to write |
| * addr - The 32bit address to send to (may be 0) |
| * port - The port number to send to (may be 0) |
| */ |
| void |
| _javanet_sendto (JNIEnv * env, jobject this, jarray buf, int offset, int len, |
| int addr, int port) |
| { |
| #ifndef WITHOUT_NETWORK |
| int fd; |
| jbyte *p; |
| int bytes_sent; |
| |
| /* Get the real file descriptor */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_sendto(): no native file descriptor"); |
| return; |
| } |
| |
| /* Get a pointer to the buffer */ |
| p = (*env)->GetByteArrayElements (env, buf, 0); |
| if (p == NULL) |
| return; |
| |
| /* We must send all the data, so repeat till done. */ |
| while (len > 0) |
| { |
| /* Send the data */ |
| if (addr == 0) |
| { |
| DBG ("_javanet_sendto(): Sending....\n"); |
| TARGET_NATIVE_NETWORK_SOCKET_SEND (fd, p + offset, len, bytes_sent); |
| } |
| else |
| { |
| DBG ("_javanet_sendto(): Sending....\n"); |
| TARGET_NATIVE_NETWORK_SOCKET_SEND_WITH_ADDRESS_PORT (fd, p + offset, |
| len, addr, port, |
| bytes_sent); |
| } |
| |
| if (bytes_sent < 0) |
| { |
| if (TARGET_NATIVE_LAST_ERROR () |
| != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| break; |
| } |
| } |
| else |
| { |
| len -= bytes_sent; |
| addr += bytes_sent; |
| } |
| } |
| |
| (*env)->ReleaseByteArrayElements (env, buf, p, 0); |
| |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Sets the specified option for a socket |
| */ |
| void |
| _javanet_set_option (JNIEnv * env, jobject this, jint option_id, jobject val) |
| { |
| #ifndef WITHOUT_NETWORK |
| int fd; |
| int optval; |
| jclass cls; |
| jmethodID mid; |
| int address; |
| int result; |
| |
| /* Get the real file descriptor */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_set_option(): no native file descriptor"); |
| return; |
| } |
| |
| /* We need a class object for all cases below */ |
| cls = (*env)->GetObjectClass (env, val); |
| if (cls == NULL) |
| return; |
| |
| /* Process the option request */ |
| result = TARGET_NATIVE_ERROR; |
| switch (option_id) |
| { |
| /* TCP_NODELAY case. val is a Boolean that tells us what to do */ |
| case SOCKOPT_TCP_NODELAY: |
| mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z"); |
| if (mid == NULL) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_set_option()"); |
| return; |
| } |
| |
| /* Should be a 0 or a 1 */ |
| optval = (*env)->CallBooleanMethod (env, val, mid); |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_TCP_NODELAY (fd, optval, |
| result); |
| break; |
| |
| /* SO_LINGER case. If val is a boolean, then it will always be set |
| to false indicating disable linger, otherwise it will be an |
| integer that contains the linger value */ |
| case SOCKOPT_SO_LINGER: |
| mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z"); |
| if (mid) |
| { |
| /* We are disabling linger */ |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_LINGER (fd, 1, 0, |
| result); |
| } |
| else |
| { |
| /* Clear exception if thrown for failure to do method lookup |
| above */ |
| if ((*env)->ExceptionOccurred (env)) |
| (*env)->ExceptionClear (env); |
| |
| mid = (*env)->GetMethodID (env, cls, "intValue", "()I"); |
| if (mid == NULL) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_set_option()"); |
| return; |
| } |
| |
| optval = (*env)->CallIntMethod (env, val, mid); |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_LINGER (fd, 0, optval, |
| result); |
| } |
| break; |
| |
| /* SO_TIMEOUT case. Val will be an integer with the new value */ |
| /* Not writable on Linux */ |
| case SOCKOPT_SO_TIMEOUT: |
| #ifdef SO_TIMEOUT |
| mid = (*env)->GetMethodID (env, cls, "intValue", "()I"); |
| if (mid == NULL) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_set_option()"); |
| return; |
| } |
| |
| optval = (*env)->CallIntMethod (env, val, mid); |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_TIMEOUT (fd, optval, result); |
| #else |
| result = TARGET_NATIVE_OK; |
| #endif |
| break; |
| |
| case SOCKOPT_SO_SNDBUF: |
| case SOCKOPT_SO_RCVBUF: |
| mid = (*env)->GetMethodID (env, cls, "intValue", "()I"); |
| if (mid == NULL) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_set_option()"); |
| return; |
| } |
| |
| |
| optval = (*env)->CallIntMethod (env, val, mid); |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| if (option_id == SOCKOPT_SO_SNDBUF) |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_SNDBUF (fd, optval, |
| result); |
| else |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_RCDBUF (fd, optval, |
| result); |
| break; |
| |
| /* TTL case. Val with be an Integer with the new time to live value */ |
| case SOCKOPT_IP_TTL: |
| mid = (*env)->GetMethodID (env, cls, "intValue", "()I"); |
| if (!mid) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_set_option()"); |
| return; |
| } |
| |
| optval = (*env)->CallIntMethod (env, val, mid); |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_IP_TTL (fd, optval, result); |
| break; |
| |
| /* Multicast Interface case - val is InetAddress object */ |
| case SOCKOPT_IP_MULTICAST_IF: |
| address = _javanet_get_netaddr (env, val); |
| |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_IP_MULTICAST_IF (fd, address, |
| result); |
| break; |
| |
| case SOCKOPT_SO_REUSEADDR: |
| mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z"); |
| if (mid == NULL) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_set_option()"); |
| return; |
| } |
| |
| /* Should be a 0 or a 1 */ |
| optval = (*env)->CallBooleanMethod (env, val, mid); |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_REUSE_ADDRESS (fd, optval, |
| result); |
| break; |
| |
| case SOCKOPT_SO_KEEPALIVE: |
| mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z"); |
| if (mid == NULL) |
| { |
| JCL_ThrowException (env, IO_EXCEPTION, |
| "Internal error: _javanet_set_option()"); |
| return; |
| } |
| |
| /* Should be a 0 or a 1 */ |
| optval = (*env)->CallBooleanMethod (env, val, mid); |
| if ((*env)->ExceptionOccurred (env)) |
| return; |
| |
| TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_KEEP_ALIVE (fd, optval, result); |
| break; |
| |
| case SOCKOPT_SO_BINDADDR: |
| JCL_ThrowException (env, SOCKET_EXCEPTION, "This option cannot be set"); |
| break; |
| |
| default: |
| JCL_ThrowException (env, SOCKET_EXCEPTION, "Unrecognized option"); |
| return; |
| } |
| |
| /* Check to see if above operations succeeded */ |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return; |
| } |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| /*************************************************************************/ |
| |
| /* |
| * Retrieves the specified option values for a socket |
| */ |
| jobject |
| _javanet_get_option (JNIEnv * env, jobject this, jint option_id) |
| { |
| #ifndef WITHOUT_NETWORK |
| int fd; |
| int flag, optval; |
| int address; |
| int result; |
| |
| /* Get the real file descriptor */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| "Internal error: _javanet_get_option(): no native file descriptor"); |
| return (0); |
| } |
| |
| /* Process the option requested */ |
| switch (option_id) |
| { |
| /* TCP_NODELAY case. Return a Boolean indicating on or off */ |
| case SOCKOPT_TCP_NODELAY: |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_TCP_NODELAY (fd, optval, |
| result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| |
| if (optval) |
| return (_javanet_create_boolean (env, JNI_TRUE)); |
| else |
| return (_javanet_create_boolean (env, JNI_FALSE)); |
| |
| break; |
| |
| /* SO_LINGER case. If disabled, return a Boolean object that represents |
| false, else return an Integer that is the value of SO_LINGER */ |
| case SOCKOPT_SO_LINGER: |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_LINGER (fd, flag, optval, |
| result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| |
| if (optval) |
| return (_javanet_create_integer (env, JNI_TRUE)); |
| else |
| return (_javanet_create_boolean (env, JNI_FALSE)); |
| |
| break; |
| |
| /* SO_TIMEOUT case. Return an Integer object with the timeout value */ |
| case SOCKOPT_SO_TIMEOUT: |
| #ifdef SO_TIMEOUT |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_TIMEOUT (fd, optval, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| return (_javanet_create_integer (env, optval)); |
| #else |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| "SO_TIMEOUT not supported on this platform"); |
| return (0); |
| #endif /* not SO_TIMEOUT */ |
| break; |
| |
| case SOCKOPT_SO_SNDBUF: |
| case SOCKOPT_SO_RCVBUF: |
| if (option_id == SOCKOPT_SO_SNDBUF) |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_SNDBUF (fd, optval, |
| result); |
| else |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_RCDBUF (fd, optval, |
| result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| |
| return (_javanet_create_integer (env, optval)); |
| break; |
| |
| /* The TTL case. Return an Integer with the Time to Live value */ |
| case SOCKOPT_IP_TTL: |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_IP_TTL (fd, optval, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| |
| return (_javanet_create_integer (env, optval)); |
| break; |
| |
| /* Multicast interface case */ |
| case SOCKOPT_IP_MULTICAST_IF: |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_IP_MULTICAST_IF (fd, address, |
| result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| |
| return (_javanet_create_inetaddress (env, address)); |
| break; |
| |
| case SOCKOPT_SO_BINDADDR: |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_BIND_ADDRESS (fd, address, |
| result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| |
| return (_javanet_create_inetaddress (env, address)); |
| break; |
| |
| case SOCKOPT_SO_REUSEADDR: |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_REUSE_ADDRESS (fd, optval, |
| result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| |
| if (optval) |
| return (_javanet_create_boolean (env, JNI_TRUE)); |
| else |
| return (_javanet_create_boolean (env, JNI_FALSE)); |
| |
| break; |
| |
| case SOCKOPT_SO_KEEPALIVE: |
| TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_KEEP_ALIVE (fd, optval, result); |
| if (result != TARGET_NATIVE_OK) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING ()); |
| return (0); |
| } |
| |
| if (optval) |
| return (_javanet_create_boolean (env, JNI_TRUE)); |
| else |
| return (_javanet_create_boolean (env, JNI_FALSE)); |
| |
| break; |
| |
| default: |
| JCL_ThrowException (env, SOCKET_EXCEPTION, "No such option"); |
| return (0); |
| } |
| |
| return (0); |
| #else /* not WITHOUT_NETWORK */ |
| #endif /* not WITHOUT_NETWORK */ |
| } |
| |
| void |
| _javanet_shutdownInput (JNIEnv * env, jobject this) |
| { |
| int fd; |
| |
| /* Get the real file descriptor. */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| "Internal error: _javanet_get_option(): no native file descriptor"); |
| return; |
| } |
| |
| /* Shutdown input stream of socket. */ |
| if (shutdown (fd, SHUT_RD) == -1) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING()); |
| return; |
| } |
| } |
| |
| void |
| _javanet_shutdownOutput (JNIEnv * env, jobject this) |
| { |
| int fd; |
| |
| /* Get the real file descriptor. */ |
| fd = _javanet_get_int_field (env, this, "native_fd"); |
| if (fd == -1) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| "Internal error: _javanet_get_option(): no native file descriptor"); |
| return; |
| } |
| |
| /* Shutdown output stream of socket. */ |
| if (shutdown (fd, SHUT_WR) == -1) |
| { |
| JCL_ThrowException (env, SOCKET_EXCEPTION, |
| TARGET_NATIVE_LAST_ERROR_STRING()); |
| return; |
| } |
| } |
| |
| /* end of file */ |