From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/native/jni/java-net/javanet.c | 1500 +++++++++++++++++++++++ 1 file changed, 1500 insertions(+) create mode 100644 libjava/classpath/native/jni/java-net/javanet.c (limited to 'libjava/classpath/native/jni/java-net/javanet.c') diff --git a/libjava/classpath/native/jni/java-net/javanet.c b/libjava/classpath/native/jni/java-net/javanet.c new file mode 100644 index 000000000..1f093f4aa --- /dev/null +++ b/libjava/classpath/native/jni/java-net/javanet.c @@ -0,0 +1,1500 @@ +/* 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 + +#include +#include +#include + +#include +#include + +#include "cpnative.h" +#include "cpnet.h" + +#include "javanet.h" + +#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, "", "()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, "", "(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, "", "(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 + */ +jobject +_javanet_create_inetaddress (JNIEnv * env, cpnet_address *netaddr) +{ +#ifndef WITHOUT_NETWORK + jbyte octets[4]; + char buf[64]; + jclass ia_cls; + jmethodID mid; + jstring ip_str; + jobject ia; + + /* Build a string IP address */ + cpnet_IPV4AddressToBytes(netaddr, octets); + sprintf (buf, "%d.%d.%d.%d", (int) (unsigned char)octets[0], (int)(unsigned char)octets[1], (int)(unsigned char)octets[2], (int)(unsigned char)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, cpnet_address *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 an Internet address for the passed in InetAddress object + */ +cpnet_address * +_javanet_get_ip_netaddr (JNIEnv * env, jobject addr) +{ +#ifndef WITHOUT_NETWORK + jclass cls = 0; + jmethodID mid; + jarray arr = 0; + jbyte *octets; + cpnet_address *netaddr; + jint len; + + DBG ("_javanet_get_ip_netaddr(): Entered _javanet_get_ip_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_ip_netaddr(): Got getAddress method\n"); + + arr = (*env)->CallObjectMethod (env, addr, mid); + if (arr == NULL) + return 0; + + DBG ("_javanet_get_ip_netaddr(): Got the address\n"); + + /* Turn the IP address into a system cpnet address. + * If the length is 4 then it is an IPV4 address, if it + * is 16 then it is an IPV6 address else it is an InternError. */ + len = (*env)->GetArrayLength (env, arr); + if (len != 4 && len != 16) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal Error"); + return 0; + } + DBG ("_javanet_get_ip_netaddr(): Length ok\n"); + + octets = (*env)->GetByteArrayElements (env, arr, 0); + if (octets == NULL) + return 0; + + DBG ("_javanet_get_ip_netaddr(): Grabbed bytes\n"); + + switch (len) + { + case 4: + netaddr = cpnet_newIPV4Address(env); + cpnet_bytesToIPV4Address(netaddr, octets); + break; +#ifdef HAVE_INET6 + case 16: + netaddr = cpnet_newIPV6Address(env); + cpnet_bytesToIPV6Address(netaddr, octets); + break; +#endif + default: + /* This should not happen as we have checked before. + * But that way we shut the compiler warnings */ + JCL_ThrowException (env, IO_EXCEPTION, "Internal Error"); + return 0; + + } + + (*env)->ReleaseByteArrayElements (env, arr, octets, 0); + DBG ("_javanet_get_ip_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 */ + result = cpnet_openSocketStream(env, &fd, AF_INET); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + return; + } + } + else + { + /* create a datagram socket, set broadcast option */ + result = cpnet_openSocketDatagram (env, &fd, AF_INET); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + return; + } + result = cpnet_setBroadcast(env, fd, 1); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + 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 + { + result = cpnet_close(env, fd); + if (result != CPNATIVE_OK && result != CPNATIVE_EINTR) + return; + } + while (result != CPNATIVE_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 + { + result = cpnet_close (env, fd); + if (result != CPNATIVE_OK) + { + /* Only throw an error when a "real" error occurs. */ + if (result != CPNATIVE_EINTR && result != ENOTCONN && result != ECONNRESET && result != EBADF) + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + } + } + while (error == CPNATIVE_EINTR); + +#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 + cpnet_address *netaddr; + int fd; + int result; + cpnet_address *local_addr; + cpnet_address *remote_addr; + + DBG ("_javanet_connect(): Entered _javanet_connect\n"); + + /* Pre-process input variables */ + netaddr = _javanet_get_ip_netaddr (env, addr); + if ((*env)->ExceptionOccurred (env)) + return; + + if (port == -1) + port = 0; + + cpnet_addressSetPort(netaddr, port); + + 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 + { + result = cpnet_connect (env, fd, netaddr); + if (result != CPNATIVE_OK && result != CPNATIVE_EINTR) + { + JCL_ThrowException (env, CONNECT_EXCEPTION, + cpnative_getErrorString (result)); + return; + } + } + while (result != CPNATIVE_OK); + + DBG ("_javanet_connect(): Connected successfully\n"); + + /* Populate instance variables */ + result = cpnet_getLocalAddr (env, fd, &local_addr); + if (result != CPNATIVE_OK) + { + cpnet_freeAddress(env, netaddr); + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_close (env, fd); + return; + } + + _javanet_create_localfd (env, this, stream); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_freeAddress(env, netaddr); + cpnet_freeAddress(env, local_addr); + cpnet_close (env, fd); + return; + } + DBG ("_javanet_connect(): Created fd\n"); + + if (stream) + _javanet_set_int_field (env, this, "java/net/SocketImpl", "localport", + cpnet_addressGetPort(local_addr)); + else + _javanet_set_int_field (env, this, "java/net/DatagramSocketImpl", + "localPort", cpnet_addressGetPort(local_addr)); + + cpnet_freeAddress (env, local_addr); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_freeAddress(env, netaddr); + cpnet_close (env, fd); + return; + } + DBG ("_javanet_connect(): Set the local port\n"); + + result = cpnet_getRemoteAddr (env, fd, &remote_addr); + if (result != CPNATIVE_OK) + { + cpnet_freeAddress(env, netaddr); + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_close (env, fd); + return; + } + + if (stream) + { + if (cpnet_isAddressEqual(remote_addr, netaddr)) + { + _javanet_set_remhost_addr (env, this, addr); + } + else + { + _javanet_set_remhost (env, this, remote_addr); + } + cpnet_freeAddress(env, netaddr); + + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. + */ + cpnet_freeAddress (env, remote_addr); + cpnet_close (env, fd); + return; + } + DBG ("_javanet_connect(): Set the remote host\n"); + + _javanet_set_int_field (env, this, "java/net/SocketImpl", "port", + cpnet_addressGetPort(remote_addr)); + cpnet_freeAddress (env, remote_addr); + + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. + */ + cpnet_close (env, fd); + 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 + jint fd; + cpnet_address *tmpaddr; + cpnet_address *local_addr; + int result; + + DBG ("_javanet_bind(): Entering native bind()\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; + } + + cpnet_setReuseAddress (env, fd, 1); + + /* Get the address to connect to */ + tmpaddr = _javanet_get_ip_netaddr (env, addr); + if ((*env)->ExceptionOccurred (env)) + return; + + cpnet_addressSetPort (tmpaddr, port); + result = cpnet_bind(env, fd, tmpaddr); + cpnet_freeAddress (env, tmpaddr); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, BIND_EXCEPTION, + cpnative_getErrorString (result)); + return; + } + DBG ("_javanet_bind(): Past bind\n"); + + /* Update instance variables, specifically the local port number */ + result = cpnet_getLocalAddr (env, fd, &local_addr); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + return; + } + + if (stream) + _javanet_set_int_field (env, this, "java/net/SocketImpl", + "localport", cpnet_addressGetPort (local_addr)); + else + _javanet_set_int_field (env, this, "java/net/DatagramSocketImpl", + "localPort", cpnet_addressGetPort (local_addr)); + DBG ("_javanet_bind(): Past update port number\n"); + + cpnet_freeAddress (env, local_addr); + + 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 */ + result = cpnet_listen (env, fd, queuelen); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + 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; + cpnet_address *remote_addr, *local_addr; + + /* 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 + { + result = cpnet_accept (env, fd, &newfd); + if (result != CPNATIVE_OK && result != CPNATIVE_EINTR) + { + if (result == ETIMEDOUT || result == EAGAIN) + JCL_ThrowException (env, "java/net/SocketTimeoutException", + "Accept operation timed out"); + else + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + return; + } + } + while (result != CPNATIVE_OK); + + /* Reset the inherited timeout. */ + cpnet_setSocketTimeout (env, newfd, 0); + + /* 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 + { + result = cpnet_close (env, newfd); + if (result != CPNATIVE_OK && result != CPNATIVE_EINTR) + return; + } + while (result != CPNATIVE_OK); + return; + } + + result = cpnet_getLocalAddr (env, newfd, &local_addr); + if (result != CPNATIVE_OK) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_close (env, newfd); + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + return; + } + + _javanet_create_localfd (env, impl, 1); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_freeAddress (env, local_addr); + cpnet_close (env, newfd); + return; + } + + _javanet_set_int_field (env, impl, "java/net/SocketImpl", "localport", + cpnet_addressGetPort (local_addr)); + cpnet_freeAddress (env, local_addr); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_close (env, newfd); + return; + } + + result = cpnet_getRemoteAddr (env, newfd, &remote_addr); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_close (env, newfd); + return; + } + + _javanet_set_remhost (env, impl, remote_addr); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_close (env, newfd); + cpnet_freeAddress (env, remote_addr); + return; + } + + _javanet_set_int_field (env, impl, "java/net/SocketImpl", "port", + cpnet_addressGetPort (remote_addr)); + cpnet_freeAddress (env, remote_addr); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + cpnet_close (env, newfd); + 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, cpnet_address **addr) +{ +#ifndef WITHOUT_NETWORK + int fd; + jbyte *p; + cpnet_address *from_addr; + jint received_bytes; + int result; + + 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_addr = NULL; + do + { + if (addr != NULL) + { + result = cpnet_recvFrom (env, fd, p + offset, len, &from_addr, &received_bytes); + } + else + { + result = cpnet_recv (env, fd, p + offset, len, &received_bytes); + } + } + while (result == CPNATIVE_EINTR); + if (result != 0) + { + if (result == EAGAIN || result == ETIMEDOUT) + JCL_ThrowException (env, "java/net/SocketTimeoutException", "Receive operation timed out"); + else + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + + /* 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_addr; + } + + /* 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, + cpnet_address *addr) +{ +#ifndef WITHOUT_NETWORK + int fd; + jbyte *p; + jint bytes_sent; + 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_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 == NULL) + { + DBG ("_javanet_sendto(): Sending....\n"); + result = cpnet_send (env, fd, p + offset, len, &bytes_sent); + } + else + { + DBG ("_javanet_sendto(): Sending....\n"); + result = cpnet_sendTo (env, fd, p + offset, len, addr, &bytes_sent); + } + + if (result == EDESTADDRREQ) + { + JCL_ThrowException (env, NULL_EXCEPTION, + "Socket is not connected and no address is given"); + break; + } + + if (bytes_sent < 0) + { + if (result != CPNATIVE_EINTR) + { + JCL_ThrowException (env, IO_EXCEPTION, + cpnative_getErrorString (result)); + 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; + cpnet_address * address; + int result = CPNATIVE_OK; + + /* 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 */ + 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; + + result = cpnet_setSocketTCPNoDelay (env, fd, optval); + 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 */ + result = cpnet_setLinger (env, fd, JNI_FALSE, 0); + } + 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; + + result = cpnet_setLinger(env, fd, JNI_TRUE, optval); + } + break; + + /* SO_TIMEOUT case. Val will be an integer with the new value */ + /* Not writable on Linux */ + case SOCKOPT_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; + + result = cpnet_setSocketTimeout (env, fd, optval); + 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) + result = cpnet_setSendBuf (env, fd, optval); + else + result = cpnet_setRecvBuf (env, fd, optval); + 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; + + result = cpnet_setTTL (env, fd, optval); + break; + + /* Multicast Interface case - val is InetAddress object */ + case SOCKOPT_IP_MULTICAST_IF: + address = _javanet_get_ip_netaddr (env, val); + + if ((*env)->ExceptionOccurred (env)) + return; + + result = cpnet_setMulticastIF (env, fd, address); + cpnet_freeAddress (env, address); + 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; + + result = cpnet_setReuseAddress (env, fd, optval); + 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; + + result = cpnet_setKeepAlive (env, fd, optval); + 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 != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + 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; + cpnet_address *address; + int result; + jobject obj; + + /* 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: + result = cpnet_getSocketTCPNoDelay (env, fd, &optval); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + 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: + result = cpnet_getLinger (env, fd, &flag, &optval); + + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + return (0); + } + + if (flag) + return (_javanet_create_integer (env, optval)); + else + return (_javanet_create_boolean (env, JNI_FALSE)); + + break; + + /* SO_TIMEOUT case. Return an Integer object with the timeout value */ + case SOCKOPT_SO_TIMEOUT: + result = cpnet_getSocketTimeout (env, fd, &optval); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + return (0); + } + return (_javanet_create_integer (env, optval)); + break; + + case SOCKOPT_SO_SNDBUF: + case SOCKOPT_SO_RCVBUF: + if (option_id == SOCKOPT_SO_SNDBUF) + result = cpnet_getSendBuf (env, fd, &optval); + else + result = cpnet_getRecvBuf (env, fd, &optval); + + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + 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: + result = cpnet_getTTL (env, fd, &optval); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + return (0); + } + + return (_javanet_create_integer (env, optval)); + break; + + /* Multicast interface case */ + case SOCKOPT_IP_MULTICAST_IF: + result = cpnet_getMulticastIF (env, fd, &address); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + return (0); + } + + obj = _javanet_create_inetaddress (env, address); + cpnet_freeAddress (env, address); + + return obj; + break; + + case SOCKOPT_SO_BINDADDR: + result = cpnet_getLocalAddr (env, fd, &address); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + return (0); + } + + obj = _javanet_create_inetaddress (env, address); + cpnet_freeAddress (env, address); + + return obj; + break; + + case SOCKOPT_SO_REUSEADDR: + result = cpnet_getReuseAddress (env, fd, &optval); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + return (0); + } + + if (optval) + return _javanet_create_boolean (env, JNI_TRUE); + else + return _javanet_create_boolean (env, JNI_FALSE); + + break; + + case SOCKOPT_SO_KEEPALIVE: + result = cpnet_getKeepAlive (env, fd, &optval); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + 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 result; + 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. */ + result = cpnet_shutdown (env, fd, CPNET_SHUTDOWN_READ); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + return; + } +} + +void +_javanet_shutdownOutput (JNIEnv * env, jobject this) +{ + int fd; + 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; + } + + /* Shutdown output stream of socket. */ + result = cpnet_shutdown (env, fd, CPNET_SHUTDOWN_WRITE); + if (result != CPNATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + cpnative_getErrorString (result)); + return; + } +} + +/* end of file */ -- cgit v1.2.3