--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/OSNetworkSystem.cpp Fri Nov 20 19:29:42 2009 +0100
@@ -0,0 +1,3688 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ *
+ * Sipdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This source code 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 this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define LOG_TAG "OSNetworkSystem"
+
+#include <android/log.h>
+#include "jni.h"
+#include "errno.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+
+//#include <cutils/properties.h>
+//#include <cutils/adb_networking.h>
+//#include <utils/LogSocket.h>
+//#include "AndroidSystemNatives.h"
+
+/**
+ * @name Socket Errors
+ * Error codes for socket operations
+ *
+ * @internal SOCKERR* range from -200 to -299 avoid overlap
+ */
+#define SOCKERR_BADSOCKET -200 /* generic error */
+#define SOCKERR_NOTINITIALIZED -201 /* socket library uninitialized */
+#define SOCKERR_BADAF -202 /* bad address family */
+#define SOCKERR_BADPROTO -203 /* bad protocol */
+#define SOCKERR_BADTYPE -204 /* bad type */
+#define SOCKERR_SYSTEMBUSY -205 /* system busy handling requests */
+#define SOCKERR_SYSTEMFULL -206 /* too many sockets */
+#define SOCKERR_NOTCONNECTED -207 /* socket is not connected */
+#define SOCKERR_INTERRUPTED -208 /* the call was cancelled */
+#define SOCKERR_TIMEOUT -209 /* the operation timed out */
+#define SOCKERR_CONNRESET -210 /* the connection was reset */
+#define SOCKERR_WOULDBLOCK -211 /* the socket is marked as nonblocking operation would block */
+#define SOCKERR_ADDRNOTAVAIL -212 /* address not available */
+#define SOCKERR_ADDRINUSE -213 /* address already in use */
+#define SOCKERR_NOTBOUND -214 /* the socket is not bound */
+#define SOCKERR_UNKNOWNSOCKET -215 /* resolution of fileDescriptor to socket failed */
+#define SOCKERR_INVALIDTIMEOUT -216 /* the specified timeout is invalid */
+#define SOCKERR_FDSETFULL -217 /* Unable to create an FDSET */
+#define SOCKERR_TIMEVALFULL -218 /* Unable to create a TIMEVAL */
+#define SOCKERR_REMSOCKSHUTDOWN -219 /* The remote socket has shutdown gracefully */
+#define SOCKERR_NOTLISTENING -220 /* listen() was not invoked prior to accept() */
+#define SOCKERR_NOTSTREAMSOCK -221 /* The socket does not support connection-oriented service */
+#define SOCKERR_ALREADYBOUND -222 /* The socket is already bound to an address */
+#define SOCKERR_NBWITHLINGER -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
+#define SOCKERR_ISCONNECTED -224 /* The socket is already connected */
+#define SOCKERR_NOBUFFERS -225 /* No buffer space is available */
+#define SOCKERR_HOSTNOTFOUND -226 /* Authoritative Answer Host not found */
+#define SOCKERR_NODATA -227 /* Valid name, no data record of requested type */
+#define SOCKERR_BOUNDORCONN -228 /* The socket has not been bound or is already connected */
+#define SOCKERR_OPNOTSUPP -229 /* The socket does not support the operation */
+#define SOCKERR_OPTUNSUPP -230 /* The socket option is not supported */
+#define SOCKERR_OPTARGSINVALID -231 /* The socket option arguments are invalid */
+#define SOCKERR_SOCKLEVELINVALID -232 /* The socket level is invalid */
+#define SOCKERR_TIMEOUTFAILURE -233
+#define SOCKERR_SOCKADDRALLOCFAIL -234 /* Unable to allocate the sockaddr structure */
+#define SOCKERR_FDSET_SIZEBAD -235 /* The calculated maximum size of the file descriptor set is bad */
+#define SOCKERR_UNKNOWNFLAG -236 /* The flag is unknown */
+#define SOCKERR_MSGSIZE -237 /* The datagram was too big to fit the specified buffer & was truncated. */
+#define SOCKERR_NORECOVERY -238 /* The operation failed with no recovery possible */
+#define SOCKERR_ARGSINVALID -239 /* The arguments are invalid */
+#define SOCKERR_BADDESC -240 /* The socket argument is not a valid file descriptor */
+#define SOCKERR_NOTSOCK -241 /* The socket argument is not a socket */
+#define SOCKERR_HOSTENTALLOCFAIL -242 /* Unable to allocate the hostent structure */
+#define SOCKERR_TIMEVALALLOCFAIL -243 /* Unable to allocate the timeval structure */
+#define SOCKERR_LINGERALLOCFAIL -244 /* Unable to allocate the linger structure */
+#define SOCKERR_IPMREQALLOCFAIL -245 /* Unable to allocate the ipmreq structure */
+#define SOCKERR_FDSETALLOCFAIL -246 /* Unable to allocate the fdset structure */
+#define SOCKERR_OPFAILED -247 /* Operation failed */
+#define SOCKERR_VALUE_NULL -248 /* The value indexed was NULL */
+#define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
+#define SOCKERR_ENETUNREACH -250 /* network is not reachable */
+#define SOCKERR_EACCES -251 /* permissions do not allow action on socket */
+#define SOCKERR_EHOSTUNREACH -252 /* no route to host */
+#define SOCKERR_EPIPE -253 /* broken pipe */
+
+#define JAVASOCKOPT_TCP_NODELAY 1
+#define JAVASOCKOPT_IP_TOS 3
+#define JAVASOCKOPT_SO_REUSEADDR 4
+#define JAVASOCKOPT_SO_KEEPALIVE 8
+#define JAVASOCKOPT_MCAST_TIME_TO_LIVE 10 /* Currently unused */
+#define JAVASOCKOPT_SO_BINDADDR 15
+#define JAVASOCKOPT_MCAST_INTERFACE 16
+#define JAVASOCKOPT_MCAST_TTL 17
+#define JAVASOCKOPT_IP_MULTICAST_LOOP 18
+#define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
+#define JAVASOCKOPT_MCAST_DROP_MEMBERSHIP 20
+#define JAVASOCKOPT_IP_MULTICAST_IF2 31
+#define JAVASOCKOPT_SO_BROADCAST 32
+#define JAVASOCKOPT_SO_LINGER 128
+#define JAVASOCKOPT_REUSEADDR_AND_REUSEPORT 10001
+#define JAVASOCKOPT_SO_SNDBUF 4097
+#define JAVASOCKOPT_SO_RCVBUF 4098
+#define JAVASOCKOPT_SO_RCVTIMEOUT 4102
+#define JAVASOCKOPT_SO_OOBINLINE 4099
+
+/* constants for calling multi-call functions */
+#define SOCKET_STEP_START 10
+#define SOCKET_STEP_CHECK 20
+#define SOCKET_STEP_DONE 30
+
+#define BROKEN_MULTICAST_IF 1
+#define BROKEN_MULTICAST_TTL 2
+#define BROKEN_TCP_NODELAY 4
+
+#define SOCKET_CONNECT_STEP_START 0
+#define SOCKET_CONNECT_STEP_CHECK 1
+
+#define SOCKET_OP_NONE 0
+#define SOCKET_OP_READ 1
+#define SOCKET_OP_WRITE 2
+#define SOCKET_READ_WRITE 3
+
+#define SOCKET_MSG_PEEK 1
+#define SOCKET_MSG_OOB 2
+
+#define SOCKET_NOFLAGS 0
+
+#undef BUFFERSIZE
+#define BUFFERSIZE 2048
+
+// wait for 500000 usec = 0.5 second
+#define SEND_RETRY_TIME 500000
+
+
+struct CachedFields {
+ jfieldID fd_descriptor;
+ jclass iaddr_class;
+ jmethodID iaddr_class_init;
+ jmethodID iaddr_getbyaddress;
+ jfieldID iaddr_ipaddress;
+ jclass genericipmreq_class;
+ jclass integer_class;
+ jmethodID integer_class_init;
+ jfieldID integer_class_value;
+ jclass boolean_class;
+ jmethodID boolean_class_init;
+ jfieldID boolean_class_value;
+ jclass byte_class;
+ jmethodID byte_class_init;
+ jfieldID byte_class_value;
+ jclass string_class;
+ jmethodID string_class_init;
+ jfieldID socketimpl_address;
+ jfieldID socketimpl_port;
+ jclass dpack_class;
+ jfieldID dpack_address;
+ jfieldID dpack_port;
+ jfieldID dpack_length;
+ jclass fd_class;
+ jfieldID descriptor;
+} gCachedFields;
+
+static int useAdbNetworking = 0;
+
+/* needed for connecting with timeout */
+typedef struct selectFDSet {
+ int nfds;
+ int sock;
+ fd_set writeSet;
+ fd_set readSet;
+ fd_set exceptionSet;
+} selectFDSet;
+
+static const char * netLookupErrorString(int anErrorNum);
+
+#define log_socket_close(a,b)
+#define log_socket_connect(a,b,c)
+#define add_send_stats(a,b)
+#define add_recv_stats(a,b)
+#define adb_networking_connect_fd(a,b) 0
+#define adb_networking_gethostbyname(a,b) 0
+#define PROPERTY_VALUE_MAX 1
+#define property_get(a,b,c)
+#define assert(a)
+/*
+ * Throw an exception with the specified class and an optional message.
+ */
+int jniThrowException(JNIEnv* env, const char* className, const char* msg)
+{
+ jclass exceptionClass;
+
+ exceptionClass = env->FindClass(className);
+ if (exceptionClass == NULL) {
+// LOGE("Unable to find exception class %s\n", className);
+ assert(0); /* fatal during dev; should always be fatal? */
+ return -1;
+ }
+
+ if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {
+// LOGE("Failed throwing '%s' '%s'\n", className, msg);
+ assert(!"failed to throw");
+ }
+ return 0;
+}
+
+/*
+ * Internal helper function.
+ *
+ * Get the file descriptor.
+ */
+static inline int getFd(JNIEnv* env, jobject obj)
+{
+ return env->GetIntField(obj, gCachedFields.descriptor);
+}
+
+/*
+ * Internal helper function.
+ *
+ * Set the file descriptor.
+ */
+static inline void setFd(JNIEnv* env, jobject obj, jint value)
+{
+ env->SetIntField(obj, gCachedFields.descriptor, value);
+}
+
+/*
+ * For JNIHelp.c
+ * Get an int file descriptor from a java.io.FileDescriptor
+ */
+
+static int jniGetFDFromFileDescriptor (JNIEnv* env, jobject fileDescriptor) {
+
+ return getFd(env, fileDescriptor);
+}
+
+/*
+ * For JNIHelp.c
+ * Set the descriptor of a java.io.FileDescriptor
+ */
+
+static void jniSetFileDescriptorOfFD (JNIEnv* env, jobject fileDescriptor, int value) {
+
+ setFd(env, fileDescriptor, value);
+}
+
+/**
+ * Throws an SocketException with the message affiliated with the errorCode.
+ */
+static void throwSocketException(JNIEnv *env, int errorCode) {
+ jniThrowException(env, "java/net/SocketException",
+ netLookupErrorString(errorCode));
+}
+
+/**
+ * Throws an IOException with the given message.
+ */
+static void throwIOExceptionStr(JNIEnv *env, const char *message) {
+ jniThrowException(env, "java/io/IOException", message);
+}
+
+/**
+ * Throws a NullPointerException.
+ */
+static void throwNullPointerException(JNIEnv *env) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+}
+
+/**
+ * Converts a 4-byte array to a native address structure. Throws a
+ * NullPointerException or an IOException in case of error. This is
+ * signaled by a return value of -1. The normal return value is 0.
+ */
+static int javaAddressToStructIn(
+ JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
+
+ memset(address, 0, sizeof(address));
+
+ if (java_address == NULL) {
+ return -1;
+ }
+
+ if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
+ return -1;
+ }
+
+ jbyte * java_address_bytes
+ = env->GetByteArrayElements(java_address, NULL);
+
+ memcpy(&(address->s_addr),
+ java_address_bytes,
+ sizeof(address->s_addr));
+
+ env->ReleaseByteArrayElements(java_address, java_address_bytes, JNI_ABORT);
+
+ return 0;
+}
+
+/**
+ * Converts a native address structure to a 4-byte array. Throws a
+ * NullPointerException or an IOException in case of error. This is
+ * signaled by a return value of -1. The normal return value is 0.
+ */
+static int structInToJavaAddress(
+ JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
+
+ if (java_address == NULL) {
+ return -1;
+ }
+
+ if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
+ return -1;
+ }
+
+ jbyte *java_address_bytes;
+
+ java_address_bytes = env->GetByteArrayElements(java_address, NULL);
+
+ memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
+
+ env->ReleaseByteArrayElements(java_address, java_address_bytes, 0);
+
+ return 0;
+}
+
+/**
+ * Converts a native address structure to an InetAddress object.
+ * Throws a NullPointerException or an IOException in case of
+ * error. This is signaled by a return value of -1. The normal
+ * return value is 0.
+ */
+static int socketAddressToInetAddress(JNIEnv *env,
+ struct sockaddr_in *sockaddress, jobject inetaddress, int *port) {
+
+ jbyteArray ipaddress;
+ int result;
+
+ ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
+ gCachedFields.iaddr_ipaddress);
+
+ if (structInToJavaAddress(env, &sockaddress->sin_addr, ipaddress) < 0) {
+ return -1;
+ }
+
+ *port = ntohs(sockaddress->sin_port);
+
+ return 0;
+}
+
+/**
+ * Converts an InetAddress object to a native address structure.
+ * Throws a NullPointerException or an IOException in case of
+ * error. This is signaled by a return value of -1. The normal
+ * return value is 0.
+ */
+static int inetAddressToSocketAddress(JNIEnv *env,
+ jobject inetaddress, int port, struct sockaddr_in *sockaddress) {
+
+ jbyteArray ipaddress;
+ int result;
+
+ ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
+ gCachedFields.iaddr_ipaddress);
+
+ memset(sockaddress, 0, sizeof(sockaddress));
+
+ sockaddress->sin_family = AF_INET;
+ sockaddress->sin_port = htons(port);
+
+ if (javaAddressToStructIn(env, ipaddress, &(sockaddress->sin_addr)) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
+ jbyteArray bytes;
+ int success;
+
+ bytes = env->NewByteArray(4);
+
+ if (bytes == NULL) {
+ return NULL;
+ }
+
+ if (structInToJavaAddress(env, address, bytes) < 0) {
+ return NULL;
+ }
+
+ return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_getbyaddress, bytes);
+}
+
+/**
+ * Answer a new java.lang.Boolean object.
+ *
+ * @param env pointer to the JNI library
+ * @param anInt the Boolean constructor argument
+ *
+ * @return the new Boolean
+ */
+
+static jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
+ jclass tempClass;
+ jmethodID tempMethod;
+
+ tempClass = gCachedFields.boolean_class;
+ tempMethod = gCachedFields.boolean_class_init;
+ return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
+}
+
+/**
+ * Answer a new java.lang.Byte object.
+ *
+ * @param env pointer to the JNI library
+ * @param anInt the Byte constructor argument
+ *
+ * @return the new Byte
+ */
+
+static jobject newJavaLangByte(JNIEnv * env, jbyte val) {
+ jclass tempClass;
+ jmethodID tempMethod;
+
+ tempClass = gCachedFields.byte_class;
+ tempMethod = gCachedFields.byte_class_init;
+ return env->NewObject(tempClass, tempMethod, val);
+}
+
+/**
+ * Answer a new java.lang.Integer object.
+ *
+ * @param env pointer to the JNI library
+ * @param anInt the Integer constructor argument
+ *
+ * @return the new Integer
+ */
+
+static jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
+ jclass tempClass;
+ jmethodID tempMethod;
+
+ tempClass = gCachedFields.integer_class;
+ tempMethod = gCachedFields.integer_class_init;
+ return env->NewObject(tempClass, tempMethod, anInt);
+}
+
+/**
+ * Answer a new java.lang.String object.
+ *
+ * @param env pointer to the JNI library
+ * @param anInt the byte[] constructor argument
+ *
+ * @return the new String
+ */
+
+static jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
+ jclass tempClass;
+ jmethodID tempMethod;
+
+ tempClass = gCachedFields.string_class;
+ tempMethod = gCachedFields.string_class_init;
+ return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
+}
+
+/**
+ * Query OS for timestamp.
+ * Retrieve the current value of system clock and convert to milliseconds.
+ *
+ * @param[in] portLibrary The port library.
+ *
+ * @return 0 on failure, time value in milliseconds on success.
+ * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
+ *
+ * technically, this should return I_64 since both timeval.tv_sec and
+ * timeval.tv_usec are long
+ */
+
+static int time_msec_clock() {
+ struct timeval tp;
+ struct timezone tzp;
+
+ gettimeofday(&tp, &tzp);
+ return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+}
+
+/**
+ * check if the passed sockaddr_in struct contains a localhost address
+ *
+ * @param[in] address pointer to the address to check
+ *
+ * @return 0 if the passed address isn't a localhost address
+ */
+static int isLocalhost(struct sockaddr_in *address) {
+ // return address == 127.0.0.1
+ return (unsigned int) address->sin_addr.s_addr == 16777343;
+}
+
+/**
+ * Answer the errorString corresponding to the errorNumber, if available.
+ * This function will answer a default error string, if the errorNumber is not
+ * recognized.
+ *
+ * This function will have to be reworked to handle internationalization
+ * properly, removing the explicit strings.
+ *
+ * @param anErrorNum the error code to resolve to a human readable string
+ *
+ * @return a human readable error string
+ */
+
+static const char * netLookupErrorString(int anErrorNum) {
+ switch (anErrorNum) {
+ case SOCKERR_BADSOCKET:
+ return "Bad socket";
+ case SOCKERR_NOTINITIALIZED:
+ return "Socket library uninitialized";
+ case SOCKERR_BADAF:
+ return "Bad address family";
+ case SOCKERR_BADPROTO:
+ return "Bad protocol";
+ case SOCKERR_BADTYPE:
+ return "Bad type";
+ case SOCKERR_SYSTEMBUSY:
+ return "System busy handling requests";
+ case SOCKERR_SYSTEMFULL:
+ return "Too many sockets allocated";
+ case SOCKERR_NOTCONNECTED:
+ return "Socket is not connected";
+ case SOCKERR_INTERRUPTED:
+ return "The system call was cancelled";
+ case SOCKERR_TIMEOUT:
+ return "The operation timed out";
+ case SOCKERR_CONNRESET:
+ return "The connection was reset";
+ case SOCKERR_WOULDBLOCK:
+ return "The nonblocking operation would block";
+ case SOCKERR_ADDRNOTAVAIL:
+ return "The address is not available";
+ case SOCKERR_ADDRINUSE:
+ return "The address is already in use";
+ case SOCKERR_NOTBOUND:
+ return "The socket is not bound";
+ case SOCKERR_UNKNOWNSOCKET:
+ return "Resolution of the FileDescriptor to socket failed";
+ case SOCKERR_INVALIDTIMEOUT:
+ return "The specified timeout is invalid";
+ case SOCKERR_FDSETFULL:
+ return "Unable to create an FDSET";
+ case SOCKERR_TIMEVALFULL:
+ return "Unable to create a TIMEVAL";
+ case SOCKERR_REMSOCKSHUTDOWN:
+ return "The remote socket has shutdown gracefully";
+ case SOCKERR_NOTLISTENING:
+ return "Listen() was not invoked prior to accept()";
+ case SOCKERR_NOTSTREAMSOCK:
+ return "The socket does not support connection-oriented service";
+ case SOCKERR_ALREADYBOUND:
+ return "The socket is already bound to an address";
+ case SOCKERR_NBWITHLINGER:
+ return "The socket is marked non-blocking & SO_LINGER is non-zero";
+ case SOCKERR_ISCONNECTED:
+ return "The socket is already connected";
+ case SOCKERR_NOBUFFERS:
+ return "No buffer space is available";
+ case SOCKERR_HOSTNOTFOUND:
+ return "Authoritative Answer Host not found";
+ case SOCKERR_NODATA:
+ return "Valid name, no data record of requested type";
+ case SOCKERR_BOUNDORCONN:
+ return "The socket has not been bound or is already connected";
+ case SOCKERR_OPNOTSUPP:
+ return "The socket does not support the operation";
+ case SOCKERR_OPTUNSUPP:
+ return "The socket option is not supported";
+ case SOCKERR_OPTARGSINVALID:
+ return "The socket option arguments are invalid";
+ case SOCKERR_SOCKLEVELINVALID:
+ return "The socket level is invalid";
+ case SOCKERR_TIMEOUTFAILURE:
+ return "The timeout operation failed";
+ case SOCKERR_SOCKADDRALLOCFAIL:
+ return "Failed to allocate address structure";
+ case SOCKERR_FDSET_SIZEBAD:
+ return "The calculated maximum size of the file descriptor set is bad";
+ case SOCKERR_UNKNOWNFLAG:
+ return "The flag is unknown";
+ case SOCKERR_MSGSIZE:
+ return "The datagram was too big to fit the specified buffer, so truncated";
+ case SOCKERR_NORECOVERY:
+ return "The operation failed with no recovery possible";
+ case SOCKERR_ARGSINVALID:
+ return "The arguments are invalid";
+ case SOCKERR_BADDESC:
+ return "The socket argument is not a valid file descriptor";
+ case SOCKERR_NOTSOCK:
+ return "The socket argument is not a socket";
+ case SOCKERR_HOSTENTALLOCFAIL:
+ return "Unable to allocate the hostent structure";
+ case SOCKERR_TIMEVALALLOCFAIL:
+ return "Unable to allocate the timeval structure";
+ case SOCKERR_LINGERALLOCFAIL:
+ return "Unable to allocate the linger structure";
+ case SOCKERR_IPMREQALLOCFAIL:
+ return "Unable to allocate the ipmreq structure";
+ case SOCKERR_FDSETALLOCFAIL:
+ return "Unable to allocate the fdset structure";
+ case SOCKERR_OPFAILED:
+ return "Operation failed";
+ case SOCKERR_CONNECTION_REFUSED:
+ return "Connection refused";
+ case SOCKERR_ENETUNREACH:
+ return "Network unreachable";
+ case SOCKERR_EHOSTUNREACH:
+ return "No route to host";
+ case SOCKERR_EPIPE:
+ return "Broken pipe";
+ case SOCKERR_EACCES:
+ return "Permission denied (maybe missing INTERNET permission)";
+
+ default:
+// LOGE("unknown socket error %d", anErrorNum);
+ return "unknown error";
+ }
+}
+
+static int convertError(int errorCode) {
+ switch (errorCode) {
+ case EBADF:
+ return SOCKERR_BADDESC;
+ case ENOBUFS:
+ return SOCKERR_NOBUFFERS;
+ case EOPNOTSUPP:
+ return SOCKERR_OPNOTSUPP;
+ case ENOPROTOOPT:
+ return SOCKERR_OPTUNSUPP;
+ case EINVAL:
+ return SOCKERR_SOCKLEVELINVALID;
+ case ENOTSOCK:
+ return SOCKERR_NOTSOCK;
+ case EINTR:
+ return SOCKERR_INTERRUPTED;
+ case ENOTCONN:
+ return SOCKERR_NOTCONNECTED;
+ case EAFNOSUPPORT:
+ return SOCKERR_BADAF;
+ /* note: CONNRESET not included because it has the same
+ * value as ECONNRESET and they both map to SOCKERR_CONNRESET */
+ case ECONNRESET:
+ return SOCKERR_CONNRESET;
+ case EAGAIN:
+ return SOCKERR_WOULDBLOCK;
+ case EPROTONOSUPPORT:
+ return SOCKERR_BADPROTO;
+ case EFAULT:
+ return SOCKERR_ARGSINVALID;
+ case ETIMEDOUT:
+ return SOCKERR_TIMEOUT;
+ case ECONNREFUSED:
+ return SOCKERR_CONNECTION_REFUSED;
+ case ENETUNREACH:
+ return SOCKERR_ENETUNREACH;
+ case EACCES:
+ return SOCKERR_EACCES;
+ case EPIPE:
+ return SOCKERR_EPIPE;
+ case EHOSTUNREACH:
+ return SOCKERR_EHOSTUNREACH;
+ case EADDRINUSE:
+ return SOCKERR_ADDRINUSE;
+ case EADDRNOTAVAIL:
+ return SOCKERR_ADDRNOTAVAIL;
+ case EMSGSIZE:
+ return SOCKERR_MSGSIZE;
+ default:
+// LOGE("unclassified errno %d (%s)", errorCode, strerror(errorCode));
+ return SOCKERR_OPFAILED;
+ }
+}
+
+static int sockSelect(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout) {
+
+ int result = select(nfds, readfds, writefds, exceptfds, timeout);
+
+ if (result < 0) {
+ if (errno == EINTR) {
+ result = SOCKERR_INTERRUPTED;
+ } else {
+ result = SOCKERR_OPFAILED;
+ }
+ } else if (result == 0) {
+ result = SOCKERR_TIMEOUT;
+ }
+ return result;
+}
+
+#define SELECT_READ_TYPE 0
+#define SELECT_WRITE_TYPE 1
+
+static int selectWait(int handle, int uSecTime, int type) {
+ fd_set fdset;
+ struct timeval time, *timePtr;
+ int result = 0;
+ int size = handle + 1;
+
+ FD_ZERO(&fdset);
+ FD_SET(handle, &fdset);
+
+ if (0 <= uSecTime) {
+ /* Use a timeout if uSecTime >= 0 */
+ memset(&time, 0, sizeof(time));
+ time.tv_usec = uSecTime;
+ timePtr = &time;
+ } else {
+ /* Infinite timeout if uSecTime < 0 */
+ timePtr = NULL;
+ }
+
+ if (type == SELECT_READ_TYPE) {
+ result = sockSelect(size, &fdset, NULL, NULL, timePtr);
+ } else {
+ result = sockSelect(size, NULL, &fdset, NULL, timePtr);
+ }
+ return result;
+}
+
+static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int type) {
+ /* now try reading the socket for the timespan timeout.
+ * if timeout is 0 try forever until the soclets gets ready or until an
+ * exception occurs.
+ */
+ int pollTimeoutUSec = 100000, pollMsec = 100;
+ int finishTime = 0;
+ int timeLeft = timeout;
+ int hasTimeout = timeout > 0 ? 1 : 0;
+ int result = 0;
+ int handle;
+
+ if (hasTimeout) {
+ finishTime = time_msec_clock() + timeout;
+ }
+
+ int poll = 1;
+
+ while (poll) { /* begin polling loop */
+
+ /*
+ * Fetch the handle every time in case the socket is closed.
+ */
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_INTERRUPTED);
+ return -1;
+ }
+
+ if (hasTimeout) {
+
+ if (timeLeft - 10 < pollMsec) {
+ pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
+ }
+
+ result = selectWait(handle, pollTimeoutUSec, type);
+
+ /*
+ * because we are polling at a time smaller than timeout
+ * (presumably) lets treat an interrupt and timeout the same - go
+ * see if we're done timewise, and then just try again if not.
+ */
+ if (SOCKERR_TIMEOUT == result ||
+ SOCKERR_INTERRUPTED == result) {
+
+ timeLeft = finishTime - time_msec_clock();
+
+ if (timeLeft <= 0) {
+ /*
+ * Always throw the "timeout" message because that is
+ * effectively what has happened, even if we happen to
+ * have been interrupted.
+ */
+ jniThrowException(env, "java/net/SocketTimeoutException",
+ netLookupErrorString(SOCKERR_TIMEOUT));
+ } else {
+ continue; // try again
+ }
+
+ } else if (0 > result) {
+ log_socket_close(handle, result);
+ throwSocketException(env, result);
+ }
+ poll = 0;
+
+ } else { /* polling with no timeout (why would you do this?)*/
+
+ result = selectWait(handle, pollTimeoutUSec, type);
+
+ /*
+ * if interrupted (or a timeout) just retry
+ */
+ if (SOCKERR_TIMEOUT == result ||
+ SOCKERR_INTERRUPTED == result) {
+
+ continue; // try again
+ } else if (0 > result) {
+ log_socket_close(handle, result);
+ throwSocketException(env, result);
+ }
+ poll = 0;
+ }
+ } /* end polling loop */
+
+ return result;
+}
+
+/**
+ * A helper method, to set the connect context to a Long object.
+ *
+ * @param env pointer to the JNI library
+ * @param longclass Java Long Object
+ */
+void setConnectContext(JNIEnv *env,jobject longclass,jbyte * context) {
+ jclass descriptorCLS;
+ jfieldID descriptorFID;
+ descriptorCLS = env->FindClass("java/lang/Long");
+ descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+ env->SetLongField(longclass, descriptorFID, (jlong)((jint)context));
+};
+
+/**
+ * A helper method, to get the connect context.
+ *
+ * @param env pointer to the JNI library
+ * @param longclass Java Long Object
+ */
+jbyte *getConnectContext(JNIEnv *env, jobject longclass) {
+ jclass descriptorCLS;
+ jfieldID descriptorFID;
+ descriptorCLS = env->FindClass("java/lang/Long");
+ descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+ return (jbyte*) ((jint)env->GetLongField(longclass, descriptorFID));
+};
+
+// typical ip checksum
+unsigned short ip_checksum(unsigned short* buffer, int size) {
+ register unsigned short * buf = buffer;
+ register int bufleft = size;
+ register unsigned long sum = 0;
+
+ while (bufleft > 1) {
+ sum = sum + (*buf++);
+ bufleft = bufleft - sizeof(unsigned short );
+ }
+ if (bufleft) {
+ sum = sum + (*(unsigned char*)buf);
+ }
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+
+ return (unsigned short )(~sum);
+}
+
+/**
+ * Establish a connection to a peer with a timeout. This function is called
+ * repeatedly in order to carry out the connect and to allow other tasks to
+ * proceed on certain platforms. The caller must first call with
+ * step = SOCKET_STEP_START, if the result is SOCKERR_NOTCONNECTED it will then
+ * call it with step = CHECK until either another error or 0 is returned to
+ * indicate the connect is complete. Each time the function should sleep for no
+ * more than timeout milliseconds. If the connect succeeds or an error occurs,
+ * the caller must always end the process by calling the function with
+ * step = SOCKET_STEP_DONE
+ *
+ * @param[in] portLibrary The port library.
+ * @param[in] sock pointer to the unconnected local socket.
+ * @param[in] addr pointer to the sockaddr, specifying remote host/port.
+ * @param[in] timeout the timeout in milliseconds. If timeout is negative,
+ * perform a block operation.
+ * @param[in,out] pointer to context pointer. Filled in on first call and then
+ * to be passed into each subsequent call.
+ *
+ * @return 0, if no errors occurred, otherwise the (negative) error code.
+ */
+static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
+ unsigned int timeout, unsigned int step, jbyte *ctxt) {
+ int rc = 0;
+ struct timeval passedTimeout;
+ int errorVal;
+ socklen_t errorValLen = sizeof(int);
+ struct selectFDSet *context = NULL;
+
+ if (SOCKET_STEP_START == step) {
+
+ context = (struct selectFDSet *) ctxt;
+
+ context->sock = handle;
+ context->nfds = handle + 1;
+
+ if (useAdbNetworking && !isLocalhost(&addr)) {
+
+ // LOGD("+connect to address 0x%08x (via adb)",
+ // addr.sin_addr.s_addr);
+ rc = adb_networking_connect_fd(handle, &addr);
+ // LOGD("-connect ret %d errno %d (via adb)", rc, errno);
+
+ } else {
+ log_socket_connect(handle, ntohl(addr.sin_addr.s_addr),
+ ntohs(addr.sin_port));
+ /* set the socket to non-blocking */
+ int block = JNI_TRUE;
+ rc = ioctl(handle, FIONBIO, &block);
+ if (0 != rc) {
+ return convertError(rc);
+ }
+
+ // LOGD("+connect to address 0x%08x (via normal) on handle %d",
+ // addr.sin_addr.s_addr, handle);
+ do {
+ rc = connect(handle, (struct sockaddr *) &addr,
+ sizeof(struct sockaddr));
+ } while (rc < 0 && errno == EINTR);
+ // LOGD("-connect to address 0x%08x (via normal) returned %d",
+ // addr.sin_addr.s_addr, (int) rc);
+
+ }
+
+ if (rc == -1) {
+ rc = errno;
+ switch (rc) {
+ case EINTR:
+ return SOCKERR_ALREADYBOUND;
+ case EAGAIN:
+ case EINPROGRESS:
+ return SOCKERR_NOTCONNECTED;
+ default:
+ return convertError(rc);
+ }
+ }
+
+ /* we connected right off the bat so just return */
+ return rc;
+
+ } else if (SOCKET_STEP_CHECK == step) {
+ /* now check if we have connected yet */
+
+ context = (struct selectFDSet *) ctxt;
+
+ /*
+ * set the timeout value to be used. Because on some unix platforms we
+ * don't get notified when a socket is closed we only sleep for 100ms
+ * at a time
+ */
+ passedTimeout.tv_sec = 0;
+ if (timeout > 100) {
+ passedTimeout.tv_usec = 100 * 1000;
+ } else if ((int)timeout >= 0) {
+ passedTimeout.tv_usec = timeout * 1000;
+ }
+
+ /* initialize the FD sets for the select */
+ FD_ZERO(&(context->exceptionSet));
+ FD_ZERO(&(context->writeSet));
+ FD_ZERO(&(context->readSet));
+ FD_SET(context->sock, &(context->writeSet));
+ FD_SET(context->sock, &(context->readSet));
+ FD_SET(context->sock, &(context->exceptionSet));
+
+ rc = select(context->nfds,
+ &(context->readSet),
+ &(context->writeSet),
+ &(context->exceptionSet),
+ (int)timeout >= 0 ? &passedTimeout : NULL);
+
+ /* if there is at least one descriptor ready to be checked */
+ if (0 < rc) {
+ /* if the descriptor is in the write set we connected or failed */
+ if (FD_ISSET(context->sock, &(context->writeSet))) {
+
+ if (!FD_ISSET(context->sock, &(context->readSet))) {
+ /* ok we have connected ok */
+ return 0;
+ } else {
+ /* ok we have more work to do to figure it out */
+ if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR,
+ &errorVal, &errorValLen) >= 0) {
+ return errorVal ? convertError(errorVal) : 0;
+ } else {
+ return convertError(errno);
+ }
+ }
+ }
+
+ /* if the descriptor is in the exception set the connect failed */
+ if (FD_ISSET(context->sock, &(context->exceptionSet))) {
+ if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal,
+ &errorValLen) >= 0) {
+ return errorVal ? convertError(errorVal) : 0;
+ }
+ rc = errno;
+ return convertError(rc);
+ }
+
+ } else if (rc < 0) {
+ /* something went wrong with the select call */
+ rc = errno;
+
+ /* if it was EINTR we can just try again. Return not connected */
+ if (EINTR == rc) {
+ return SOCKERR_NOTCONNECTED;
+ }
+
+ /* some other error occured so look it up and return */
+ return convertError(rc);
+ }
+
+ /*
+ * if we get here the timeout expired or the connect had not yet
+ * completed just indicate that the connect is not yet complete
+ */
+ return SOCKERR_NOTCONNECTED;
+ } else if (SOCKET_STEP_DONE == step) {
+ /* we are done the connect or an error occured so clean up */
+ if (handle != -1) {
+ int block = JNI_FALSE;
+ ioctl(handle, FIONBIO, &block);
+ }
+ return 0;
+ }
+ return SOCKERR_ARGSINVALID;
+}
+
+/**
+ * Join/Leave the nominated multicast group on the specified socket.
+ * Implemented by setting the multicast 'add membership'/'drop membership'
+ * option at the HY_IPPROTO_IP level on the socket.
+ *
+ * Implementation note for multicast sockets in general:
+ *
+ * - This code is untested, because at the time of this writing multicast can't
+ * be properly tested on Android due to GSM routing restrictions. So it might
+ * or might not work.
+ *
+ * - The REUSEPORT socket option that Harmony employs is not supported on Linux
+ * and thus also not supported on Android. It's is not needed for multicast
+ * to work anyway (REUSEADDR should suffice).
+ *
+ * @param env pointer to the JNI library.
+ * @param socketP pointer to the hysocket to join/leave on.
+ * @param optVal pointer to the InetAddress, the multicast group to join/drop.
+ *
+ * @exception SocketException if an error occurs during the call
+ */
+static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
+ int ignoreIF, int setSockOptVal) {
+ int result;
+ struct ip_mreq ipmreqP;
+ struct sockaddr_in sockaddrP;
+ int length = sizeof(struct ip_mreq);
+ socklen_t lengthIF = sizeof(struct sockaddr_in);
+
+ /*
+ * JNI objects needed to access the information in the optVal oject
+ * passed in. The object passed in is a GenericIPMreq object
+ */
+ jclass cls;
+ jfieldID multiaddrID;
+ jfieldID interfaceAddrID;
+ jobject multiaddr;
+ jobject interfaceAddr;
+
+ /*
+ * check whether we are getting an InetAddress or an Generic IPMreq, for now
+ * we support both so that we will not break the tests
+ */
+ if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
+
+ ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (!ignoreIF) {
+
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockaddrP,
+ &lengthIF);
+
+ if (0 != result) {
+ throwSocketException (env, convertError(errno));
+ return;
+ }
+
+ memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
+ }
+
+ result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
+
+ result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+ if (0 != result) {
+ throwSocketException (env, convertError(errno));
+ return;
+ }
+
+ } else {
+
+ /* we need the multicast address regardless of the type of address */
+ cls = env->GetObjectClass(optVal);
+ multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
+ multiaddr = env->GetObjectField(optVal, multiaddrID);
+
+ result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
+
+ /* we need to use an IP_MREQ as it is an IPV4 address */
+ interfaceAddrID = env->GetFieldID(cls, "interfaceAddr",
+ "Ljava/net/InetAddress;");
+ interfaceAddr = env->GetObjectField(optVal, interfaceAddrID);
+
+ ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ /*
+ * if an interfaceAddr was passed then use that value, otherwise set the
+ * interface to all 0 to indicate the system should select the interface
+ * used
+ */
+ if (!ignoreIF) {
+ if (NULL != interfaceAddr) {
+
+ result = inetAddressToSocketAddress(env, interfaceAddr, 0,
+ &sockaddrP);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
+
+ }
+ }
+
+ /* join/drop the multicast address */
+ result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+ if (0 != result) {
+ throwSocketException (env, convertError(errno));
+ return;
+ }
+ }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
+ jboolean jcl_supports_ipv6) {
+ // LOGD("ENTER oneTimeInitializationImpl of OSNetworkSystem");
+
+ char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
+ char adbConnectedProperty[PROPERTY_VALUE_MAX];
+
+ property_get("android.net.use-adb-networking", useAdbNetworkingProperty, "");
+ property_get("adb.connected", adbConnectedProperty, "");
+
+ if (strlen((char *)useAdbNetworkingProperty) > 0
+ && strlen((char *)adbConnectedProperty) > 0) {
+ useAdbNetworking = 1;
+ }
+
+ memset(&gCachedFields, 0, sizeof(gCachedFields));
+
+ // initializing InetAddress
+
+ jclass iaddrclass = env->FindClass("java/net/InetAddress");
+
+ if (iaddrclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.net.InetAddress");
+ return;
+ }
+
+ gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass);
+
+ jmethodID iaddrclassinit = env->GetMethodID(iaddrclass, "<init>", "()V");
+
+ if (iaddrclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.<init>()");
+ return;
+ }
+
+ gCachedFields.iaddr_class_init = iaddrclassinit;
+
+ jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass,
+ "getByAddress", "([B)Ljava/net/InetAddress;");
+
+ if (iaddrgetbyaddress == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "InetAddress.getByAddress(byte[] val)");
+ return;
+ }
+
+ gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress;
+
+ jmethodID iaddrgetaddress = env->GetStaticMethodID(iaddrclass,
+ "getByAddress", "([B)Ljava/net/InetAddress;");
+
+
+
+
+ jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B");
+
+ if (iaddripaddress == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "Can't find field InetAddress.ipaddress");
+ return;
+ }
+
+ gCachedFields.iaddr_ipaddress = iaddripaddress;
+
+ // get the GenericIPMreq class
+
+ jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq");
+
+ if (genericipmreqclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "org.apache.harmony.luni.net.GenericIPMreq");
+ return;
+ }
+
+ gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass);
+
+ // initializing Integer
+
+ jclass integerclass = env->FindClass("java/lang/Integer");
+
+ if (integerclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.lang.Integer");
+ return;
+ }
+
+ jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V");
+
+ if (integerclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "Integer.<init>(int val)");
+ return;
+ }
+
+ jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I");
+
+ if (integerclassvalue == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value");
+ return;
+ }
+
+ gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass);
+ gCachedFields.integer_class_init = integerclassinit;
+ gCachedFields.integer_class_value = integerclassvalue;
+
+ // initializing Boolean
+
+ jclass booleanclass = env->FindClass("java/lang/Boolean");
+
+ if (booleanclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.lang.Boolean");
+ return;
+ }
+
+ jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V");
+
+ if (booleanclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "Boolean.<init>(boolean val)");
+ return;
+ }
+
+ jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z");
+
+ if (booleanclassvalue == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value");
+ return;
+ }
+
+ gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass);
+ gCachedFields.boolean_class_init = booleanclassinit;
+ gCachedFields.boolean_class_value = booleanclassvalue;
+
+ // initializing Byte
+
+ jclass byteclass = env->FindClass("java/lang/Byte");
+
+ if (byteclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.lang.Byte");
+ return;
+ }
+
+ jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V");
+
+ if (byteclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "Byte.<init>(byte val)");
+ return;
+ }
+
+ jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B");
+
+ if (byteclassvalue == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value");
+ return;
+ }
+
+ gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass);
+ gCachedFields.byte_class_init = byteclassinit;
+ gCachedFields.byte_class_value = byteclassvalue;
+
+ // initializing String
+
+ jclass stringclass = env->FindClass("java/lang/String");
+
+ if (stringclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.lang.String");
+ return;
+ }
+
+ jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V");
+
+ if (stringclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "String.<init>(byte[] val)");
+ return;
+ }
+
+ gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass);
+ gCachedFields.string_class_init = stringclassinit;
+
+ // initializing ScoketImpl
+
+ jclass socketimplclass = env->FindClass("java/net/SocketImpl");
+
+ if (socketimplclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.net.SocketImpl");
+ return;
+ }
+
+ jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I");
+
+ if (socketimplport == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port");
+ return;
+ }
+
+ jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address",
+ "Ljava/net/InetAddress;");
+
+ if (socketimpladdress == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "SocketImpl.address");
+ return;
+ }
+
+ gCachedFields.socketimpl_address = socketimpladdress;
+ gCachedFields.socketimpl_port = socketimplport;
+
+ gCachedFields.dpack_class = env->FindClass("java/net/DatagramPacket");
+ if (gCachedFields.dpack_class == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.net.DatagramPacket");
+ return;
+ }
+
+ gCachedFields.dpack_address = env->GetFieldID(gCachedFields.dpack_class,
+ "address", "Ljava/net/InetAddress;");
+ if (gCachedFields.dpack_address == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "DatagramPacket.address");
+ return;
+ }
+
+ gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class,
+ "port", "I");
+ if (gCachedFields.dpack_port == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "DatagramPacket.port");
+ return;
+ }
+
+ gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class,
+ "length", "I");
+ if (gCachedFields.dpack_length == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "DatagramPacket.length");
+ return;
+ }
+
+ gCachedFields.fd_class = env->FindClass("java/io/FileDescriptor");
+ if (gCachedFields.fd_class == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.io.FileDescriptor");
+ return;
+ }
+ gCachedFields.descriptor = env->GetFieldID(gCachedFields.fd_class, "descriptor", "I");
+ if (gCachedFields.descriptor == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "FileDescriptor.descriptor");
+ return;
+ }
+
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createSocketImpl");
+
+ int ret = socket(PF_INET, SOCK_STREAM, 0);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ return;
+ }
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
+
+ return;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createDatagramSocketImpl");
+
+ int ret = socket(PF_INET, SOCK_DGRAM, 0);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ return;
+ }
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
+
+ return;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint address, jint offset, jint count,
+ jint timeout) {
+ // LOGD("ENTER readSocketDirectImpl");
+
+ int handle;
+ jbyte *message = (jbyte *)address;
+ int result, ret, localCount;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ result = selectWait(handle, timeout, SELECT_READ_TYPE);
+
+ if (0 > result) {
+ return 0;
+ }
+
+ localCount = (count < 65536) ? count : 65536;
+
+ do {
+ ret = recv(handle, (jbyte *) message, localCount, SOCKET_NOFLAGS);
+ } while (ret < 0 && errno == EINTR);
+
+ if (0 == ret) {
+ return -1;
+ } else if (ret == -1) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ add_recv_stats(handle, ret);
+ return ret;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyteArray data, jint offset, jint count,
+ jint timeout) {
+ // LOGD("ENTER readSocketImpl");
+
+ jbyte *message;
+ int result, localCount;
+
+ jbyte internalBuffer[BUFFERSIZE];
+
+ localCount = (count < 65536) ? count : 65536;
+
+ if (localCount > BUFFERSIZE) {
+ message = (jbyte*)malloc(localCount * sizeof(jbyte));
+ if (message == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for readSocket");
+ return 0;
+ }
+ } else {
+ message = (jbyte *)internalBuffer;
+ }
+
+ result = Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
+ (jint) message, offset, count, timeout);
+
+ if (result > 0) {
+ env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
+ }
+
+ if (((jbyte *)message) != internalBuffer) {
+ free(( jbyte *)message);
+ }
+
+ return result;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint address, jint offset, jint count) {
+ // LOGD("ENTER writeSocketDirectImpl");
+
+ int handle;
+ jbyte *message = (jbyte *)address;
+ int result = 0, sent = 0;
+
+ if (count <= 0) {
+ return 0;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+
+ if (SOCKERR_WOULDBLOCK == err){
+ jclass socketExClass,errorCodeExClass;
+ jmethodID errorCodeExConstructor, socketExConstructor,socketExCauseMethod;
+ jobject errorCodeEx, socketEx;
+ const char* errorMessage = netLookupErrorString(err);
+ jstring errorMessageString = env->NewStringUTF(errorMessage);
+
+ errorCodeExClass = env->FindClass("org/apache/harmony/luni/util/ErrorCodeException");
+ if (!errorCodeExClass){
+ return 0;
+ }
+ errorCodeExConstructor = env->GetMethodID(errorCodeExClass,"<init>","(I)V");
+ if (!errorCodeExConstructor){
+ return 0;
+ }
+ errorCodeEx = env->NewObject(errorCodeExClass,errorCodeExConstructor,err);
+
+ socketExClass = env->FindClass("java/net/SocketException");
+ if (!socketExClass) {
+ return 0;
+ }
+ socketExConstructor = env->GetMethodID(socketExClass,"<init>","(Ljava/lang/String;)V");
+ if (!socketExConstructor) {
+ return 0;
+ }
+ socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
+ socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
+ env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
+ env->Throw((jthrowable)socketEx);
+ return 0;
+ }
+ throwSocketException(env, err);
+ return 0;
+ }
+
+ add_send_stats(handle, result);
+ return result;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
+ // LOGD("ENTER writeSocketImpl");
+
+ jbyte *message;
+ int sent = 0;
+ jint result = 0;
+
+/* TODO: ARRAY PINNING */
+#define INTERNAL_SEND_BUFFER_MAX 512
+ jbyte internalBuffer[INTERNAL_SEND_BUFFER_MAX];
+
+ if (count > INTERNAL_SEND_BUFFER_MAX) {
+ message = (jbyte*)malloc(count * sizeof( jbyte));
+ if (message == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for writeSocket");
+ return 0;
+ }
+ } else {
+ message = (jbyte *)internalBuffer;
+ }
+
+ env->GetByteArrayRegion(data, offset, count, message);
+
+ result = Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
+ (jint) message, offset, count);
+
+ if (( jbyte *)message != internalBuffer) {
+ free(( jbyte *)message);
+ }
+#undef INTERNAL_SEND_BUFFER_MAX
+ return result;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean nonblocking) {
+ // LOGD("ENTER setNonBlockingImpl");
+
+ int handle;
+ int result;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ int block = nonblocking;
+
+ result = ioctl(handle, FIONBIO, &block);
+
+ if (result == -1) {
+ throwSocketException(env, convertError(errno));
+ }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port);
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectWithTimeoutSocketImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jint timeout, jint trafficClass,
+ jobject inetAddr, jint port, jint step, jbyteArray passContext) {
+ // LOGD("ENTER connectWithTimeoutSocketImpl");
+
+ int handle;
+ int result = 0;
+ struct sockaddr_in address;
+ jbyte *context = NULL;
+
+ memset(&address, 0, sizeof(address));
+
+ address.sin_family = AF_INET;
+
+ result = inetAddressToSocketAddress(env, inetAddr, port,
+ (struct sockaddr_in *) &address);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return result;
+ }
+
+ // Check if we're using adb networking and redirect in case it is used.
+ if (useAdbNetworking && !isLocalhost(&address)) {
+ return Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(env, clazz, fileDescriptor,
+ trafficClass, inetAddr, port);
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return -1;
+ }
+
+ address.sin_port = htons(port);
+
+ context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
+
+ switch (step) {
+ case SOCKET_CONNECT_STEP_START:
+ result = sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_START, context);
+ break;
+ case SOCKET_CONNECT_STEP_CHECK:
+ result = sockConnectWithTimeout(handle, address, timeout,
+ SOCKET_STEP_CHECK, context);
+ break;
+ }
+
+ env->ReleasePrimitiveArrayCritical(passContext, context, JNI_ABORT);
+
+ if (0 == result) {
+ /* connected , so stop here */
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
+ } else if (result != SOCKERR_NOTCONNECTED) {
+ /* can not connect... */
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
+ if (result == SOCKERR_EACCES) {
+ jniThrowException(env, "java/lang/SecurityException",
+ netLookupErrorString(result));
+ } else {
+ jniThrowException(env, "java/net/ConnectException",
+ netLookupErrorString(result));
+ }
+ }
+
+ return result;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jint remotePort, jint timeout,
+ jint trafficClass, jobject inetAddr) {
+ // LOGD("ENTER connectStreamWithTimeoutSocketImpl");
+
+ int result = 0;
+ int handle;
+ struct sockaddr_in address;
+ jbyte *context = NULL;
+ int remainingTimeout = timeout;
+ int passedTimeout = 0;
+ int finishTime = 0;
+ int blocking = 0;
+ char hasTimeout = timeout > 0;
+
+ /* if a timeout was specified calculate the finish time value */
+ if (hasTimeout) {
+ finishTime = time_msec_clock() + (int) timeout;
+ }
+
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ } else {
+ result = inetAddressToSocketAddress(env, inetAddr, remotePort,
+ (struct sockaddr_in *) &address);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ // Check if we're using adb networking and redirect in case it is used.
+ if (useAdbNetworking && !isLocalhost(&address)) {
+ int retVal = Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(env, clazz,
+ fileDescriptor, trafficClass, inetAddr, remotePort);
+ if (retVal != 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ }
+ return;
+ }
+
+ /*
+ * we will be looping checking for when we are connected so allocate
+ * the descriptor sets that we will use
+ */
+ context =(jbyte *) malloc(sizeof(struct selectFDSet));
+
+ if (NULL == context) {
+ throwSocketException(env, SOCKERR_NOBUFFERS);
+ return;
+ }
+
+ result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
+ if (0 == result) {
+ /* ok we connected right away so we are done */
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
+ goto bail;
+ } else if (result != SOCKERR_NOTCONNECTED) {
+ log_socket_close(handle, result);
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
+ context);
+ /* we got an error other than NOTCONNECTED so we cannot continue */
+ if (SOCKERR_EACCES == result) {
+ jniThrowException(env, "java/lang/SecurityException",
+ netLookupErrorString(result));
+ } else {
+ throwSocketException(env, result);
+ }
+ goto bail;
+ }
+
+ while (SOCKERR_NOTCONNECTED == result) {
+ passedTimeout = remainingTimeout;
+
+ /*
+ * ok now try and connect. Depending on the platform this may sleep
+ * for up to passedTimeout milliseconds
+ */
+ result = sockConnectWithTimeout(handle, address, passedTimeout,
+ SOCKET_STEP_CHECK, context);
+
+ /*
+ * now check if the socket is still connected.
+ * Do it here as some platforms seem to think they
+ * are connected if the socket is closed on them.
+ */
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ goto bail;
+ }
+
+ /*
+ * check if we are now connected,
+ * if so we can finish the process and return
+ */
+ if (0 == result) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ goto bail;
+ }
+
+ /*
+ * if the error is SOCKERR_NOTCONNECTED then we have not yet
+ * connected and we may not be done yet
+ */
+ if (SOCKERR_NOTCONNECTED == result) {
+ /* check if the timeout has expired */
+ if (hasTimeout) {
+ remainingTimeout = finishTime - time_msec_clock();
+ if (remainingTimeout <= 0) {
+ log_socket_close(handle, result);
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ jniThrowException(env,
+ "java/net/SocketTimeoutException",
+ netLookupErrorString(result));
+ goto bail;
+ }
+ } else {
+ remainingTimeout = 100;
+ }
+ } else {
+ log_socket_close(handle, result);
+ sockConnectWithTimeout(handle, address, remainingTimeout,
+ SOCKET_STEP_DONE, context);
+ if ((SOCKERR_CONNRESET == result) ||
+ (SOCKERR_CONNECTION_REFUSED == result) ||
+ (SOCKERR_ADDRNOTAVAIL == result) ||
+ (SOCKERR_ADDRINUSE == result) ||
+ (SOCKERR_ENETUNREACH == result)) {
+ jniThrowException(env, "java/net/ConnectException",
+ netLookupErrorString(result));
+ } else if (SOCKERR_EACCES == result) {
+ jniThrowException(env, "java/lang/SecurityException",
+ netLookupErrorString(result));
+ } else {
+ throwSocketException(env, result);
+ }
+ goto bail;
+ }
+ }
+ }
+
+bail:
+
+ /* free the memory for the FD set */
+ if (context != NULL) {
+ free(context);
+ }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port) {
+ //LOGD("ENTER direct-call connectSocketImpl\n");
+
+ struct sockaddr_in address;
+ int ret;
+ int handle;
+ jbyteArray java_in_addr;
+
+ memset(&address, 0, sizeof(address));
+
+ address.sin_family = AF_INET;
+
+ ret = inetAddressToSocketAddress(env, inetAddr, port,
+ (struct sockaddr_in *) &address);
+
+ if (ret < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return ret;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return -1;
+ }
+
+ address.sin_port = htons(port);
+
+ if (useAdbNetworking && !isLocalhost(&address)) {
+
+ // LOGD("+connect to address 0x%08x port %d (via adb)",
+ // address.sin_addr.s_addr, (int) port);
+ ret = adb_networking_connect_fd(handle, &address);
+ // LOGD("-connect ret %d errno %d (via adb)", ret, errno);
+
+ } else {
+
+ // call this method with a timeout of zero
+ Java_org_sipdroid_net_impl_OSNetworkSystem_connectStreamWithTimeoutSocketImpl(env, clazz,
+ fileDescriptor, port, 0, trafficClass, inetAddr);
+ if (env->ExceptionOccurred() != 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+
+ }
+
+ if (ret < 0) {
+ jniThrowException(env, "java/net/ConnectException",
+ netLookupErrorString(convertError(errno)));
+ return ret;
+ }
+
+ return ret;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint port, jobject inetAddress) {
+ // LOGD("ENTER socketBindImpl");
+
+ struct sockaddr_in sockaddress;
+ int ret;
+ int handle;
+
+ ret = inetAddressToSocketAddress(env, inetAddress, port,
+ (struct sockaddr_in *) &sockaddress);
+
+ if (ret < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
+
+ if (ret < 0) {
+ jniThrowException(env, "java/net/BindException",
+ netLookupErrorString(convertError(errno)));
+ return;
+ }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint backlog) {
+ // LOGD("ENTER listenStreamSocketImpl");
+
+ int ret;
+ int handle;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ ret = listen(handle, backlog);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return;
+ }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor) {
+ // LOGD("ENTER availableStreamImpl");
+
+ int handle;
+ char message[BUFFERSIZE];
+
+ int result;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ do {
+ result = selectWait(handle, 1, SELECT_READ_TYPE);
+
+ if (SOCKERR_TIMEOUT == result) {
+ // The read operation timed out, so answer 0 bytes available
+ return 0;
+ } else if (SOCKERR_INTERRUPTED == result) {
+ continue;
+ } else if (0 > result) {
+ log_socket_close(handle, result);
+ throwSocketException(env, result);
+ return 0;
+ }
+ } while (SOCKERR_INTERRUPTED == result);
+
+ result = recv(handle, (jbyte *) message, BUFFERSIZE, MSG_PEEK);
+
+ if (0 > result) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ add_recv_stats(handle, result);
+ return result;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
+ // LOGD("ENTER acceptSocketImpl");
+
+ union {
+ struct sockaddr address;
+ struct sockaddr_in in_address;
+ } sa;
+
+ int ret;
+ int retFD;
+ int result;
+ int handle;
+ socklen_t addrlen;
+
+ if (newSocket == NULL) {
+ throwNullPointerException(env);
+ return;
+ }
+
+ result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
+
+ if (0 > result) {
+ return;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fdServer);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ do {
+ addrlen = sizeof(sa);
+ ret = accept(handle, &(sa.address), &addrlen);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return;
+ }
+
+ retFD = ret;
+
+ /* For AF_INET / inetOrLocal == true only: put
+ * peer address and port in instance variables
+ * We don't bother for UNIX domain sockets, since most peers are
+ * anonymous anyway
+ */
+ if (sa.address.sa_family == AF_INET) {
+ // inetOrLocal should also be true
+
+ jobject inetAddress;
+
+ inetAddress = structInToInetAddress(env, &(sa.in_address.sin_addr));
+
+ if (inetAddress == NULL) {
+ close(retFD);
+ newSocket = NULL;
+ return;
+ }
+
+ env->SetObjectField(newSocket,
+ gCachedFields.socketimpl_address, inetAddress);
+
+ env->SetIntField(newSocket, gCachedFields.socketimpl_port,
+ ntohs(sa.in_address.sin_port));
+ }
+
+ jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
+}
+
+extern "C" jboolean Java_org_sipdroid_net_impl_OSNetworkSystem_supportsUrgentDataImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor) {
+ // LOGD("ENTER supportsUrgentDataImpl");
+
+ int handle;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyte value) {
+ // LOGD("ENTER sendUrgentDataImpl");
+
+ int handle;
+ int result;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ result = send(handle, (jbyte *) &value, 1, MSG_OOB);
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass clazz,
+ jobject fd, jint port, jint trafficClass, jobject inetAddress) {
+ // LOGD("ENTER connectDatagramImpl2");
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ struct sockaddr_in sockAddr;
+ int ret;
+
+ ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
+
+ if (ret < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+ log_socket_connect(handle, ntohl(sockAddr.sin_addr.s_addr), port);
+ int result = connect(handle, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd) {
+ // LOGD("ENTER disconnectDatagramImpl");
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ struct sockaddr_in *sockAddr;
+ socklen_t sockAddrLen = sizeof(struct sockaddr_in);
+ sockAddr = (struct sockaddr_in *) malloc(sockAddrLen);
+ memset(sockAddr, 0, sockAddrLen);
+
+ sockAddr->sin_family = AF_UNSPEC;
+ int result = connect(handle, (struct sockaddr *)sockAddr, sockAddrLen);
+ free(sockAddr);
+
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ }
+}
+
+extern "C" jboolean Java_org_sipdroid_net_impl_OSNetworkSystem_socketBindImpl2(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint port, jboolean bindToDevice,
+ jobject inetAddress) {
+ // LOGD("ENTER socketBindImpl2");
+
+ struct sockaddr_in sockaddress;
+ int ret;
+ int handle;
+
+ ret = inetAddressToSocketAddress(env, inetAddress, port,
+ (struct sockaddr_in *) &sockaddress);
+
+ if (ret < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ jniThrowException(env, "java/net/BindException", netLookupErrorString(err));
+ return 0;
+ }
+
+ return 0;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jobject sender, jint receiveTimeout) {
+ // LOGD("ENTER peekDatagramImpl");
+
+ int port = -1;
+
+ int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+ if (0> result) {
+ return (jint) 0;
+ }
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ struct sockaddr_in sockAddr;
+ socklen_t sockAddrLen = sizeof(sockAddr);
+
+ int length = recvfrom(handle, NULL, 0, MSG_PEEK,
+ (struct sockaddr *)&sockAddr, &sockAddrLen);
+
+ if (length < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+
+ if (socketAddressToInetAddress(env, &sockAddr, sender, &port) < 0) {
+ throwIOExceptionStr(env, "Address conversion failed");
+ return -1;
+ }
+ add_recv_stats(handle, length);
+ return port;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jobject packet, jint address, jint offset, jint length,
+ jint receiveTimeout, jboolean peek) {
+ // LOGD("ENTER receiveDatagramDirectImpl");
+
+ int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+ if (0 > result) {
+ return (jint) 0;
+ }
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ struct sockaddr_in sockAddr;
+ socklen_t sockAddrLen = sizeof(sockAddr);
+
+ int mode = peek ? MSG_PEEK : 0;
+
+ int actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
+ (struct sockaddr *)&sockAddr, &sockAddrLen);
+
+ if (actualLength < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+
+ if (packet != NULL) {
+ int port = ntohs(sockAddr.sin_port);
+ jobject sender = env->GetObjectField(packet, gCachedFields.dpack_address);
+ //__android_log_print(ANDROID_LOG_INFO,"OSNetwork","Sender address %x ", sender);
+ if (sender != 0) {
+ jbyteArray addr = (jbyteArray)env->GetObjectField(sender, gCachedFields.iaddr_ipaddress);
+ //__android_log_print(ANDROID_LOG_INFO,"OSNetwork","Sender Recup");
+ if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
+ jniThrowException(env, "java/net/SocketException",
+ "Could not set address of packet.");
+ return 0;
+ }
+ }
+ else {
+ jbyteArray addr = env->NewByteArray(sizeof(struct in_addr));
+ if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
+ jniThrowException(env, "java/net/SocketException",
+ "Could not set address of packet.");
+ return 0;
+ }
+ sender = env->CallStaticObjectMethod(
+ gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
+ addr);
+
+ }
+ env->SetObjectField(packet, gCachedFields.dpack_address, sender);
+ env->SetIntField(packet, gCachedFields.dpack_port, port);
+ env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
+ }
+ add_recv_stats(handle, actualLength);
+ return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
+ jint receiveTimeout, jboolean peek) {
+ // LOGD("ENTER receiveDatagramImpl");
+
+ int localLength = (length < 65536) ? length : 65536;
+ jbyte *bytes = (jbyte*) malloc(localLength);
+ if (bytes == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for receiveDatagram");
+ return 0;
+ }
+
+ int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
+ packet, (jint)bytes, offset, localLength, receiveTimeout, peek);
+
+ if (actualLength > 0) {
+ env->SetByteArrayRegion(data, offset, actualLength, bytes);
+ }
+ free(bytes);
+
+ return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramDirectImpl(JNIEnv* env,
+ jclass clazz, jobject fd, jobject packet, jint address, jint offset,
+ jint length, jint receiveTimeout, jboolean peek) {
+ // LOGD("ENTER receiveConnectedDatagramDirectImpl");
+
+ int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+
+ if (0 > result) {
+ return 0;
+ }
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ int mode = peek ? MSG_PEEK : 0;
+
+ int actualLength = recvfrom(handle,
+ (char*)(address + offset), length, mode, NULL, NULL);
+
+ if (actualLength < 0) {
+ jniThrowException(env, "java/net/PortUnreachableException", "");
+ return 0;
+ }
+
+ if ( packet != NULL) {
+ env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
+ }
+ add_recv_stats(handle, actualLength);
+ return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
+ jint receiveTimeout, jboolean peek) {
+ // LOGD("ENTER receiveConnectedDatagramImpl");
+
+ int localLength = (length < 65536) ? length : 65536;
+ jbyte *bytes = (jbyte*) malloc(localLength);
+ if (bytes == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for recvConnectedDatagram");
+ return 0;
+ }
+
+ int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramDirectImpl(env,
+ clazz, fd, packet, (jint)bytes, offset, localLength,
+ receiveTimeout, peek);
+
+ if (actualLength > 0) {
+ env->SetByteArrayRegion(data, offset, actualLength, bytes);
+ }
+ free(bytes);
+
+ return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jint address, jint offset, jint length, jint port,
+ jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
+ // LOGD("ENTER sendDatagramDirectImpl");
+
+ int result = 0;
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ struct sockaddr_in receiver;
+
+ if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ result = sendto(handle, (char*)(address + offset), length, SOCKET_NOFLAGS,
+ (struct sockaddr*)&receiver, sizeof(receiver));
+
+ if (result < 0) {
+ int err = convertError(errno);
+ if ((SOCKERR_CONNRESET == err)
+ || (SOCKERR_CONNECTION_REFUSED == err)) {
+ return 0;
+ } else {
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ }
+ add_send_stats(handle, result);
+ return result;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jbyteArray data, jint offset, jint length, jint port,
+ jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
+ // LOGD("ENTER sendDatagramImpl");
+
+ jbyte *bytes = env->GetByteArrayElements(data, NULL);
+ int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramDirectImpl(env, clazz, fd,
+ (jint)bytes, offset, length, port, bindToDevice, trafficClass,
+ inetAddress);
+ env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
+
+ return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramDirectImpl(JNIEnv* env,
+ jclass clazz, jobject fd, jint address, jint offset, jint length,
+ jboolean bindToDevice) {
+ // LOGD("ENTER sendConnectedDatagramDirectImpl");
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ int result = send(handle, (char*)(address + offset), length, 0);
+
+ if (result < 0) {
+ int err = convertError(errno);
+ if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
+ return 0;
+ } else {
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ }
+ add_send_stats(handle, length);
+ return result;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jbyteArray data, jint offset, jint length,
+ jboolean bindToDevice) {
+ // LOGD("ENTER sendConnectedDatagramImpl");
+
+ jbyte *bytes = env->GetByteArrayElements(data, NULL);
+ int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramDirectImpl(env,
+ clazz, fd, (jint)bytes, offset, length, bindToDevice);
+ env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
+
+ return actualLength;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createServerStreamSocketImpl");
+
+ if (fileDescriptor == NULL) {
+ throwNullPointerException(env);
+ return;
+ }
+
+ int handle = socket(PF_INET, SOCK_STREAM, 0);
+
+ if (handle < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ return;
+ }
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
+
+ int value = 1;
+
+ setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createMulticastSocketImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createMulticastSocketImpl");
+
+ int handle = socket(PF_INET, SOCK_DGRAM, 0);
+
+ if (handle < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ return;
+ }
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
+
+ int value = 1;
+
+ // setsockopt(handle, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(jbyte));
+ setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
+}
+
+/*
+ * @param timeout in milliseconds. If zero, block until data received
+ */
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyteArray data, jint offset, jint count,
+ jint timeout) {
+ // LOGD("ENTER receiveStreamImpl");
+
+ int result;
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ // Cap read length to available buf size
+ int spaceAvailable = env->GetArrayLength(data) - offset;
+ int localCount = count < spaceAvailable? count : spaceAvailable;
+
+ jboolean isCopy;
+ jbyte *body = env->GetByteArrayElements(data, &isCopy);
+
+ // set timeout
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv,
+ sizeof(struct timeval));
+
+ do {
+ result = recv(handle, body + offset, localCount, SOCKET_NOFLAGS);
+ } while (result < 0 && errno == EINTR);
+
+ env->ReleaseByteArrayElements(data, body, 0);
+
+ /*
+ * If no bytes are read, return -1 to signal 'endOfFile'
+ * to the Java input stream
+ */
+ if (0 < result) {
+ add_recv_stats(handle, result);
+ return result;
+ } else if (0 == result) {
+ return -1;
+ } else {
+ // If EAGAIN or EWOULDBLOCK, read timed out
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ jniThrowException(env, "java/net/SocketTimeoutException",
+ netLookupErrorString(SOCKERR_TIMEOUT));
+ } else {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ }
+ return 0;
+ }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
+ // LOGD("ENTER sendStreamImpl");
+
+ int handle = 0;
+ int result = 0, sent = 0;
+
+ jboolean isCopy;
+ jbyte *message = env->GetByteArrayElements(data, &isCopy);
+
+ // Cap write length to available buf size
+ int spaceAvailable = env->GetArrayLength(data) - offset;
+ if (count > spaceAvailable) count = spaceAvailable;
+
+ while (sent < count) {
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env,
+ sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
+ env->ReleaseByteArrayElements(data, message, 0);
+ return 0;
+ }
+
+ // LOGD("before select %d", count);
+ selectWait(handle, SEND_RETRY_TIME, SELECT_WRITE_TYPE);
+ result = send(handle, (jbyte *)message + offset + sent,
+ (int) count - sent, SOCKET_NOFLAGS);
+
+ if (result < 0) {
+ result = errno;
+ if (result == EAGAIN ||result == EWOULDBLOCK) {
+ // LOGD("write blocked %d", sent);
+ continue;
+ }
+ env->ReleaseByteArrayElements(data, message, 0);
+ int err = convertError(result);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ sent += result;
+ }
+
+ env->ReleaseByteArrayElements(data, message, 0);
+ add_send_stats(handle, sent);
+ return sent;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject obj,
+ jobject fileDescriptor) {
+ // LOGD("ENTER shutdownInputImpl");
+
+ int ret;
+ int handle;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ ret = shutdown(handle, SHUT_RD);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return;
+ }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject obj,
+ jobject fileDescriptor) {
+ // LOGD("ENTER shutdownOutputImpl");
+
+ int ret;
+ int handle;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ return;
+ }
+
+ ret = shutdown(handle, SHUT_WR);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return;
+ }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
+ jobject fd, jbyteArray data, jint offset, jint length, jint port,
+ jobject inetAddress) {
+ // LOGD("ENTER sendDatagramImpl2");
+
+ jbyte *message;
+ jbyte nhostAddrBytes[4];
+ unsigned short nPort;
+ int result = 0, sent = 0;
+ int handle = 0;
+ struct sockaddr_in sockaddrP;
+
+ if (inetAddress != NULL) {
+
+ result = inetAddressToSocketAddress(env, inetAddress, port,
+ (struct sockaddr_in *) &sockaddrP);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+ }
+
+ message = (jbyte*) malloc(length * sizeof(jbyte));
+ if (message == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for readSocket");
+ return 0;
+ }
+
+ env->GetByteArrayRegion(data, offset, length, message);
+
+ while (sent < length) {
+ handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env,
+ sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
+ free(message);
+ return 0;
+ }
+
+ result = sendto(handle, (char *) (message + sent),
+ (int) (length - sent), SOCKET_NOFLAGS,
+ (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
+
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ free(message);
+ return 0;
+ }
+
+ sent += result;
+ }
+
+ free(message);
+ add_send_stats(handle, sent);
+ return sent;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
+ jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
+ jint countWriteC, jintArray outFlags, jlong timeout) {
+ // LOGD("ENTER selectImpl");
+
+ struct timeval timeP;
+ int result = 0;
+ int size = 0;
+ jobject gotFD;
+ fd_set *fdset_read,*fdset_write;
+ int handle;
+ jboolean isCopy ;
+ jint *flagArray;
+ int val;
+ unsigned int time_sec = (unsigned int)timeout/1000;
+ unsigned int time_msec = (unsigned int)(timeout%1000);
+
+ fdset_read = (fd_set *)malloc(sizeof(fd_set));
+ fdset_write = (fd_set *)malloc(sizeof(fd_set));
+
+ FD_ZERO(fdset_read);
+ FD_ZERO(fdset_write);
+
+ for (val = 0; val<countReadC; val++) {
+
+ gotFD = env->GetObjectArrayElement(readFDArray,val);
+
+ handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+ FD_SET(handle, fdset_read);
+
+ if (0 > (size - handle)) {
+ size = handle;
+ }
+ }
+
+ for (val = 0; val<countWriteC; val++) {
+
+ gotFD = env->GetObjectArrayElement(writeFDArray,val);
+
+ handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+ FD_SET(handle, fdset_write);
+
+ if (0 > (size - handle)) {
+ size = handle;
+ }
+ }
+
+ /* the size is the max_fd + 1 */
+ size =size + 1;
+
+ if (0 > size) {
+ result = SOCKERR_FDSET_SIZEBAD;
+ } else {
+ /* only set when timeout >= 0 (non-block)*/
+ if (0 <= timeout) {
+
+ timeP.tv_sec = time_sec;
+ timeP.tv_usec = time_msec*1000;
+
+ result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
+
+ } else {
+ result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
+ }
+ }
+
+ if (0 < result) {
+ /*output the result to a int array*/
+ flagArray = env->GetIntArrayElements(outFlags, &isCopy);
+
+ for (val=0; val<countReadC; val++) {
+ gotFD = env->GetObjectArrayElement(readFDArray,val);
+
+ handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+ if (FD_ISSET(handle,fdset_read)) {
+ flagArray[val] = SOCKET_OP_READ;
+ } else {
+ flagArray[val] = SOCKET_OP_NONE;
+ }
+ }
+
+ for (val=0; val<countWriteC; val++) {
+
+ gotFD = env->GetObjectArrayElement(writeFDArray,val);
+
+ handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+ if (FD_ISSET(handle,fdset_write)) {
+ flagArray[val+countReadC] = SOCKET_OP_WRITE;
+ } else {
+ flagArray[val+countReadC] = SOCKET_OP_NONE;
+ }
+ }
+
+ env->ReleaseIntArrayElements(outFlags, flagArray, 0);
+ }
+
+ free(fdset_write);
+ free(fdset_read);
+
+ /* return both correct and error result, let java handle the exception*/
+ return result;
+}
+
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
+ // LOGD("ENTER getSocketLocalAddressImpl");
+
+ struct sockaddr_in addr;
+ socklen_t addrLen = sizeof(addr);
+
+ memset(&addr, 0, addrLen);
+
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ int result;
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
+ return NULL;
+ }
+
+ result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
+
+ // Spec says ignore all errors
+
+ return structInToInetAddress(env, &(addr.sin_addr));
+
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean preferIPv6Addresses) {
+ // LOGD("ENTER getSocketLocalPortImpl");
+
+ struct sockaddr_in addr;
+ socklen_t addrLen = sizeof(addr);
+
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ int result;
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
+ return 0;
+ }
+
+ result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
+
+ if (0 != result) {
+ // The java spec does not indicate any exceptions on this call
+ return 0;
+ } else {
+ return ntohs(addr.sin_port);
+ }
+}
+
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint anOption) {
+ // LOGD("ENTER getSocketOptionImpl");
+
+ int handle;
+ int intValue = 0;
+ socklen_t intSize = sizeof(int);
+ unsigned char byteValue = 0;
+ socklen_t byteSize = sizeof(unsigned char);
+ int result;
+ struct sockaddr_in sockVal;
+ socklen_t sockSize = sizeof(sockVal);
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return NULL;
+ }
+
+ switch ((int) anOption & 0xffff) {
+ case JAVASOCKOPT_SO_LINGER: {
+ struct linger lingr;
+ socklen_t size = sizeof(struct linger);
+ result = getsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr, &size);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ if (!lingr.l_onoff) {
+ intValue = -1;
+ } else {
+ intValue = lingr.l_linger;
+ }
+ return newJavaLangInteger(env, intValue);
+ }
+ case JAVASOCKOPT_TCP_NODELAY: {
+ if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
+ return NULL;
+ }
+ result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_MCAST_TTL: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
+ return newJavaLangByte(env, 0);
+ }
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteValue, &byteSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangByte(env, (jbyte)(byteValue & 0xFF));
+ }
+ case JAVASOCKOPT_MCAST_INTERFACE: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+ return NULL;
+ }
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return structInToInetAddress(env, &(sockVal.sin_addr));
+ }
+ case JAVASOCKOPT_SO_SNDBUF: {
+ result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangInteger(env, intValue);
+ }
+ case JAVASOCKOPT_SO_RCVBUF: {
+ result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangInteger(env, intValue);
+ }
+ case JAVASOCKOPT_SO_BROADCAST: {
+ result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_SO_REUSEADDR: {
+ result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_SO_KEEPALIVE: {
+ result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_SO_OOBINLINE: {
+ result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_IP_MULTICAST_LOOP: {
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_IP_TOS: {
+ result = getsockopt(handle, IPPROTO_IP, IP_TOS, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangInteger(env, intValue);
+ }
+ case JAVASOCKOPT_SO_RCVTIMEOUT: {
+ struct timeval timeout;
+ socklen_t size = sizeof(timeout);
+ result = getsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
+ }
+ default: {
+ throwSocketException(env, SOCKERR_OPTUNSUPP);
+ return NULL;
+ }
+ }
+
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint anOption, jobject optVal) {
+ // LOGD("ENTER setSocketOptionImpl");
+
+ int handle, result;
+ int intVal, intSize = sizeof(int);
+ unsigned char byteVal, byteSize = sizeof(unsigned char);
+ struct sockaddr_in sockVal;
+ int sockSize = sizeof(sockVal);
+
+ if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
+ intVal = (int) env->GetIntField(optVal, gCachedFields.integer_class_value);
+ } else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
+ intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
+ } else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
+ byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
+ } else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
+ if (inetAddressToSocketAddress(env, optVal, 0, &sockVal) < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+ } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
+ // we'll use optVal directly
+ } else {
+ throwSocketException(env, SOCKERR_OPTUNSUPP);
+ return;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ switch ((int) anOption & 0xffff) {
+ case JAVASOCKOPT_SO_LINGER: {
+ struct linger lingr;
+ lingr.l_onoff = intVal > 0 ? 1 : 0;
+ lingr.l_linger = intVal;
+ result = setsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr,
+ sizeof(struct linger));
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_TCP_NODELAY: {
+ if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
+ return;
+ }
+ result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_MCAST_TTL: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
+ return;
+ }
+ result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteVal, byteSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
+ mcastAddDropMembership(env, handle, optVal,
+ (anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
+ return;
+ }
+
+ case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
+ mcastAddDropMembership(env, handle, optVal,
+ (anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
+ return;
+ }
+
+ case JAVASOCKOPT_MCAST_INTERFACE: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+ return;
+ }
+ result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, sockSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_SNDBUF: {
+ result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_RCVBUF: {
+ result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_BROADCAST: {
+ result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_REUSEADDR: {
+ result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+ case JAVASOCKOPT_SO_KEEPALIVE: {
+ result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_OOBINLINE: {
+ result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_IP_MULTICAST_LOOP: {
+ result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_IP_TOS: {
+ result = setsockopt(handle, IPPROTO_IP, IP_TOS, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_REUSEADDR_AND_REUSEPORT: {
+ // SO_REUSEPORT doesn't need to get set on this System
+ result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_RCVTIMEOUT: {
+ struct timeval timeout;
+ timeout.tv_sec = intVal / 1000;
+ timeout.tv_usec = (intVal % 1000) * 1000;
+ result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
+ sizeof(struct timeval));
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ default: {
+ throwSocketException(env, SOCKERR_OPTUNSUPP);
+ }
+ }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
+ // LOGD("ENTER getSocketFlagsImpl");
+
+ // Not implemented by harmony
+ return 0;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor) {
+ // LOGD("ENTER socketCloseImpl");
+
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ log_socket_close(handle, SOCKET_CLOSE_LOCAL);
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
+
+ close(handle);
+}
+
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz,
+ jbyteArray addrStr) {
+ // LOGD("ENTER getHostByAddrImpl");
+
+ if (addrStr == NULL) {
+ throwNullPointerException(env);
+ return JNI_FALSE;
+ }
+
+ jstring address = (jstring)newJavaLangString(env, addrStr);
+ jstring result;
+ const char* addr = env->GetStringUTFChars(address, NULL);
+
+ struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET);
+
+ if (ent != NULL && ent->h_name != NULL) {
+ result = env->NewStringUTF(ent->h_name);
+ } else {
+ result = NULL;
+ }
+
+ env->ReleaseStringUTFChars(address, addr);
+
+ return result;
+}
+
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz,
+ jstring nameStr, jboolean preferIPv6Addresses) {
+ // LOGD("ENTER getHostByNameImpl");
+
+ if (nameStr == NULL) {
+ throwNullPointerException(env);
+ return NULL;
+ }
+
+ const char* name = env->GetStringUTFChars(nameStr, NULL);
+
+ if (useAdbNetworking) {
+
+ union {
+ struct in_addr a;
+ jbyte j[4];
+ } outaddr;
+
+ // LOGD("ADB networking: +gethostbyname '%s'", name);
+ int err;
+ err = adb_networking_gethostbyname(name, &(outaddr.a));
+
+ env->ReleaseStringUTFChars(nameStr, name);
+#if 0
+ LOGD("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
+ err, (unsigned int)outaddr.a.s_addr,
+ outaddr.j[0],outaddr.j[1],
+ outaddr.j[2],outaddr.j[3]);
+#endif
+
+ if (err < 0) {
+ return NULL;
+ } else {
+ jbyteArray addr = env->NewByteArray(4);
+ env->SetByteArrayRegion(addr, 0, 4, outaddr.j);
+ return addr;
+ }
+ } else {
+
+ // normal case...no adb networking
+ struct hostent* ent = gethostbyname(name);
+
+ env->ReleaseStringUTFChars(nameStr, name);
+
+ if (ent != NULL && ent->h_length > 0) {
+ jbyteArray addr = env->NewByteArray(4);
+ jbyte v[4];
+ memcpy(v, ent->h_addr, 4);
+ env->SetByteArrayRegion(addr, 0, 4, v);
+ return addr;
+ } else {
+ return NULL;
+ }
+ }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
+ jobject sender, jbyteArray address) {
+ // LOGD("ENTER setInetAddressImpl");
+
+ env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
+}
+
+/*
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
+ // LOGD("ENTER inheritedChannelImpl");
+
+ int socket = 0;
+ int opt;
+ socklen_t length = sizeof(opt);
+ int socket_type;
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+ jclass channel_class, socketaddr_class, serverSocket_class, socketImpl_class;
+ jobject channel_object = NULL, socketaddr_object, serverSocket_object;
+ jobject fd_object, addr_object, localAddr_object, socketImpl_object;
+ jfieldID port_field, socketaddr_field, bound_field, fd_field;
+ jfieldID serverSocket_field, socketImpl_field, addr_field, localAddr_field;
+ jmethodID channel_new;
+ jbyteArray addr_array;
+ struct sockaddr_in *sock;
+ jbyte * address;
+ jbyte * localAddr;
+ jboolean jtrue = JNI_TRUE;
+
+ if (0 != getsockopt(socket, SOL_SOCKET, SO_TYPE, &opt, &length)) {
+ return NULL;
+ }
+ if (SOCK_STREAM !=opt && SOCK_DGRAM !=opt) {
+ return NULL;
+ }
+ socket_type = opt;
+
+ length = sizeof(struct sockaddr);
+ if (0 != getsockname(socket, (struct sockaddr *)&local_addr, &length)) {
+ return NULL;
+ } else {
+ if (AF_INET != local_addr.sin_family || length != sizeof(struct sockaddr)) {
+ return NULL;
+ }
+ localAddr = (jbyte*) malloc(sizeof(jbyte)*4);
+ if (NULL == localAddr) {
+ return NULL;
+ }
+ memcpy (localAddr, &(local_addr.sin_addr.s_addr), 4);
+ }
+ if (0 != getpeername(socket, (struct sockaddr *)&remote_addr, &length)) {
+ remote_addr.sin_port = 0;
+ remote_addr.sin_addr.s_addr = 0;
+ address = (jbyte*) malloc(sizeof(jbyte)*4);
+ bzero(address, sizeof(jbyte)*4);
+ } else {
+ if (AF_INET != remote_addr.sin_family
+ || length != sizeof(struct sockaddr)) {
+ return NULL;
+ }
+ address = (jbyte*) malloc(sizeof(jbyte)*4);
+ memcpy (address, &(remote_addr.sin_addr.s_addr), 4);
+ }
+
+ // analysis end, begin pack to java
+ if (SOCK_STREAM == opt) {
+ if (remote_addr.sin_port!=0) {
+ //socket
+ channel_class = env->FindClass(
+ "org/apache/harmony/nio/internal/SocketChannelImpl");
+ if (NULL == channel_class) {
+ goto clean;
+ }
+
+ channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+ if (NULL == channel_new) {
+ goto clean;
+ }
+ channel_object = env->NewObject(channel_class, channel_new);
+ if (NULL == channel_object) {
+ goto clean;
+ }
+ // new and set FileDescript
+
+ fd_field = env->GetFieldID(channel_class, "fd",
+ "java/io/FielDescriptor");
+ fd_object = env->GetObjectField(channel_object, fd_field);
+ if (NULL == fd_object) {
+ goto clean;
+ }
+
+ jniSetFileDescriptorOfFD(env, fd_object, socket);
+
+ // local port
+ port_field = env->GetFieldID(channel_class, "localPort", "I");
+ env->SetIntField(channel_object, port_field,
+ ntohs(local_addr.sin_port));
+
+ // new and set remote addr
+ addr_object = env->NewObject(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_class_init);
+ if (NULL == addr_object) {
+ goto clean;
+ }
+ socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+ socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+ "Ljava/net/InetSocketAddress;");
+ socketaddr_object = env->GetObjectField(channel_object,
+ socketaddr_field);
+ if (NULL == socketaddr_object) {
+ goto clean;
+ }
+ addr_field = env->GetFieldID(socketaddr_class, "addr",
+ "Ljava/net/InetAddress;");
+ env->SetObjectField(socketaddr_object, addr_field, addr_object);
+ addr_array = env->NewByteArray((jsize)4);
+ env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+ env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress,
+ addr_array);
+
+ // localAddr
+ socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+ socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+ "Ljava/net/InetSocketAddress;");
+ socketaddr_object = env->GetObjectField(channel_object,
+ socketaddr_field);
+
+ localAddr_field = env->GetFieldID(channel_class, "localAddress",
+ "Ljava/net/InetAddress;");
+ localAddr_object = env->NewObject(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_class_init);
+ jfieldID socketaddr_field = env->GetFieldID(channel_class,
+ "connectAddress", "Ljava/net/InetSocketAddress;");
+ jobject socketaddr_object = env->GetObjectField(channel_object,
+ socketaddr_field);
+ env->SetObjectField(socketaddr_object, localAddr_field,
+ localAddr_object);
+ if (NULL == localAddr_object) {
+ goto clean;
+ }
+ addr_array = env->NewByteArray((jsize)4);
+ env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
+ env->SetObjectField(localAddr_object, gCachedFields.iaddr_ipaddress,
+ addr_array);
+
+
+ // set port
+ port_field = env->GetFieldID(socketaddr_class, "port", "I");
+ env->SetIntField(socketaddr_object, port_field,
+ ntohs(remote_addr.sin_port));
+
+ // set bound
+ if (0 != local_addr.sin_port) {
+ bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+ env->SetBooleanField(channel_object, bound_field, jtrue);
+ }
+
+ } else {
+ //serverSocket
+ channel_class = env->FindClass(
+ "org/apache/harmony/nio/internal/ServerSocketChannelImpl");
+ if (NULL == channel_class) {
+ goto clean;
+ }
+
+ channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+ if (NULL == channel_new) {
+ goto clean;
+ }
+ channel_object = env->NewObject(channel_class, channel_new);
+ if (NULL == channel_object) {
+ goto clean;
+ }
+
+ serverSocket_field = env->GetFieldID(channel_class, "socket",
+ "Ljava/net/ServerSocket;");
+ serverSocket_class = env->FindClass("Ljava/net/ServerSocket;");
+ serverSocket_object = env->GetObjectField(channel_object,
+ serverSocket_field);
+ // set bound
+ if (0 != local_addr.sin_port) {
+ bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+ env->SetBooleanField(channel_object, bound_field, jtrue);
+ bound_field = env->GetFieldID(serverSocket_class, "isBound", "Z");
+ env->SetBooleanField(serverSocket_object, bound_field, jtrue);
+ }
+ // localAddr
+ socketImpl_class = env->FindClass("java/net/SocketImpl");
+ socketImpl_field = env->GetFieldID(channel_class, "impl",
+ "Ljava/net/SocketImpl;");
+ socketImpl_object = env->GetObjectField(channel_object,
+ socketImpl_field);
+ if (NULL == socketImpl_object) {
+ goto clean;
+ }
+
+ localAddr_field = env->GetFieldID(channel_class, "localAddress",
+ "Ljava/net/InetAddress;");
+ localAddr_object = env->NewObject(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_class_init);
+ if (NULL == localAddr_object) {
+ goto clean;
+ }
+ env->SetObjectField(socketImpl_object, localAddr_field,
+ localAddr_object);
+ addr_array = env->NewByteArray((jsize)4);
+ env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
+ env->SetObjectField(localAddr_object,
+ gCachedFields.iaddr_ipaddress, addr_array);
+
+ // set port
+ port_field = env->GetFieldID(socketImpl_class, "localport", "I");
+ env->SetIntField(socketImpl_object, port_field,
+ ntohs(local_addr.sin_port));
+ }
+ } else {
+ //Datagram Socket
+ // new DatagramChannel
+ channel_class = env->FindClass(
+ "org/apache/harmony/nio/internal/DatagramChannelImpl");
+ if (NULL == channel_class) {
+ goto clean;
+ }
+
+ channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+ if (NULL == channel_new) {
+ goto clean;
+ }
+ channel_object = env->NewObject(channel_class, channel_new);
+ if (NULL == channel_object) {
+ goto clean;
+ }
+
+ // new and set FileDescript
+ fd_field = env->GetFieldID(channel_class, "fd", "java/io/FileDescriptor");
+ fd_object = env->GetObjectField(channel_object, fd_field);
+ if (NULL == fd_object) {
+ goto clean;
+ }
+
+ jniSetFileDescriptorOfFD(env, fd_object, socket);
+
+ port_field = env->GetFieldID(channel_class, "localPort", "I");
+ env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
+
+ // new and set remote addr
+ addr_object = env->NewObject(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_class_init);
+ if (NULL == addr_object) {
+ goto clean;
+ }
+ socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+ socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+ "Ljava/net/InetSocketAddress;");
+ socketaddr_object = env->GetObjectField(channel_object, socketaddr_field);
+ if (NULL == socketaddr_object) {
+ goto clean;
+ }
+ addr_field = env->GetFieldID(socketaddr_class, "addr",
+ "Ljava/net/InetAddress;");
+ env->SetObjectField(socketaddr_object, addr_field, addr_object);
+ addr_array = env->NewByteArray((jsize)4);
+ env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+ env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress, addr_array);
+
+ // set bound
+ if (0 != local_addr.sin_port) {
+ bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+ env->SetBooleanField(channel_object, bound_field, jtrue);
+ }
+ }
+clean:
+ free(address);
+ free(localAddr);
+ return channel_object;
+}
+*/