jni/OSNetworkSystem.cpp
changeset 823 2036ebfaccda
equal deleted inserted replaced
536:537ddd8aa407 823:2036ebfaccda
       
     1 /*
       
     2  * Copyright (C) 2009 The Sipdroid Open Source Project
       
     3  * Copyright (C) 2007 The Android Open Source Project
       
     4  * 
       
     5  * This file is part of Sipdroid (http://www.sipdroid.org)
       
     6  * 
       
     7  * Sipdroid is free software; you can redistribute it and/or modify
       
     8  * it under the terms of the GNU General Public License as published by
       
     9  * the Free Software Foundation; either version 3 of the License, or
       
    10  * (at your option) any later version.
       
    11  * 
       
    12  * This source code is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    15  * GNU General Public License for more details.
       
    16  * 
       
    17  * You should have received a copy of the GNU General Public License
       
    18  * along with this source code; if not, write to the Free Software
       
    19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    20  */
       
    21 
       
    22 #define LOG_TAG "OSNetworkSystem"
       
    23 
       
    24 #include <android/log.h>
       
    25 #include "jni.h"
       
    26 #include "errno.h"
       
    27 
       
    28 #include <unistd.h>
       
    29 #include <stdio.h>
       
    30 #include <sys/socket.h>
       
    31 #include <netinet/in.h>
       
    32 #include <netinet/tcp.h>
       
    33 #include <netdb.h>
       
    34 #include <sys/time.h>
       
    35 #include <stdlib.h>
       
    36 #include <sys/ioctl.h>
       
    37 #include <sys/un.h>
       
    38 
       
    39 //#include <cutils/properties.h>
       
    40 //#include <cutils/adb_networking.h>
       
    41 //#include <utils/LogSocket.h>
       
    42 //#include "AndroidSystemNatives.h"
       
    43 
       
    44 /**
       
    45  * @name Socket Errors
       
    46  * Error codes for socket operations
       
    47  *
       
    48  * @internal SOCKERR* range from -200 to -299 avoid overlap
       
    49  */
       
    50 #define SOCKERR_BADSOCKET          -200 /* generic error */
       
    51 #define SOCKERR_NOTINITIALIZED     -201 /* socket library uninitialized */
       
    52 #define SOCKERR_BADAF              -202 /* bad address family */
       
    53 #define SOCKERR_BADPROTO           -203 /* bad protocol */
       
    54 #define SOCKERR_BADTYPE            -204 /* bad type */
       
    55 #define SOCKERR_SYSTEMBUSY         -205 /* system busy handling requests */
       
    56 #define SOCKERR_SYSTEMFULL         -206 /* too many sockets */
       
    57 #define SOCKERR_NOTCONNECTED       -207 /* socket is not connected */
       
    58 #define SOCKERR_INTERRUPTED        -208 /* the call was cancelled */
       
    59 #define SOCKERR_TIMEOUT            -209 /* the operation timed out */
       
    60 #define SOCKERR_CONNRESET          -210 /* the connection was reset */
       
    61 #define SOCKERR_WOULDBLOCK         -211 /* the socket is marked as nonblocking operation would block */
       
    62 #define SOCKERR_ADDRNOTAVAIL       -212 /* address not available */
       
    63 #define SOCKERR_ADDRINUSE          -213 /* address already in use */
       
    64 #define SOCKERR_NOTBOUND           -214 /* the socket is not bound */
       
    65 #define SOCKERR_UNKNOWNSOCKET      -215 /* resolution of fileDescriptor to socket failed */
       
    66 #define SOCKERR_INVALIDTIMEOUT     -216 /* the specified timeout is invalid */
       
    67 #define SOCKERR_FDSETFULL          -217 /* Unable to create an FDSET */
       
    68 #define SOCKERR_TIMEVALFULL        -218 /* Unable to create a TIMEVAL */
       
    69 #define SOCKERR_REMSOCKSHUTDOWN    -219 /* The remote socket has shutdown gracefully */
       
    70 #define SOCKERR_NOTLISTENING       -220 /* listen() was not invoked prior to accept() */
       
    71 #define SOCKERR_NOTSTREAMSOCK      -221 /* The socket does not support connection-oriented service */
       
    72 #define SOCKERR_ALREADYBOUND       -222 /* The socket is already bound to an address */
       
    73 #define SOCKERR_NBWITHLINGER       -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
       
    74 #define SOCKERR_ISCONNECTED        -224 /* The socket is already connected */
       
    75 #define SOCKERR_NOBUFFERS          -225 /* No buffer space is available */
       
    76 #define SOCKERR_HOSTNOTFOUND       -226 /* Authoritative Answer Host not found */
       
    77 #define SOCKERR_NODATA             -227 /* Valid name, no data record of requested type */
       
    78 #define SOCKERR_BOUNDORCONN        -228 /* The socket has not been bound or is already connected */
       
    79 #define SOCKERR_OPNOTSUPP          -229 /* The socket does not support the operation */
       
    80 #define SOCKERR_OPTUNSUPP          -230 /* The socket option is not supported */
       
    81 #define SOCKERR_OPTARGSINVALID     -231 /* The socket option arguments are invalid */
       
    82 #define SOCKERR_SOCKLEVELINVALID   -232 /* The socket level is invalid */
       
    83 #define SOCKERR_TIMEOUTFAILURE     -233
       
    84 #define SOCKERR_SOCKADDRALLOCFAIL  -234 /* Unable to allocate the sockaddr structure */
       
    85 #define SOCKERR_FDSET_SIZEBAD      -235 /* The calculated maximum size of the file descriptor set is bad */
       
    86 #define SOCKERR_UNKNOWNFLAG        -236 /* The flag is unknown */
       
    87 #define SOCKERR_MSGSIZE            -237 /* The datagram was too big to fit the specified buffer & was truncated. */
       
    88 #define SOCKERR_NORECOVERY         -238 /* The operation failed with no recovery possible */
       
    89 #define SOCKERR_ARGSINVALID        -239 /* The arguments are invalid */
       
    90 #define SOCKERR_BADDESC            -240 /* The socket argument is not a valid file descriptor */
       
    91 #define SOCKERR_NOTSOCK            -241 /* The socket argument is not a socket */
       
    92 #define SOCKERR_HOSTENTALLOCFAIL   -242 /* Unable to allocate the hostent structure */
       
    93 #define SOCKERR_TIMEVALALLOCFAIL   -243 /* Unable to allocate the timeval structure */
       
    94 #define SOCKERR_LINGERALLOCFAIL    -244 /* Unable to allocate the linger structure */
       
    95 #define SOCKERR_IPMREQALLOCFAIL    -245 /* Unable to allocate the ipmreq structure */
       
    96 #define SOCKERR_FDSETALLOCFAIL     -246 /* Unable to allocate the fdset structure */
       
    97 #define SOCKERR_OPFAILED           -247 /* Operation failed */
       
    98 #define SOCKERR_VALUE_NULL         -248 /* The value indexed was NULL */
       
    99 #define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
       
   100 #define SOCKERR_ENETUNREACH        -250 /* network is not reachable */
       
   101 #define SOCKERR_EACCES             -251 /* permissions do not allow action on socket */
       
   102 #define SOCKERR_EHOSTUNREACH       -252 /* no route to host */
       
   103 #define SOCKERR_EPIPE              -253 /* broken pipe */
       
   104 
       
   105 #define JAVASOCKOPT_TCP_NODELAY 1
       
   106 #define JAVASOCKOPT_IP_TOS 3
       
   107 #define JAVASOCKOPT_SO_REUSEADDR 4
       
   108 #define JAVASOCKOPT_SO_KEEPALIVE 8
       
   109 #define JAVASOCKOPT_MCAST_TIME_TO_LIVE 10 /* Currently unused */
       
   110 #define JAVASOCKOPT_SO_BINDADDR 15
       
   111 #define JAVASOCKOPT_MCAST_INTERFACE 16
       
   112 #define JAVASOCKOPT_MCAST_TTL 17
       
   113 #define JAVASOCKOPT_IP_MULTICAST_LOOP 18
       
   114 #define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
       
   115 #define JAVASOCKOPT_MCAST_DROP_MEMBERSHIP 20
       
   116 #define JAVASOCKOPT_IP_MULTICAST_IF2 31
       
   117 #define JAVASOCKOPT_SO_BROADCAST 32
       
   118 #define JAVASOCKOPT_SO_LINGER 128
       
   119 #define JAVASOCKOPT_REUSEADDR_AND_REUSEPORT  10001
       
   120 #define JAVASOCKOPT_SO_SNDBUF 4097
       
   121 #define JAVASOCKOPT_SO_RCVBUF 4098
       
   122 #define JAVASOCKOPT_SO_RCVTIMEOUT  4102
       
   123 #define JAVASOCKOPT_SO_OOBINLINE  4099
       
   124 
       
   125 /* constants for calling multi-call functions */
       
   126 #define SOCKET_STEP_START 10
       
   127 #define SOCKET_STEP_CHECK 20
       
   128 #define SOCKET_STEP_DONE 30
       
   129 
       
   130 #define BROKEN_MULTICAST_IF 1
       
   131 #define BROKEN_MULTICAST_TTL 2
       
   132 #define BROKEN_TCP_NODELAY 4
       
   133 
       
   134 #define SOCKET_CONNECT_STEP_START 0
       
   135 #define SOCKET_CONNECT_STEP_CHECK 1
       
   136 
       
   137 #define SOCKET_OP_NONE 0
       
   138 #define SOCKET_OP_READ 1
       
   139 #define SOCKET_OP_WRITE 2
       
   140 #define SOCKET_READ_WRITE 3
       
   141 
       
   142 #define SOCKET_MSG_PEEK 1
       
   143 #define SOCKET_MSG_OOB 2
       
   144 
       
   145 #define SOCKET_NOFLAGS 0
       
   146 
       
   147 #undef BUFFERSIZE
       
   148 #define BUFFERSIZE 2048
       
   149 
       
   150 // wait for 500000 usec = 0.5 second
       
   151 #define SEND_RETRY_TIME 500000
       
   152 
       
   153 
       
   154 struct CachedFields {
       
   155     jfieldID fd_descriptor;
       
   156     jclass iaddr_class;
       
   157     jmethodID iaddr_class_init;
       
   158     jmethodID iaddr_getbyaddress;
       
   159     jfieldID iaddr_ipaddress;
       
   160     jclass genericipmreq_class;
       
   161     jclass integer_class;
       
   162     jmethodID integer_class_init;
       
   163     jfieldID integer_class_value;
       
   164     jclass boolean_class;
       
   165     jmethodID boolean_class_init;
       
   166     jfieldID boolean_class_value;
       
   167     jclass byte_class;
       
   168     jmethodID byte_class_init;
       
   169     jfieldID byte_class_value;
       
   170     jclass string_class;
       
   171     jmethodID string_class_init;
       
   172     jfieldID socketimpl_address;
       
   173     jfieldID socketimpl_port;
       
   174     jclass dpack_class;
       
   175     jfieldID dpack_address;
       
   176     jfieldID dpack_port;
       
   177     jfieldID dpack_length;
       
   178     jclass fd_class;
       
   179     jfieldID descriptor;
       
   180 } gCachedFields;
       
   181 
       
   182 static int useAdbNetworking = 0;
       
   183 
       
   184 /* needed for connecting with timeout */
       
   185 typedef struct selectFDSet {
       
   186   int nfds;
       
   187   int sock;
       
   188   fd_set writeSet;
       
   189   fd_set readSet;
       
   190   fd_set exceptionSet;
       
   191 } selectFDSet;
       
   192 
       
   193 static const char * netLookupErrorString(int anErrorNum);
       
   194 
       
   195 #define log_socket_close(a,b)
       
   196 #define log_socket_connect(a,b,c)
       
   197 #define add_send_stats(a,b)
       
   198 #define add_recv_stats(a,b)
       
   199 #define adb_networking_connect_fd(a,b) 0
       
   200 #define adb_networking_gethostbyname(a,b) 0
       
   201 #define PROPERTY_VALUE_MAX 1
       
   202 #define property_get(a,b,c)
       
   203 #define assert(a)
       
   204 /*
       
   205  * Throw an exception with the specified class and an optional message.
       
   206  */
       
   207 int jniThrowException(JNIEnv* env, const char* className, const char* msg)
       
   208 {
       
   209     jclass exceptionClass;
       
   210 
       
   211     exceptionClass = env->FindClass(className);
       
   212     if (exceptionClass == NULL) {
       
   213 //        LOGE("Unable to find exception class %s\n", className);
       
   214         assert(0);      /* fatal during dev; should always be fatal? */
       
   215         return -1;
       
   216     }
       
   217 
       
   218     if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {
       
   219 //        LOGE("Failed throwing '%s' '%s'\n", className, msg);
       
   220         assert(!"failed to throw");
       
   221     }
       
   222     return 0;
       
   223 }
       
   224 
       
   225 /*
       
   226  * Internal helper function.
       
   227  *
       
   228  * Get the file descriptor.
       
   229  */
       
   230 static inline int getFd(JNIEnv* env, jobject obj)
       
   231 {
       
   232     return env->GetIntField(obj, gCachedFields.descriptor);
       
   233 }
       
   234 
       
   235 /*
       
   236  * Internal helper function.
       
   237  *
       
   238  * Set the file descriptor.
       
   239  */
       
   240 static inline void setFd(JNIEnv* env, jobject obj, jint value)
       
   241 {
       
   242     env->SetIntField(obj, gCachedFields.descriptor, value);
       
   243 }
       
   244 
       
   245 /* 
       
   246  * For JNIHelp.c
       
   247  * Get an int file descriptor from a java.io.FileDescriptor
       
   248  */
       
   249 
       
   250 static int jniGetFDFromFileDescriptor (JNIEnv* env, jobject fileDescriptor) {
       
   251 
       
   252     return getFd(env, fileDescriptor);
       
   253 }
       
   254 
       
   255 /*
       
   256  * For JNIHelp.c
       
   257  * Set the descriptor of a java.io.FileDescriptor
       
   258  */
       
   259 
       
   260 static void jniSetFileDescriptorOfFD (JNIEnv* env, jobject fileDescriptor, int value) {
       
   261 
       
   262     setFd(env, fileDescriptor, value);
       
   263 }
       
   264 
       
   265 /**
       
   266  * Throws an SocketException with the message affiliated with the errorCode.
       
   267  */
       
   268 static void throwSocketException(JNIEnv *env, int errorCode) {
       
   269     jniThrowException(env, "java/net/SocketException",
       
   270         netLookupErrorString(errorCode));
       
   271 }
       
   272 
       
   273 /**
       
   274  * Throws an IOException with the given message.
       
   275  */
       
   276 static void throwIOExceptionStr(JNIEnv *env, const char *message) {
       
   277     jniThrowException(env, "java/io/IOException", message);
       
   278 }
       
   279 
       
   280 /**
       
   281  * Throws a NullPointerException.
       
   282  */
       
   283 static void throwNullPointerException(JNIEnv *env) {
       
   284     jniThrowException(env, "java/lang/NullPointerException", NULL);
       
   285 }
       
   286 
       
   287 /**
       
   288  * Converts a 4-byte array to a native address structure. Throws a
       
   289  * NullPointerException or an IOException in case of error. This is
       
   290  * signaled by a return value of -1. The normal return value is 0.
       
   291  */
       
   292 static int javaAddressToStructIn(
       
   293         JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
       
   294 
       
   295     memset(address, 0, sizeof(address));
       
   296 
       
   297     if (java_address == NULL) {
       
   298         return -1;
       
   299     }
       
   300 
       
   301     if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
       
   302         return -1;
       
   303     }
       
   304 
       
   305     jbyte * java_address_bytes
       
   306         =  env->GetByteArrayElements(java_address, NULL);
       
   307 
       
   308     memcpy(&(address->s_addr),
       
   309         java_address_bytes,
       
   310         sizeof(address->s_addr));
       
   311 
       
   312     env->ReleaseByteArrayElements(java_address, java_address_bytes, JNI_ABORT);
       
   313 
       
   314     return 0;
       
   315 }
       
   316 
       
   317 /**
       
   318  * Converts a native address structure to a 4-byte array. Throws a
       
   319  * NullPointerException or an IOException in case of error. This is
       
   320  * signaled by a return value of -1. The normal return value is 0.
       
   321  */
       
   322 static int structInToJavaAddress(
       
   323         JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
       
   324 
       
   325     if (java_address == NULL) {
       
   326         return -1;
       
   327     }
       
   328 
       
   329     if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
       
   330         return -1;
       
   331     }
       
   332 
       
   333     jbyte *java_address_bytes;
       
   334 
       
   335     java_address_bytes = env->GetByteArrayElements(java_address, NULL);
       
   336 
       
   337     memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
       
   338 
       
   339     env->ReleaseByteArrayElements(java_address, java_address_bytes, 0);
       
   340 
       
   341     return 0;
       
   342 }
       
   343 
       
   344 /**
       
   345  * Converts a native address structure to an InetAddress object.
       
   346  * Throws a NullPointerException or an IOException in case of
       
   347  * error. This is signaled by a return value of -1. The normal
       
   348  * return value is 0.
       
   349  */
       
   350 static int socketAddressToInetAddress(JNIEnv *env,
       
   351         struct sockaddr_in *sockaddress, jobject inetaddress, int *port) {
       
   352 
       
   353     jbyteArray ipaddress;
       
   354     int result;
       
   355 
       
   356     ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
       
   357             gCachedFields.iaddr_ipaddress);
       
   358 
       
   359     if (structInToJavaAddress(env, &sockaddress->sin_addr, ipaddress) < 0) {
       
   360         return -1;
       
   361     }
       
   362 
       
   363     *port = ntohs(sockaddress->sin_port);
       
   364 
       
   365     return 0;
       
   366 }
       
   367 
       
   368 /**
       
   369  * Converts an InetAddress object to a native address structure.
       
   370  * Throws a NullPointerException or an IOException in case of
       
   371  * error. This is signaled by a return value of -1. The normal
       
   372  * return value is 0.
       
   373  */
       
   374 static int inetAddressToSocketAddress(JNIEnv *env,
       
   375         jobject inetaddress, int port, struct sockaddr_in *sockaddress) {
       
   376 
       
   377     jbyteArray ipaddress;
       
   378     int result;
       
   379 
       
   380     ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
       
   381             gCachedFields.iaddr_ipaddress);
       
   382 
       
   383     memset(sockaddress, 0, sizeof(sockaddress));
       
   384 
       
   385     sockaddress->sin_family = AF_INET;
       
   386     sockaddress->sin_port = htons(port);
       
   387 
       
   388     if (javaAddressToStructIn(env, ipaddress, &(sockaddress->sin_addr)) < 0) {
       
   389         return -1;
       
   390     }
       
   391 
       
   392     return 0;
       
   393 }
       
   394 
       
   395 static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
       
   396     jbyteArray bytes;
       
   397     int success;
       
   398 
       
   399     bytes = env->NewByteArray(4);
       
   400 
       
   401     if (bytes == NULL) {
       
   402         return NULL;
       
   403     }
       
   404 
       
   405     if (structInToJavaAddress(env, address, bytes) < 0) {
       
   406         return NULL;
       
   407     }
       
   408 
       
   409     return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
       
   410             gCachedFields.iaddr_getbyaddress, bytes);
       
   411 }
       
   412 
       
   413 /**
       
   414  * Answer a new java.lang.Boolean object.
       
   415  *
       
   416  * @param env   pointer to the JNI library
       
   417  * @param anInt the Boolean constructor argument
       
   418  *
       
   419  * @return  the new Boolean
       
   420  */
       
   421 
       
   422 static jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
       
   423     jclass tempClass;
       
   424     jmethodID tempMethod;
       
   425 
       
   426     tempClass = gCachedFields.boolean_class;
       
   427     tempMethod = gCachedFields.boolean_class_init;
       
   428     return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
       
   429 }
       
   430 
       
   431 /**
       
   432  * Answer a new java.lang.Byte object.
       
   433  *
       
   434  * @param env   pointer to the JNI library
       
   435  * @param anInt the Byte constructor argument
       
   436  *
       
   437  * @return  the new Byte
       
   438  */
       
   439 
       
   440 static jobject newJavaLangByte(JNIEnv * env, jbyte val) {
       
   441     jclass tempClass;
       
   442     jmethodID tempMethod;
       
   443 
       
   444     tempClass = gCachedFields.byte_class;
       
   445     tempMethod = gCachedFields.byte_class_init;
       
   446     return env->NewObject(tempClass, tempMethod, val);
       
   447 }
       
   448 
       
   449 /**
       
   450  * Answer a new java.lang.Integer object.
       
   451  *
       
   452  * @param env   pointer to the JNI library
       
   453  * @param anInt the Integer constructor argument
       
   454  *
       
   455  * @return  the new Integer
       
   456  */
       
   457 
       
   458 static jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
       
   459     jclass tempClass;
       
   460     jmethodID tempMethod;
       
   461 
       
   462     tempClass = gCachedFields.integer_class;
       
   463     tempMethod = gCachedFields.integer_class_init;
       
   464     return env->NewObject(tempClass, tempMethod, anInt);
       
   465 }
       
   466 
       
   467 /**
       
   468  * Answer a new java.lang.String object.
       
   469  *
       
   470  * @param env   pointer to the JNI library
       
   471  * @param anInt the byte[] constructor argument
       
   472  *
       
   473  * @return  the new String
       
   474  */
       
   475 
       
   476 static jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
       
   477     jclass tempClass;
       
   478     jmethodID tempMethod;
       
   479 
       
   480     tempClass = gCachedFields.string_class;
       
   481     tempMethod = gCachedFields.string_class_init;
       
   482     return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
       
   483 }
       
   484 
       
   485 /**
       
   486  * Query OS for timestamp.
       
   487  * Retrieve the current value of system clock and convert to milliseconds.
       
   488  *
       
   489  * @param[in] portLibrary The port library.
       
   490  *
       
   491  * @return 0 on failure, time value in milliseconds on success.
       
   492  * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
       
   493  *
       
   494  * technically, this should return I_64 since both timeval.tv_sec and
       
   495  * timeval.tv_usec are long
       
   496  */
       
   497 
       
   498 static int time_msec_clock() {
       
   499     struct timeval tp;
       
   500     struct timezone tzp;
       
   501 
       
   502     gettimeofday(&tp, &tzp);
       
   503     return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
       
   504 }
       
   505 
       
   506 /**
       
   507  * check if the passed sockaddr_in struct contains a localhost address
       
   508  *
       
   509  * @param[in] address pointer to the address to check
       
   510  *
       
   511  * @return 0 if the passed address isn't a localhost address
       
   512  */
       
   513 static int isLocalhost(struct sockaddr_in *address) {
       
   514     // return address == 127.0.0.1
       
   515     return (unsigned int) address->sin_addr.s_addr == 16777343;
       
   516 }
       
   517 
       
   518 /**
       
   519  * Answer the errorString corresponding to the errorNumber, if available.
       
   520  * This function will answer a default error string, if the errorNumber is not
       
   521  * recognized.
       
   522  *
       
   523  * This function will have to be reworked to handle internationalization
       
   524  * properly, removing the explicit strings.
       
   525  *
       
   526  * @param anErrorNum    the error code to resolve to a human readable string
       
   527  *
       
   528  * @return  a human readable error string
       
   529  */
       
   530 
       
   531 static const char * netLookupErrorString(int anErrorNum) {
       
   532     switch (anErrorNum) {
       
   533         case SOCKERR_BADSOCKET:
       
   534             return "Bad socket";
       
   535         case SOCKERR_NOTINITIALIZED:
       
   536             return "Socket library uninitialized";
       
   537         case SOCKERR_BADAF:
       
   538             return "Bad address family";
       
   539         case SOCKERR_BADPROTO:
       
   540             return "Bad protocol";
       
   541         case SOCKERR_BADTYPE:
       
   542             return "Bad type";
       
   543         case SOCKERR_SYSTEMBUSY:
       
   544             return "System busy handling requests";
       
   545         case SOCKERR_SYSTEMFULL:
       
   546             return "Too many sockets allocated";
       
   547         case SOCKERR_NOTCONNECTED:
       
   548             return "Socket is not connected";
       
   549         case SOCKERR_INTERRUPTED:
       
   550             return "The system call was cancelled";
       
   551         case SOCKERR_TIMEOUT:
       
   552             return "The operation timed out";
       
   553         case SOCKERR_CONNRESET:
       
   554             return "The connection was reset";
       
   555         case SOCKERR_WOULDBLOCK:
       
   556             return "The nonblocking operation would block";
       
   557         case SOCKERR_ADDRNOTAVAIL:
       
   558             return "The address is not available";
       
   559         case SOCKERR_ADDRINUSE:
       
   560             return "The address is already in use";
       
   561         case SOCKERR_NOTBOUND:
       
   562             return "The socket is not bound";
       
   563         case SOCKERR_UNKNOWNSOCKET:
       
   564             return "Resolution of the FileDescriptor to socket failed";
       
   565         case SOCKERR_INVALIDTIMEOUT:
       
   566             return "The specified timeout is invalid";
       
   567         case SOCKERR_FDSETFULL:
       
   568             return "Unable to create an FDSET";
       
   569         case SOCKERR_TIMEVALFULL:
       
   570             return "Unable to create a TIMEVAL";
       
   571         case SOCKERR_REMSOCKSHUTDOWN:
       
   572             return "The remote socket has shutdown gracefully";
       
   573         case SOCKERR_NOTLISTENING:
       
   574             return "Listen() was not invoked prior to accept()";
       
   575         case SOCKERR_NOTSTREAMSOCK:
       
   576             return "The socket does not support connection-oriented service";
       
   577         case SOCKERR_ALREADYBOUND:
       
   578             return "The socket is already bound to an address";
       
   579         case SOCKERR_NBWITHLINGER:
       
   580             return "The socket is marked non-blocking & SO_LINGER is non-zero";
       
   581         case SOCKERR_ISCONNECTED:
       
   582             return "The socket is already connected";
       
   583         case SOCKERR_NOBUFFERS:
       
   584             return "No buffer space is available";
       
   585         case SOCKERR_HOSTNOTFOUND:
       
   586             return "Authoritative Answer Host not found";
       
   587         case SOCKERR_NODATA:
       
   588             return "Valid name, no data record of requested type";
       
   589         case SOCKERR_BOUNDORCONN:
       
   590             return "The socket has not been bound or is already connected";
       
   591         case SOCKERR_OPNOTSUPP:
       
   592             return "The socket does not support the operation";
       
   593         case SOCKERR_OPTUNSUPP:
       
   594             return "The socket option is not supported";
       
   595         case SOCKERR_OPTARGSINVALID:
       
   596             return "The socket option arguments are invalid";
       
   597         case SOCKERR_SOCKLEVELINVALID:
       
   598             return "The socket level is invalid";
       
   599         case SOCKERR_TIMEOUTFAILURE:
       
   600             return "The timeout operation failed";
       
   601         case SOCKERR_SOCKADDRALLOCFAIL:
       
   602             return "Failed to allocate address structure";
       
   603         case SOCKERR_FDSET_SIZEBAD:
       
   604             return "The calculated maximum size of the file descriptor set is bad";
       
   605         case SOCKERR_UNKNOWNFLAG:
       
   606             return "The flag is unknown";
       
   607         case SOCKERR_MSGSIZE:
       
   608             return "The datagram was too big to fit the specified buffer, so truncated";
       
   609         case SOCKERR_NORECOVERY:
       
   610             return "The operation failed with no recovery possible";
       
   611         case SOCKERR_ARGSINVALID:
       
   612             return "The arguments are invalid";
       
   613         case SOCKERR_BADDESC:
       
   614             return "The socket argument is not a valid file descriptor";
       
   615         case SOCKERR_NOTSOCK:
       
   616             return "The socket argument is not a socket";
       
   617         case SOCKERR_HOSTENTALLOCFAIL:
       
   618             return "Unable to allocate the hostent structure";
       
   619         case SOCKERR_TIMEVALALLOCFAIL:
       
   620             return "Unable to allocate the timeval structure";
       
   621         case SOCKERR_LINGERALLOCFAIL:
       
   622             return "Unable to allocate the linger structure";
       
   623         case SOCKERR_IPMREQALLOCFAIL:
       
   624             return "Unable to allocate the ipmreq structure";
       
   625         case SOCKERR_FDSETALLOCFAIL:
       
   626             return "Unable to allocate the fdset structure";
       
   627         case SOCKERR_OPFAILED:
       
   628             return "Operation failed";
       
   629         case SOCKERR_CONNECTION_REFUSED:
       
   630             return "Connection refused";
       
   631         case SOCKERR_ENETUNREACH:
       
   632             return "Network unreachable";
       
   633         case SOCKERR_EHOSTUNREACH:
       
   634             return "No route to host";
       
   635         case SOCKERR_EPIPE:
       
   636             return "Broken pipe";
       
   637         case SOCKERR_EACCES:
       
   638             return "Permission denied (maybe missing INTERNET permission)";
       
   639 
       
   640         default:
       
   641 //            LOGE("unknown socket error %d", anErrorNum);
       
   642             return "unknown error";
       
   643     }
       
   644 }
       
   645 
       
   646 static int convertError(int errorCode) {
       
   647     switch (errorCode) {
       
   648         case EBADF:
       
   649             return SOCKERR_BADDESC;
       
   650         case ENOBUFS:
       
   651             return SOCKERR_NOBUFFERS;
       
   652         case EOPNOTSUPP:
       
   653             return SOCKERR_OPNOTSUPP;
       
   654         case ENOPROTOOPT:
       
   655             return SOCKERR_OPTUNSUPP;
       
   656         case EINVAL:
       
   657             return SOCKERR_SOCKLEVELINVALID;
       
   658         case ENOTSOCK:
       
   659             return SOCKERR_NOTSOCK;
       
   660         case EINTR:
       
   661             return SOCKERR_INTERRUPTED;
       
   662         case ENOTCONN:
       
   663             return SOCKERR_NOTCONNECTED;
       
   664         case EAFNOSUPPORT:
       
   665             return SOCKERR_BADAF;
       
   666             /* note: CONNRESET not included because it has the same
       
   667              * value as ECONNRESET and they both map to SOCKERR_CONNRESET */
       
   668         case ECONNRESET:
       
   669             return SOCKERR_CONNRESET;
       
   670         case EAGAIN:
       
   671             return SOCKERR_WOULDBLOCK;
       
   672         case EPROTONOSUPPORT:
       
   673             return SOCKERR_BADPROTO;
       
   674         case EFAULT:
       
   675             return SOCKERR_ARGSINVALID;
       
   676         case ETIMEDOUT:
       
   677             return SOCKERR_TIMEOUT;
       
   678         case ECONNREFUSED:
       
   679             return SOCKERR_CONNECTION_REFUSED;
       
   680         case ENETUNREACH:
       
   681             return SOCKERR_ENETUNREACH;
       
   682         case EACCES:
       
   683             return SOCKERR_EACCES;
       
   684         case EPIPE:
       
   685             return SOCKERR_EPIPE;
       
   686         case EHOSTUNREACH:
       
   687             return SOCKERR_EHOSTUNREACH;
       
   688         case EADDRINUSE:
       
   689             return SOCKERR_ADDRINUSE;
       
   690         case EADDRNOTAVAIL:
       
   691             return SOCKERR_ADDRNOTAVAIL;
       
   692         case EMSGSIZE:
       
   693             return SOCKERR_MSGSIZE;
       
   694         default:
       
   695 //            LOGE("unclassified errno %d (%s)", errorCode, strerror(errorCode));
       
   696             return SOCKERR_OPFAILED;
       
   697     }
       
   698 }
       
   699 
       
   700 static int sockSelect(int nfds, fd_set *readfds, fd_set *writefds,
       
   701         fd_set *exceptfds, struct timeval *timeout) {
       
   702 
       
   703     int result = select(nfds, readfds, writefds, exceptfds, timeout);
       
   704 
       
   705     if (result < 0) {
       
   706         if (errno == EINTR) {
       
   707             result = SOCKERR_INTERRUPTED;
       
   708         } else {
       
   709             result = SOCKERR_OPFAILED;
       
   710         }
       
   711     } else if (result == 0) {
       
   712         result = SOCKERR_TIMEOUT;
       
   713     }
       
   714     return result;
       
   715 }
       
   716 
       
   717 #define SELECT_READ_TYPE 0
       
   718 #define SELECT_WRITE_TYPE 1
       
   719 
       
   720 static int selectWait(int handle, int uSecTime, int type) {
       
   721     fd_set fdset;
       
   722     struct timeval time, *timePtr;
       
   723     int result = 0;
       
   724     int size = handle + 1;
       
   725 
       
   726     FD_ZERO(&fdset);
       
   727     FD_SET(handle, &fdset);
       
   728 
       
   729     if (0 <= uSecTime) {
       
   730         /* Use a timeout if uSecTime >= 0 */
       
   731         memset(&time, 0, sizeof(time));
       
   732         time.tv_usec = uSecTime;
       
   733         timePtr = &time;
       
   734     } else {
       
   735         /* Infinite timeout if uSecTime < 0 */
       
   736         timePtr = NULL;
       
   737     }
       
   738 
       
   739     if (type == SELECT_READ_TYPE) {
       
   740         result = sockSelect(size, &fdset, NULL, NULL, timePtr);
       
   741     } else {
       
   742         result = sockSelect(size, NULL, &fdset, NULL, timePtr);
       
   743     }
       
   744     return result;
       
   745 }
       
   746 
       
   747 static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int type) {
       
   748     /* now try reading the socket for the timespan timeout.
       
   749      * if timeout is 0 try forever until the soclets gets ready or until an
       
   750      * exception occurs.
       
   751      */
       
   752     int pollTimeoutUSec = 100000, pollMsec = 100;
       
   753     int finishTime = 0;
       
   754     int timeLeft = timeout;
       
   755     int hasTimeout = timeout > 0 ? 1 : 0;
       
   756     int result = 0;
       
   757     int handle;
       
   758 
       
   759     if (hasTimeout) {
       
   760         finishTime = time_msec_clock() + timeout;
       
   761     }
       
   762 
       
   763     int poll = 1;
       
   764 
       
   765     while (poll) { /* begin polling loop */
       
   766 
       
   767         /*
       
   768          * Fetch the handle every time in case the socket is closed.
       
   769          */
       
   770         handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
   771 
       
   772         if (handle == 0 || handle == -1) {
       
   773             throwSocketException(env, SOCKERR_INTERRUPTED);
       
   774             return -1;
       
   775         }
       
   776 
       
   777         if (hasTimeout) {
       
   778 
       
   779             if (timeLeft - 10 < pollMsec) {
       
   780                 pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
       
   781             }
       
   782 
       
   783             result = selectWait(handle, pollTimeoutUSec, type);
       
   784 
       
   785             /*
       
   786              * because we are polling at a time smaller than timeout
       
   787              * (presumably) lets treat an interrupt and timeout the same - go
       
   788              * see if we're done timewise, and then just try again if not.
       
   789              */
       
   790             if (SOCKERR_TIMEOUT == result ||
       
   791                 SOCKERR_INTERRUPTED == result) {
       
   792 
       
   793                 timeLeft = finishTime - time_msec_clock();
       
   794 
       
   795                 if (timeLeft <= 0) {
       
   796                     /*
       
   797                      * Always throw the "timeout" message because that is
       
   798                      * effectively what has happened, even if we happen to
       
   799                      * have been interrupted.
       
   800                      */
       
   801                     jniThrowException(env, "java/net/SocketTimeoutException",
       
   802                             netLookupErrorString(SOCKERR_TIMEOUT));
       
   803                 } else {
       
   804                     continue; // try again
       
   805                 }
       
   806 
       
   807             } else if (0 > result) {
       
   808                 log_socket_close(handle, result);
       
   809                 throwSocketException(env, result);
       
   810             }
       
   811             poll = 0;
       
   812 
       
   813         } else { /* polling with no timeout (why would you do this?)*/
       
   814 
       
   815             result = selectWait(handle, pollTimeoutUSec, type);
       
   816 
       
   817             /*
       
   818              *  if interrupted (or a timeout) just retry
       
   819              */
       
   820             if (SOCKERR_TIMEOUT == result ||
       
   821                SOCKERR_INTERRUPTED == result) {
       
   822 
       
   823                 continue; // try again
       
   824             } else if (0 > result) {
       
   825                 log_socket_close(handle, result);
       
   826                 throwSocketException(env, result);
       
   827             }
       
   828             poll = 0;
       
   829         }
       
   830     } /* end polling loop */
       
   831 
       
   832     return result;
       
   833 }
       
   834 
       
   835 /**
       
   836  * A helper method, to set the connect context to a Long object.
       
   837  *
       
   838  * @param env  pointer to the JNI library
       
   839  * @param longclass Java Long Object
       
   840  */
       
   841 void setConnectContext(JNIEnv *env,jobject longclass,jbyte * context) {
       
   842     jclass descriptorCLS;
       
   843     jfieldID descriptorFID;
       
   844     descriptorCLS = env->FindClass("java/lang/Long");
       
   845     descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
       
   846     env->SetLongField(longclass, descriptorFID, (jlong)((jint)context));
       
   847 };
       
   848 
       
   849 /**
       
   850  * A helper method, to get the connect context.
       
   851  *
       
   852  * @param env  pointer to the JNI library
       
   853  * @param longclass Java Long Object
       
   854  */
       
   855 jbyte *getConnectContext(JNIEnv *env, jobject longclass) {
       
   856     jclass descriptorCLS;
       
   857     jfieldID descriptorFID;
       
   858     descriptorCLS = env->FindClass("java/lang/Long");
       
   859     descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
       
   860     return (jbyte*) ((jint)env->GetLongField(longclass, descriptorFID));
       
   861 };
       
   862 
       
   863 // typical ip checksum
       
   864 unsigned short ip_checksum(unsigned short* buffer, int size) {
       
   865     register unsigned short * buf = buffer;
       
   866     register int bufleft = size;
       
   867     register unsigned long sum = 0;
       
   868 
       
   869     while (bufleft > 1) {
       
   870         sum = sum + (*buf++);
       
   871         bufleft = bufleft - sizeof(unsigned short );
       
   872     }
       
   873     if (bufleft) {
       
   874         sum = sum + (*(unsigned char*)buf);
       
   875     }
       
   876     sum = (sum >> 16) + (sum & 0xffff);
       
   877     sum += (sum >> 16);
       
   878 
       
   879     return (unsigned short )(~sum);
       
   880 }
       
   881 
       
   882 /**
       
   883  * Establish a connection to a peer with a timeout.  This function is called
       
   884  * repeatedly in order to carry out the connect and to allow other tasks to
       
   885  * proceed on certain platforms. The caller must first call with
       
   886  * step = SOCKET_STEP_START, if the result is SOCKERR_NOTCONNECTED it will then
       
   887  * call it with step = CHECK until either another error or 0 is returned to
       
   888  * indicate the connect is complete.  Each time the function should sleep for no
       
   889  * more than timeout milliseconds.  If the connect succeeds or an error occurs,
       
   890  * the caller must always end the process by calling the function with
       
   891  * step = SOCKET_STEP_DONE
       
   892  *
       
   893  * @param[in] portLibrary The port library.
       
   894  * @param[in] sock pointer to the unconnected local socket.
       
   895  * @param[in] addr pointer to the sockaddr, specifying remote host/port.
       
   896  * @param[in] timeout the timeout in milliseconds. If timeout is negative,
       
   897  *         perform a block operation.
       
   898  * @param[in,out] pointer to context pointer. Filled in on first call and then
       
   899  *         to be passed into each subsequent call.
       
   900  *
       
   901  * @return 0, if no errors occurred, otherwise the (negative) error code.
       
   902  */
       
   903 static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
       
   904         unsigned int timeout, unsigned int step, jbyte *ctxt) {
       
   905     int rc = 0;
       
   906     struct timeval passedTimeout;
       
   907     int errorVal;
       
   908     socklen_t errorValLen = sizeof(int);
       
   909     struct selectFDSet *context = NULL;
       
   910 
       
   911     if (SOCKET_STEP_START == step) {
       
   912 
       
   913         context = (struct selectFDSet *) ctxt;
       
   914 
       
   915         context->sock = handle;
       
   916         context->nfds = handle + 1;
       
   917 
       
   918         if (useAdbNetworking && !isLocalhost(&addr)) {
       
   919 
       
   920             // LOGD("+connect to address 0x%08x (via adb)",
       
   921             //         addr.sin_addr.s_addr);
       
   922             rc = adb_networking_connect_fd(handle, &addr);
       
   923             // LOGD("-connect ret %d errno %d (via adb)", rc, errno);
       
   924 
       
   925         } else {
       
   926             log_socket_connect(handle, ntohl(addr.sin_addr.s_addr),
       
   927                     ntohs(addr.sin_port));
       
   928             /* set the socket to non-blocking */
       
   929             int block = JNI_TRUE;
       
   930             rc = ioctl(handle, FIONBIO, &block);
       
   931             if (0 != rc) {
       
   932                 return convertError(rc);
       
   933             }
       
   934 
       
   935             // LOGD("+connect to address 0x%08x (via normal) on handle %d",
       
   936             //         addr.sin_addr.s_addr, handle);
       
   937             do {
       
   938                 rc = connect(handle, (struct sockaddr *) &addr,
       
   939                         sizeof(struct sockaddr));
       
   940             } while (rc < 0 && errno == EINTR);
       
   941             // LOGD("-connect to address 0x%08x (via normal) returned %d",
       
   942             //         addr.sin_addr.s_addr, (int) rc);
       
   943 
       
   944         }
       
   945 
       
   946         if (rc == -1) {
       
   947             rc = errno;
       
   948             switch (rc) {
       
   949                 case EINTR:
       
   950                     return SOCKERR_ALREADYBOUND;
       
   951                 case EAGAIN:
       
   952                 case EINPROGRESS:
       
   953                     return SOCKERR_NOTCONNECTED;
       
   954                 default:
       
   955                     return convertError(rc);
       
   956             }
       
   957         }
       
   958 
       
   959         /* we connected right off the bat so just return */
       
   960         return rc;
       
   961 
       
   962     } else if (SOCKET_STEP_CHECK == step) {
       
   963         /* now check if we have connected yet */
       
   964 
       
   965         context = (struct selectFDSet *) ctxt;
       
   966 
       
   967         /*
       
   968          * set the timeout value to be used. Because on some unix platforms we
       
   969          * don't get notified when a socket is closed we only sleep for 100ms
       
   970          * at a time
       
   971          */
       
   972         passedTimeout.tv_sec = 0;
       
   973         if (timeout > 100) {
       
   974             passedTimeout.tv_usec = 100 * 1000;
       
   975         } else if ((int)timeout >= 0) {
       
   976           passedTimeout.tv_usec = timeout * 1000;
       
   977         }
       
   978 
       
   979         /* initialize the FD sets for the select */
       
   980         FD_ZERO(&(context->exceptionSet));
       
   981         FD_ZERO(&(context->writeSet));
       
   982         FD_ZERO(&(context->readSet));
       
   983         FD_SET(context->sock, &(context->writeSet));
       
   984         FD_SET(context->sock, &(context->readSet));
       
   985         FD_SET(context->sock, &(context->exceptionSet));
       
   986 
       
   987         rc = select(context->nfds,
       
   988                    &(context->readSet),
       
   989                    &(context->writeSet),
       
   990                    &(context->exceptionSet),
       
   991                    (int)timeout >= 0 ? &passedTimeout : NULL);
       
   992 
       
   993         /* if there is at least one descriptor ready to be checked */
       
   994         if (0 < rc) {
       
   995             /* if the descriptor is in the write set we connected or failed */
       
   996             if (FD_ISSET(context->sock, &(context->writeSet))) {
       
   997 
       
   998                 if (!FD_ISSET(context->sock, &(context->readSet))) {
       
   999                     /* ok we have connected ok */
       
  1000                     return 0;
       
  1001                 } else {
       
  1002                     /* ok we have more work to do to figure it out */
       
  1003                     if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR,
       
  1004                             &errorVal, &errorValLen) >= 0) {
       
  1005                         return errorVal ? convertError(errorVal) : 0;
       
  1006                     } else {
       
  1007                         return convertError(errno);
       
  1008                     }
       
  1009                 }
       
  1010             }
       
  1011 
       
  1012             /* if the descriptor is in the exception set the connect failed */
       
  1013             if (FD_ISSET(context->sock, &(context->exceptionSet))) {
       
  1014                 if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal,
       
  1015                         &errorValLen) >= 0) {
       
  1016                     return errorVal ? convertError(errorVal) : 0;
       
  1017                 }
       
  1018                 rc = errno;
       
  1019                 return convertError(rc);
       
  1020             }
       
  1021 
       
  1022         } else if (rc < 0) {
       
  1023             /* something went wrong with the select call */
       
  1024             rc = errno;
       
  1025 
       
  1026             /* if it was EINTR we can just try again. Return not connected */
       
  1027             if (EINTR == rc) {
       
  1028                 return SOCKERR_NOTCONNECTED;
       
  1029             }
       
  1030 
       
  1031             /* some other error occured so look it up and return */
       
  1032             return convertError(rc);
       
  1033         }
       
  1034 
       
  1035         /*
       
  1036          * if we get here the timeout expired or the connect had not yet
       
  1037          * completed just indicate that the connect is not yet complete
       
  1038          */
       
  1039         return SOCKERR_NOTCONNECTED;
       
  1040     } else if (SOCKET_STEP_DONE == step) {
       
  1041         /* we are done the connect or an error occured so clean up  */
       
  1042         if (handle != -1) {
       
  1043             int block = JNI_FALSE;
       
  1044             ioctl(handle, FIONBIO, &block);
       
  1045         }
       
  1046         return 0;
       
  1047     }
       
  1048     return SOCKERR_ARGSINVALID;
       
  1049 }
       
  1050 
       
  1051 /**
       
  1052  * Join/Leave the nominated multicast group on the specified socket.
       
  1053  * Implemented by setting the multicast 'add membership'/'drop membership'
       
  1054  * option at the HY_IPPROTO_IP level on the socket.
       
  1055  *
       
  1056  * Implementation note for multicast sockets in general:
       
  1057  *
       
  1058  * - This code is untested, because at the time of this writing multicast can't
       
  1059  * be properly tested on Android due to GSM routing restrictions. So it might
       
  1060  * or might not work.
       
  1061  *
       
  1062  * - The REUSEPORT socket option that Harmony employs is not supported on Linux
       
  1063  * and thus also not supported on Android. It's is not needed for multicast
       
  1064  * to work anyway (REUSEADDR should suffice).
       
  1065  *
       
  1066  * @param env pointer to the JNI library.
       
  1067  * @param socketP pointer to the hysocket to join/leave on.
       
  1068  * @param optVal pointer to the InetAddress, the multicast group to join/drop.
       
  1069  *
       
  1070  * @exception SocketException if an error occurs during the call
       
  1071  */
       
  1072 static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
       
  1073         int ignoreIF, int setSockOptVal) {
       
  1074     int result;
       
  1075     struct ip_mreq ipmreqP;
       
  1076     struct sockaddr_in sockaddrP;
       
  1077     int length = sizeof(struct ip_mreq);
       
  1078     socklen_t lengthIF = sizeof(struct sockaddr_in);
       
  1079 
       
  1080     /*
       
  1081      * JNI objects needed to access the information in the optVal oject
       
  1082      * passed in. The object passed in is a GenericIPMreq object
       
  1083      */
       
  1084     jclass cls;
       
  1085     jfieldID multiaddrID;
       
  1086     jfieldID interfaceAddrID;
       
  1087     jobject multiaddr;
       
  1088     jobject interfaceAddr;
       
  1089 
       
  1090     /*
       
  1091      * check whether we are getting an InetAddress or an Generic IPMreq, for now
       
  1092      * we support both so that we will not break the tests
       
  1093      */
       
  1094     if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
       
  1095 
       
  1096         ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
       
  1097         if (!ignoreIF) {
       
  1098 
       
  1099             result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockaddrP,
       
  1100                     &lengthIF);
       
  1101 
       
  1102             if (0 != result) {
       
  1103                 throwSocketException (env, convertError(errno));
       
  1104                 return;
       
  1105             }
       
  1106 
       
  1107             memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
       
  1108         }
       
  1109 
       
  1110         result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
       
  1111 
       
  1112         if (result < 0) {
       
  1113             throwSocketException(env, SOCKERR_BADSOCKET);
       
  1114             return;
       
  1115         }
       
  1116 
       
  1117         memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
       
  1118 
       
  1119         result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
       
  1120         if (0 != result) {
       
  1121             throwSocketException (env, convertError(errno));
       
  1122             return;
       
  1123         }
       
  1124 
       
  1125     } else {
       
  1126 
       
  1127         /* we need the multicast address regardless of the type of address */
       
  1128         cls = env->GetObjectClass(optVal);
       
  1129         multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
       
  1130         multiaddr = env->GetObjectField(optVal, multiaddrID);
       
  1131 
       
  1132         result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
       
  1133 
       
  1134         if (result < 0) {
       
  1135             throwSocketException(env, SOCKERR_BADSOCKET);
       
  1136             return;
       
  1137         }
       
  1138 
       
  1139         memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
       
  1140 
       
  1141         /* we need to use an IP_MREQ as it is an IPV4 address */
       
  1142         interfaceAddrID = env->GetFieldID(cls, "interfaceAddr",
       
  1143                 "Ljava/net/InetAddress;");
       
  1144         interfaceAddr = env->GetObjectField(optVal, interfaceAddrID);
       
  1145 
       
  1146         ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
       
  1147 
       
  1148         /*
       
  1149          * if an interfaceAddr was passed then use that value, otherwise set the
       
  1150          * interface to all 0 to indicate the system should select the interface
       
  1151          * used
       
  1152          */
       
  1153         if (!ignoreIF) {
       
  1154             if (NULL != interfaceAddr) {
       
  1155 
       
  1156                 result = inetAddressToSocketAddress(env, interfaceAddr, 0,
       
  1157                         &sockaddrP);
       
  1158 
       
  1159                 if (result < 0) {
       
  1160                     throwSocketException(env, SOCKERR_BADSOCKET);
       
  1161                     return;
       
  1162                 }
       
  1163 
       
  1164                 memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
       
  1165 
       
  1166             }
       
  1167         }
       
  1168 
       
  1169         /* join/drop the multicast address */
       
  1170         result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
       
  1171         if (0 != result) {
       
  1172             throwSocketException (env, convertError(errno));
       
  1173             return;
       
  1174         }
       
  1175     }
       
  1176 }
       
  1177 
       
  1178 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
       
  1179         jboolean jcl_supports_ipv6) {
       
  1180     // LOGD("ENTER oneTimeInitializationImpl of OSNetworkSystem");
       
  1181 
       
  1182     char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
       
  1183     char adbConnectedProperty[PROPERTY_VALUE_MAX];
       
  1184 
       
  1185     property_get("android.net.use-adb-networking", useAdbNetworkingProperty, "");
       
  1186     property_get("adb.connected", adbConnectedProperty, "");
       
  1187 
       
  1188     if (strlen((char *)useAdbNetworkingProperty) > 0
       
  1189             && strlen((char *)adbConnectedProperty) > 0) {
       
  1190         useAdbNetworking = 1;
       
  1191     }
       
  1192 
       
  1193     memset(&gCachedFields, 0, sizeof(gCachedFields));
       
  1194 
       
  1195     // initializing InetAddress
       
  1196 
       
  1197     jclass iaddrclass = env->FindClass("java/net/InetAddress");
       
  1198 
       
  1199     if (iaddrclass == NULL) {
       
  1200         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1201                 "java.net.InetAddress");
       
  1202         return;
       
  1203     }
       
  1204 
       
  1205     gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass);
       
  1206 
       
  1207     jmethodID iaddrclassinit = env->GetMethodID(iaddrclass, "<init>", "()V");
       
  1208 
       
  1209     if (iaddrclassinit == NULL) {
       
  1210         jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.<init>()");
       
  1211         return;
       
  1212     }
       
  1213 
       
  1214     gCachedFields.iaddr_class_init = iaddrclassinit;
       
  1215 
       
  1216     jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass,
       
  1217             "getByAddress", "([B)Ljava/net/InetAddress;");
       
  1218 
       
  1219     if (iaddrgetbyaddress == NULL) {
       
  1220         jniThrowException(env, "java/lang/NoSuchMethodError",
       
  1221                 "InetAddress.getByAddress(byte[] val)");
       
  1222         return;
       
  1223     }
       
  1224 
       
  1225     gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress;
       
  1226     
       
  1227     jmethodID iaddrgetaddress = env->GetStaticMethodID(iaddrclass,
       
  1228             "getByAddress", "([B)Ljava/net/InetAddress;");
       
  1229 
       
  1230 
       
  1231 
       
  1232 
       
  1233     jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B");
       
  1234 
       
  1235     if (iaddripaddress == NULL) {
       
  1236         jniThrowException(env, "java/lang/NoSuchFieldError",
       
  1237                 "Can't find field InetAddress.ipaddress");
       
  1238         return;
       
  1239     }
       
  1240 
       
  1241     gCachedFields.iaddr_ipaddress = iaddripaddress;
       
  1242 
       
  1243     // get the GenericIPMreq class
       
  1244 
       
  1245     jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq");
       
  1246 
       
  1247     if (genericipmreqclass == NULL) {
       
  1248         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1249                 "org.apache.harmony.luni.net.GenericIPMreq");
       
  1250         return;
       
  1251     }
       
  1252 
       
  1253     gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass);
       
  1254 
       
  1255     // initializing Integer
       
  1256 
       
  1257     jclass integerclass = env->FindClass("java/lang/Integer");
       
  1258 
       
  1259     if (integerclass == NULL) {
       
  1260         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1261                 "java.lang.Integer");
       
  1262         return;
       
  1263     }
       
  1264 
       
  1265     jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V");
       
  1266 
       
  1267     if (integerclassinit == NULL) {
       
  1268         jniThrowException(env, "java/lang/NoSuchMethodError",
       
  1269                 "Integer.<init>(int val)");
       
  1270         return;
       
  1271     }
       
  1272 
       
  1273     jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I");
       
  1274 
       
  1275     if (integerclassvalue == NULL) {
       
  1276         jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value");
       
  1277         return;
       
  1278     }
       
  1279 
       
  1280     gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass);
       
  1281     gCachedFields.integer_class_init = integerclassinit;
       
  1282     gCachedFields.integer_class_value = integerclassvalue;
       
  1283 
       
  1284     // initializing Boolean
       
  1285 
       
  1286     jclass booleanclass = env->FindClass("java/lang/Boolean");
       
  1287 
       
  1288     if (booleanclass == NULL) {
       
  1289         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1290                 "java.lang.Boolean");
       
  1291         return;
       
  1292     }
       
  1293 
       
  1294     jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V");
       
  1295 
       
  1296     if (booleanclassinit == NULL) {
       
  1297         jniThrowException(env, "java/lang/NoSuchMethodError",
       
  1298                 "Boolean.<init>(boolean val)");
       
  1299         return;
       
  1300     }
       
  1301 
       
  1302     jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z");
       
  1303 
       
  1304     if (booleanclassvalue == NULL) {
       
  1305         jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value");
       
  1306         return;
       
  1307     }
       
  1308 
       
  1309     gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass);
       
  1310     gCachedFields.boolean_class_init = booleanclassinit;
       
  1311     gCachedFields.boolean_class_value = booleanclassvalue;
       
  1312 
       
  1313     // initializing Byte
       
  1314 
       
  1315     jclass byteclass = env->FindClass("java/lang/Byte");
       
  1316 
       
  1317     if (byteclass == NULL) {
       
  1318         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1319                 "java.lang.Byte");
       
  1320         return;
       
  1321     }
       
  1322 
       
  1323     jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V");
       
  1324 
       
  1325     if (byteclassinit == NULL) {
       
  1326         jniThrowException(env, "java/lang/NoSuchMethodError",
       
  1327                 "Byte.<init>(byte val)");
       
  1328         return;
       
  1329     }
       
  1330 
       
  1331     jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B");
       
  1332 
       
  1333     if (byteclassvalue == NULL) {
       
  1334         jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value");
       
  1335         return;
       
  1336     }
       
  1337 
       
  1338     gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass);
       
  1339     gCachedFields.byte_class_init = byteclassinit;
       
  1340     gCachedFields.byte_class_value = byteclassvalue;
       
  1341 
       
  1342     // initializing String
       
  1343 
       
  1344     jclass stringclass = env->FindClass("java/lang/String");
       
  1345 
       
  1346     if (stringclass == NULL) {
       
  1347         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1348                 "java.lang.String");
       
  1349         return;
       
  1350     }
       
  1351 
       
  1352     jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V");
       
  1353 
       
  1354     if (stringclassinit == NULL) {
       
  1355         jniThrowException(env, "java/lang/NoSuchMethodError",
       
  1356                 "String.<init>(byte[] val)");
       
  1357         return;
       
  1358     }
       
  1359 
       
  1360     gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass);
       
  1361     gCachedFields.string_class_init = stringclassinit;
       
  1362 
       
  1363     // initializing ScoketImpl
       
  1364 
       
  1365     jclass socketimplclass = env->FindClass("java/net/SocketImpl");
       
  1366 
       
  1367     if (socketimplclass == NULL) {
       
  1368         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1369                 "java.net.SocketImpl");
       
  1370         return;
       
  1371     }
       
  1372 
       
  1373     jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I");
       
  1374 
       
  1375     if (socketimplport == NULL) {
       
  1376         jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port");
       
  1377         return;
       
  1378     }
       
  1379 
       
  1380     jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address",
       
  1381             "Ljava/net/InetAddress;");
       
  1382 
       
  1383     if (socketimpladdress == NULL) {
       
  1384         jniThrowException(env, "java/lang/NoSuchFieldError",
       
  1385                 "SocketImpl.address");
       
  1386         return;
       
  1387     }
       
  1388 
       
  1389     gCachedFields.socketimpl_address = socketimpladdress;
       
  1390     gCachedFields.socketimpl_port = socketimplport;
       
  1391 
       
  1392     gCachedFields.dpack_class = env->FindClass("java/net/DatagramPacket");
       
  1393     if (gCachedFields.dpack_class == NULL) {
       
  1394         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1395                 "java.net.DatagramPacket");
       
  1396         return;
       
  1397     }
       
  1398 
       
  1399     gCachedFields.dpack_address = env->GetFieldID(gCachedFields.dpack_class,
       
  1400             "address", "Ljava/net/InetAddress;");
       
  1401     if (gCachedFields.dpack_address == NULL) {
       
  1402         jniThrowException(env, "java/lang/NoSuchFieldError",
       
  1403                 "DatagramPacket.address");
       
  1404         return;
       
  1405     }
       
  1406 
       
  1407     gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class,
       
  1408             "port", "I");
       
  1409     if (gCachedFields.dpack_port == NULL) {
       
  1410         jniThrowException(env, "java/lang/NoSuchFieldError",
       
  1411                 "DatagramPacket.port");
       
  1412         return;
       
  1413     }
       
  1414 
       
  1415     gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class,
       
  1416             "length", "I");
       
  1417     if (gCachedFields.dpack_length == NULL) {
       
  1418         jniThrowException(env, "java/lang/NoSuchFieldError",
       
  1419                 "DatagramPacket.length");
       
  1420         return;
       
  1421     }
       
  1422 
       
  1423         gCachedFields.fd_class = env->FindClass("java/io/FileDescriptor");
       
  1424     if (gCachedFields.fd_class == NULL) {
       
  1425         jniThrowException(env, "java/lang/ClassNotFoundException",
       
  1426                 "java.io.FileDescriptor");
       
  1427         return;
       
  1428     }
       
  1429         gCachedFields.descriptor = env->GetFieldID(gCachedFields.fd_class, "descriptor", "I");
       
  1430     if (gCachedFields.descriptor == NULL) {
       
  1431         jniThrowException(env, "java/lang/NoSuchFieldError",
       
  1432                 "FileDescriptor.descriptor");
       
  1433         return;
       
  1434     }
       
  1435 
       
  1436 }
       
  1437 
       
  1438 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
       
  1439         jobject fileDescriptor, jboolean preferIPv4Stack) {
       
  1440     // LOGD("ENTER createSocketImpl");
       
  1441 
       
  1442     int ret = socket(PF_INET, SOCK_STREAM, 0);
       
  1443 
       
  1444     if (ret < 0) {
       
  1445         int err = convertError(errno);
       
  1446         throwSocketException(env, err);
       
  1447         return;
       
  1448     }
       
  1449 
       
  1450     jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
       
  1451 
       
  1452     return;
       
  1453 }
       
  1454 
       
  1455 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
       
  1456         jobject fileDescriptor, jboolean preferIPv4Stack) {
       
  1457     // LOGD("ENTER createDatagramSocketImpl");
       
  1458 
       
  1459     int ret = socket(PF_INET, SOCK_DGRAM, 0);
       
  1460 
       
  1461     if (ret < 0) {
       
  1462         int err = convertError(errno);
       
  1463         throwSocketException(env, err);
       
  1464         return;
       
  1465     }
       
  1466 
       
  1467     jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
       
  1468 
       
  1469     return;
       
  1470 }
       
  1471 
       
  1472 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
       
  1473         jobject fileDescriptor, jint address, jint offset, jint count,
       
  1474         jint timeout) {
       
  1475     // LOGD("ENTER readSocketDirectImpl");
       
  1476 
       
  1477     int handle;
       
  1478     jbyte *message = (jbyte *)address;
       
  1479     int result, ret, localCount;
       
  1480 
       
  1481     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  1482 
       
  1483     if (handle == 0 || handle == -1) {
       
  1484         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1485         return 0;
       
  1486     }
       
  1487 
       
  1488     result = selectWait(handle, timeout, SELECT_READ_TYPE);
       
  1489 
       
  1490     if (0 > result) {
       
  1491         return 0;
       
  1492     }
       
  1493 
       
  1494     localCount = (count < 65536) ? count : 65536;
       
  1495 
       
  1496     do {
       
  1497         ret = recv(handle, (jbyte *) message, localCount, SOCKET_NOFLAGS);
       
  1498     } while (ret < 0 && errno == EINTR);
       
  1499 
       
  1500     if (0 == ret) {
       
  1501         return -1;
       
  1502     } else if (ret == -1) {
       
  1503         int err = convertError(errno);
       
  1504         log_socket_close(handle, err);
       
  1505         throwSocketException(env, err);
       
  1506         return 0;
       
  1507     }
       
  1508     add_recv_stats(handle, ret);
       
  1509     return ret;
       
  1510 }
       
  1511 
       
  1512 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
       
  1513         jobject fileDescriptor, jbyteArray data, jint offset, jint count,
       
  1514         jint timeout) {
       
  1515     // LOGD("ENTER readSocketImpl");
       
  1516 
       
  1517     jbyte *message;
       
  1518     int result, localCount;
       
  1519 
       
  1520     jbyte internalBuffer[BUFFERSIZE];
       
  1521 
       
  1522     localCount = (count < 65536) ? count : 65536;
       
  1523 
       
  1524     if (localCount > BUFFERSIZE) {
       
  1525         message = (jbyte*)malloc(localCount * sizeof(jbyte));
       
  1526         if (message == NULL) {
       
  1527             jniThrowException(env, "java/lang/OutOfMemoryError",
       
  1528                     "couldn't allocate enough memory for readSocket");
       
  1529             return 0;
       
  1530         }
       
  1531     } else {
       
  1532         message = (jbyte *)internalBuffer;
       
  1533     }
       
  1534 
       
  1535     result = Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
       
  1536             (jint) message, offset, count, timeout);
       
  1537 
       
  1538     if (result > 0) {
       
  1539         env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
       
  1540     }
       
  1541 
       
  1542     if (((jbyte *)message) != internalBuffer) {
       
  1543         free(( jbyte *)message);
       
  1544     }
       
  1545 
       
  1546     return result;
       
  1547 }
       
  1548 
       
  1549 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
       
  1550         jobject fileDescriptor, jint address, jint offset, jint count) {
       
  1551     // LOGD("ENTER writeSocketDirectImpl");
       
  1552 
       
  1553     int handle;
       
  1554     jbyte *message = (jbyte *)address;
       
  1555     int result = 0, sent = 0;
       
  1556 
       
  1557     if (count <= 0) {
       
  1558         return 0;
       
  1559     }
       
  1560 
       
  1561     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  1562 
       
  1563     if (handle == 0 || handle == -1) {
       
  1564         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1565         return 0;
       
  1566     }
       
  1567 
       
  1568     result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
       
  1569     if (result < 0) {
       
  1570         int err = convertError(errno);
       
  1571         log_socket_close(handle, err);
       
  1572 
       
  1573         if (SOCKERR_WOULDBLOCK == err){
       
  1574             jclass socketExClass,errorCodeExClass;
       
  1575             jmethodID errorCodeExConstructor, socketExConstructor,socketExCauseMethod;
       
  1576             jobject errorCodeEx, socketEx;
       
  1577             const char* errorMessage = netLookupErrorString(err);
       
  1578             jstring errorMessageString = env->NewStringUTF(errorMessage);
       
  1579 
       
  1580             errorCodeExClass = env->FindClass("org/apache/harmony/luni/util/ErrorCodeException");
       
  1581             if (!errorCodeExClass){
       
  1582                 return 0;
       
  1583             }
       
  1584             errorCodeExConstructor = env->GetMethodID(errorCodeExClass,"<init>","(I)V");
       
  1585             if (!errorCodeExConstructor){
       
  1586                 return 0;
       
  1587             }
       
  1588             errorCodeEx = env->NewObject(errorCodeExClass,errorCodeExConstructor,err);
       
  1589 
       
  1590             socketExClass = env->FindClass("java/net/SocketException");
       
  1591             if (!socketExClass) {
       
  1592                 return 0;
       
  1593             }
       
  1594             socketExConstructor = env->GetMethodID(socketExClass,"<init>","(Ljava/lang/String;)V");
       
  1595             if (!socketExConstructor) {
       
  1596                 return 0;
       
  1597             }
       
  1598             socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString); 
       
  1599             socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
       
  1600             env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
       
  1601             env->Throw((jthrowable)socketEx);
       
  1602             return 0;
       
  1603         }
       
  1604         throwSocketException(env, err);
       
  1605         return 0;
       
  1606     }
       
  1607 
       
  1608     add_send_stats(handle, result);
       
  1609     return result;
       
  1610 }
       
  1611 
       
  1612 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
       
  1613         jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
       
  1614     // LOGD("ENTER writeSocketImpl");
       
  1615 
       
  1616     jbyte *message;
       
  1617     int sent = 0;
       
  1618     jint result = 0;
       
  1619 
       
  1620 /* TODO: ARRAY PINNING */
       
  1621 #define INTERNAL_SEND_BUFFER_MAX 512
       
  1622     jbyte internalBuffer[INTERNAL_SEND_BUFFER_MAX];
       
  1623 
       
  1624     if (count > INTERNAL_SEND_BUFFER_MAX) {
       
  1625         message = (jbyte*)malloc(count * sizeof( jbyte));
       
  1626         if (message == NULL) {
       
  1627             jniThrowException(env, "java/lang/OutOfMemoryError",
       
  1628                     "couldn't allocate enough memory for writeSocket");
       
  1629             return 0;
       
  1630         }
       
  1631     } else {
       
  1632         message = (jbyte *)internalBuffer;
       
  1633     }
       
  1634 
       
  1635     env->GetByteArrayRegion(data, offset, count, message);
       
  1636 
       
  1637     result = Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
       
  1638             (jint) message, offset, count);
       
  1639 
       
  1640     if (( jbyte *)message != internalBuffer) {
       
  1641       free(( jbyte *)message);
       
  1642     }
       
  1643 #undef INTERNAL_SEND_BUFFER_MAX
       
  1644    return result;
       
  1645 }
       
  1646 
       
  1647 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
       
  1648         jobject fileDescriptor, jboolean nonblocking) {
       
  1649     // LOGD("ENTER setNonBlockingImpl");
       
  1650 
       
  1651     int handle;
       
  1652     int result;
       
  1653 
       
  1654     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  1655 
       
  1656     if (handle == 0 || handle == -1) {
       
  1657         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1658         return;
       
  1659     }
       
  1660 
       
  1661     int block = nonblocking;
       
  1662 
       
  1663     result = ioctl(handle, FIONBIO, &block);
       
  1664 
       
  1665     if (result == -1) {
       
  1666         throwSocketException(env, convertError(errno));
       
  1667     }
       
  1668 }
       
  1669 
       
  1670 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
       
  1671         jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port);
       
  1672 
       
  1673 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectWithTimeoutSocketImpl(JNIEnv* env,
       
  1674         jclass clazz, jobject fileDescriptor, jint timeout, jint trafficClass,
       
  1675         jobject inetAddr, jint port, jint step, jbyteArray passContext) {
       
  1676     // LOGD("ENTER connectWithTimeoutSocketImpl");
       
  1677 
       
  1678     int handle;
       
  1679     int result = 0;
       
  1680     struct sockaddr_in address;
       
  1681     jbyte *context = NULL;
       
  1682 
       
  1683     memset(&address, 0, sizeof(address));
       
  1684 
       
  1685     address.sin_family = AF_INET;
       
  1686 
       
  1687     result = inetAddressToSocketAddress(env, inetAddr, port,
       
  1688             (struct sockaddr_in *) &address);
       
  1689 
       
  1690     if (result < 0) {
       
  1691         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1692         return result;
       
  1693     }
       
  1694 
       
  1695     // Check if we're using adb networking and redirect in case it is used.
       
  1696     if (useAdbNetworking && !isLocalhost(&address)) {
       
  1697         return Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(env, clazz, fileDescriptor,
       
  1698                 trafficClass, inetAddr, port);
       
  1699     }
       
  1700 
       
  1701     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  1702 
       
  1703     if (handle == 0 || handle == -1) {
       
  1704         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1705         return -1;
       
  1706     }
       
  1707 
       
  1708     address.sin_port = htons(port);
       
  1709 
       
  1710     context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
       
  1711 
       
  1712     switch (step) {
       
  1713         case SOCKET_CONNECT_STEP_START:
       
  1714             result = sockConnectWithTimeout(handle, address, 0,
       
  1715                     SOCKET_STEP_START, context);
       
  1716             break;
       
  1717         case SOCKET_CONNECT_STEP_CHECK:
       
  1718             result = sockConnectWithTimeout(handle, address, timeout,
       
  1719                     SOCKET_STEP_CHECK, context);
       
  1720             break;
       
  1721     }
       
  1722 
       
  1723     env->ReleasePrimitiveArrayCritical(passContext, context, JNI_ABORT);
       
  1724 
       
  1725     if (0 == result) {
       
  1726         /* connected , so stop here */
       
  1727         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
       
  1728     } else if (result != SOCKERR_NOTCONNECTED) {
       
  1729         /* can not connect... */
       
  1730         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
       
  1731         if (result == SOCKERR_EACCES) {
       
  1732             jniThrowException(env, "java/lang/SecurityException",
       
  1733                               netLookupErrorString(result));
       
  1734         } else {
       
  1735             jniThrowException(env, "java/net/ConnectException",
       
  1736                               netLookupErrorString(result));
       
  1737         }
       
  1738     }
       
  1739 
       
  1740     return result;
       
  1741 }
       
  1742 
       
  1743 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
       
  1744         jclass clazz, jobject fileDescriptor, jint remotePort, jint timeout,
       
  1745         jint trafficClass, jobject inetAddr) {
       
  1746     // LOGD("ENTER connectStreamWithTimeoutSocketImpl");
       
  1747 
       
  1748     int result = 0;
       
  1749     int handle;
       
  1750     struct sockaddr_in address;
       
  1751     jbyte *context = NULL;
       
  1752     int remainingTimeout = timeout;
       
  1753     int passedTimeout = 0;
       
  1754     int finishTime = 0;
       
  1755     int blocking = 0;
       
  1756     char hasTimeout = timeout > 0;
       
  1757 
       
  1758     /* if a timeout was specified calculate the finish time value */
       
  1759     if (hasTimeout)  {
       
  1760         finishTime = time_msec_clock() + (int) timeout;
       
  1761     }
       
  1762 
       
  1763 
       
  1764     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  1765 
       
  1766     if (handle == 0 || handle == -1) {
       
  1767         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1768         return;
       
  1769     } else {
       
  1770         result = inetAddressToSocketAddress(env, inetAddr, remotePort,
       
  1771                 (struct sockaddr_in *) &address);
       
  1772 
       
  1773         if (result < 0) {
       
  1774             throwSocketException(env, SOCKERR_BADSOCKET);
       
  1775             return;
       
  1776         }
       
  1777 
       
  1778         // Check if we're using adb networking and redirect in case it is used.
       
  1779         if (useAdbNetworking && !isLocalhost(&address)) {
       
  1780             int retVal = Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(env, clazz,
       
  1781                     fileDescriptor, trafficClass, inetAddr, remotePort);
       
  1782             if (retVal != 0) {
       
  1783                 throwSocketException(env, SOCKERR_BADSOCKET);
       
  1784             }
       
  1785             return;
       
  1786         }
       
  1787 
       
  1788         /*
       
  1789          * we will be looping checking for when we are connected so allocate
       
  1790          * the descriptor sets that we will use
       
  1791          */
       
  1792         context =(jbyte *) malloc(sizeof(struct selectFDSet));
       
  1793 
       
  1794         if (NULL == context) {
       
  1795             throwSocketException(env, SOCKERR_NOBUFFERS);
       
  1796             return;
       
  1797         }
       
  1798 
       
  1799         result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
       
  1800         if (0 == result) {
       
  1801             /* ok we connected right away so we are done */
       
  1802             sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
       
  1803             goto bail;
       
  1804         } else if (result != SOCKERR_NOTCONNECTED) {
       
  1805             log_socket_close(handle, result);
       
  1806             sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
       
  1807                                    context);
       
  1808             /* we got an error other than NOTCONNECTED so we cannot continue */
       
  1809             if (SOCKERR_EACCES == result) {
       
  1810                 jniThrowException(env, "java/lang/SecurityException",
       
  1811                                   netLookupErrorString(result));
       
  1812             } else {
       
  1813                 throwSocketException(env, result);
       
  1814             }
       
  1815             goto bail;
       
  1816         }
       
  1817 
       
  1818         while (SOCKERR_NOTCONNECTED == result) {
       
  1819             passedTimeout = remainingTimeout;
       
  1820 
       
  1821             /*
       
  1822              * ok now try and connect. Depending on the platform this may sleep
       
  1823              * for up to passedTimeout milliseconds
       
  1824              */
       
  1825             result = sockConnectWithTimeout(handle, address, passedTimeout,
       
  1826                     SOCKET_STEP_CHECK, context);
       
  1827 
       
  1828             /*
       
  1829              * now check if the socket is still connected.
       
  1830              * Do it here as some platforms seem to think they
       
  1831              * are connected if the socket is closed on them.
       
  1832              */
       
  1833             handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  1834 
       
  1835             if (handle == 0 || handle == -1) {
       
  1836                 sockConnectWithTimeout(handle, address, 0,
       
  1837                         SOCKET_STEP_DONE, context);
       
  1838                 throwSocketException(env, SOCKERR_BADSOCKET);
       
  1839                 goto bail;
       
  1840             }
       
  1841 
       
  1842             /*
       
  1843              * check if we are now connected,
       
  1844              * if so we can finish the process and return
       
  1845              */
       
  1846             if (0 == result) {
       
  1847                 sockConnectWithTimeout(handle, address, 0,
       
  1848                         SOCKET_STEP_DONE, context);
       
  1849                 goto bail;
       
  1850             }
       
  1851 
       
  1852             /*
       
  1853              * if the error is SOCKERR_NOTCONNECTED then we have not yet
       
  1854              * connected and we may not be done yet
       
  1855              */
       
  1856             if (SOCKERR_NOTCONNECTED == result) {
       
  1857                 /* check if the timeout has expired */
       
  1858                 if (hasTimeout) {
       
  1859                     remainingTimeout = finishTime - time_msec_clock();
       
  1860                     if (remainingTimeout <= 0) {
       
  1861                         log_socket_close(handle, result);
       
  1862                         sockConnectWithTimeout(handle, address, 0,
       
  1863                                 SOCKET_STEP_DONE, context);
       
  1864                         jniThrowException(env,
       
  1865                                 "java/net/SocketTimeoutException",
       
  1866                                 netLookupErrorString(result));
       
  1867                         goto bail;
       
  1868                      }
       
  1869                 } else {
       
  1870                     remainingTimeout = 100;
       
  1871                 }
       
  1872             } else {
       
  1873                 log_socket_close(handle, result);
       
  1874                 sockConnectWithTimeout(handle, address, remainingTimeout,
       
  1875                                        SOCKET_STEP_DONE, context);
       
  1876                 if ((SOCKERR_CONNRESET == result) ||
       
  1877                     (SOCKERR_CONNECTION_REFUSED == result) ||
       
  1878                     (SOCKERR_ADDRNOTAVAIL == result) ||
       
  1879                     (SOCKERR_ADDRINUSE == result) ||
       
  1880                     (SOCKERR_ENETUNREACH == result)) {
       
  1881                     jniThrowException(env, "java/net/ConnectException",
       
  1882                                       netLookupErrorString(result));
       
  1883                 } else if (SOCKERR_EACCES == result) {
       
  1884                     jniThrowException(env, "java/lang/SecurityException",
       
  1885                                       netLookupErrorString(result));
       
  1886                 } else {
       
  1887                     throwSocketException(env, result);
       
  1888                 }
       
  1889                 goto bail;
       
  1890             }
       
  1891         }
       
  1892     }
       
  1893 
       
  1894 bail:
       
  1895 
       
  1896     /* free the memory for the FD set */
       
  1897     if (context != NULL)  {
       
  1898         free(context);
       
  1899     }
       
  1900 }
       
  1901 
       
  1902 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
       
  1903         jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port) {
       
  1904     //LOGD("ENTER direct-call connectSocketImpl\n");
       
  1905 
       
  1906     struct sockaddr_in address;
       
  1907     int ret;
       
  1908     int handle;
       
  1909     jbyteArray java_in_addr;
       
  1910 
       
  1911     memset(&address, 0, sizeof(address));
       
  1912 
       
  1913     address.sin_family = AF_INET;
       
  1914 
       
  1915     ret = inetAddressToSocketAddress(env, inetAddr, port,
       
  1916             (struct sockaddr_in *) &address);
       
  1917 
       
  1918     if (ret < 0) {
       
  1919         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1920         return ret;
       
  1921     }
       
  1922 
       
  1923     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  1924 
       
  1925     if (handle == 0 || handle == -1) {
       
  1926         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1927         return -1;
       
  1928     }
       
  1929 
       
  1930     address.sin_port = htons(port);
       
  1931 
       
  1932     if (useAdbNetworking && !isLocalhost(&address)) {
       
  1933 
       
  1934         // LOGD("+connect to address 0x%08x port %d (via adb)",
       
  1935         //         address.sin_addr.s_addr, (int) port);
       
  1936         ret = adb_networking_connect_fd(handle, &address);
       
  1937         // LOGD("-connect ret %d errno %d (via adb)", ret, errno);
       
  1938 
       
  1939     } else {
       
  1940 
       
  1941         // call this method with a timeout of zero
       
  1942         Java_org_sipdroid_net_impl_OSNetworkSystem_connectStreamWithTimeoutSocketImpl(env, clazz,
       
  1943                 fileDescriptor, port, 0, trafficClass, inetAddr);
       
  1944         if (env->ExceptionOccurred() != 0) {
       
  1945             return -1;
       
  1946         } else {
       
  1947             return 0;
       
  1948         }
       
  1949 
       
  1950     }
       
  1951 
       
  1952     if (ret < 0) {
       
  1953         jniThrowException(env, "java/net/ConnectException",
       
  1954                 netLookupErrorString(convertError(errno)));
       
  1955         return ret;
       
  1956     }
       
  1957 
       
  1958     return ret;
       
  1959 }
       
  1960 
       
  1961 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
       
  1962         jobject fileDescriptor, jint port, jobject inetAddress) {
       
  1963     // LOGD("ENTER socketBindImpl");
       
  1964 
       
  1965     struct sockaddr_in sockaddress;
       
  1966     int ret;
       
  1967     int handle;
       
  1968 
       
  1969     ret = inetAddressToSocketAddress(env, inetAddress, port,
       
  1970             (struct sockaddr_in *) &sockaddress);
       
  1971 
       
  1972     if (ret < 0) {
       
  1973         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1974         return;
       
  1975     }
       
  1976 
       
  1977     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  1978 
       
  1979     if (handle == 0 || handle == -1) {
       
  1980         throwSocketException(env, SOCKERR_BADSOCKET);
       
  1981         return;
       
  1982     }
       
  1983 
       
  1984     ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
       
  1985 
       
  1986     if (ret < 0) {
       
  1987         jniThrowException(env, "java/net/BindException",
       
  1988                 netLookupErrorString(convertError(errno)));
       
  1989         return;
       
  1990     }
       
  1991 }
       
  1992 
       
  1993 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
       
  1994         jobject fileDescriptor, jint backlog) {
       
  1995     // LOGD("ENTER listenStreamSocketImpl");
       
  1996 
       
  1997     int ret;
       
  1998     int handle;
       
  1999 
       
  2000     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2001 
       
  2002     if (handle == 0 || handle == -1) {
       
  2003         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2004         return;
       
  2005     }
       
  2006 
       
  2007     ret = listen(handle, backlog);
       
  2008 
       
  2009     if (ret < 0) {
       
  2010         int err = convertError(errno);
       
  2011         log_socket_close(handle, err);
       
  2012         throwSocketException(env, err);
       
  2013         return;
       
  2014     }
       
  2015 }
       
  2016 
       
  2017 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
       
  2018         jobject fileDescriptor) {
       
  2019     // LOGD("ENTER availableStreamImpl");
       
  2020 
       
  2021     int handle;
       
  2022     char message[BUFFERSIZE];
       
  2023 
       
  2024     int result;
       
  2025 
       
  2026     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2027 
       
  2028     if (handle == 0 || handle == -1) {
       
  2029         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2030         return 0;
       
  2031     }
       
  2032 
       
  2033     do {
       
  2034         result = selectWait(handle, 1, SELECT_READ_TYPE);
       
  2035 
       
  2036         if (SOCKERR_TIMEOUT == result) {
       
  2037             // The read operation timed out, so answer 0 bytes available
       
  2038             return 0;
       
  2039         } else if (SOCKERR_INTERRUPTED == result) {
       
  2040             continue;
       
  2041         } else if (0 > result) {
       
  2042             log_socket_close(handle, result);
       
  2043             throwSocketException(env, result);
       
  2044             return 0;
       
  2045         }
       
  2046     } while (SOCKERR_INTERRUPTED == result);
       
  2047 
       
  2048     result = recv(handle, (jbyte *) message, BUFFERSIZE, MSG_PEEK);
       
  2049 
       
  2050     if (0 > result) {
       
  2051         int err = convertError(errno);
       
  2052         log_socket_close(handle, err);
       
  2053         throwSocketException(env, err);
       
  2054         return 0;
       
  2055     }
       
  2056     add_recv_stats(handle, result);
       
  2057     return result;
       
  2058 }
       
  2059 
       
  2060 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
       
  2061         jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
       
  2062     // LOGD("ENTER acceptSocketImpl");
       
  2063 
       
  2064     union {
       
  2065         struct sockaddr address;
       
  2066         struct sockaddr_in in_address;
       
  2067     } sa;
       
  2068 
       
  2069     int ret;
       
  2070     int retFD;
       
  2071     int result;
       
  2072     int handle;
       
  2073     socklen_t addrlen;
       
  2074 
       
  2075     if (newSocket == NULL) {
       
  2076         throwNullPointerException(env);
       
  2077         return;
       
  2078     }
       
  2079 
       
  2080     result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
       
  2081 
       
  2082     if (0 > result) {
       
  2083         return;
       
  2084     }
       
  2085 
       
  2086     handle = jniGetFDFromFileDescriptor(env, fdServer);
       
  2087 
       
  2088     if (handle == 0 || handle == -1) {
       
  2089         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2090         return;
       
  2091     }
       
  2092 
       
  2093     do {
       
  2094         addrlen = sizeof(sa);
       
  2095         ret = accept(handle, &(sa.address), &addrlen);
       
  2096     } while (ret < 0 && errno == EINTR);
       
  2097 
       
  2098     if (ret < 0) {
       
  2099         int err = convertError(errno);
       
  2100         log_socket_close(handle, err);
       
  2101         throwSocketException(env, err);
       
  2102         return;
       
  2103     }
       
  2104 
       
  2105     retFD = ret;
       
  2106 
       
  2107     /* For AF_INET / inetOrLocal == true only: put
       
  2108      * peer address and port in instance variables
       
  2109      * We don't bother for UNIX domain sockets, since most peers are
       
  2110      * anonymous anyway
       
  2111      */
       
  2112     if (sa.address.sa_family == AF_INET) {
       
  2113         // inetOrLocal should also be true
       
  2114 
       
  2115         jobject inetAddress;
       
  2116 
       
  2117         inetAddress = structInToInetAddress(env, &(sa.in_address.sin_addr));
       
  2118 
       
  2119         if (inetAddress == NULL) {
       
  2120             close(retFD);
       
  2121             newSocket = NULL;
       
  2122             return;
       
  2123         }
       
  2124 
       
  2125         env->SetObjectField(newSocket,
       
  2126                 gCachedFields.socketimpl_address, inetAddress);
       
  2127 
       
  2128         env->SetIntField(newSocket, gCachedFields.socketimpl_port,
       
  2129                 ntohs(sa.in_address.sin_port));
       
  2130     }
       
  2131 
       
  2132     jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
       
  2133 }
       
  2134 
       
  2135 extern "C" jboolean Java_org_sipdroid_net_impl_OSNetworkSystem_supportsUrgentDataImpl(JNIEnv* env,
       
  2136         jclass clazz, jobject fileDescriptor) {
       
  2137     // LOGD("ENTER supportsUrgentDataImpl");
       
  2138 
       
  2139     int handle;
       
  2140 
       
  2141     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2142     if (handle == 0 || handle == -1) {
       
  2143         return JNI_FALSE;
       
  2144     }
       
  2145 
       
  2146     return JNI_TRUE;
       
  2147 }
       
  2148 
       
  2149 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
       
  2150         jobject fileDescriptor, jbyte value) {
       
  2151     // LOGD("ENTER sendUrgentDataImpl");
       
  2152 
       
  2153     int handle;
       
  2154     int result;
       
  2155 
       
  2156     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2157     if (handle == 0 || handle == -1) {
       
  2158         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2159         return;
       
  2160     }
       
  2161 
       
  2162     result = send(handle, (jbyte *) &value, 1, MSG_OOB);
       
  2163     if (result < 0) {
       
  2164         int err = convertError(errno);
       
  2165         log_socket_close(handle, err);
       
  2166         throwSocketException(env, err);
       
  2167     }
       
  2168 }
       
  2169 
       
  2170 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass clazz,
       
  2171         jobject fd, jint port, jint trafficClass, jobject inetAddress) {
       
  2172     // LOGD("ENTER connectDatagramImpl2");
       
  2173 
       
  2174     int handle = jniGetFDFromFileDescriptor(env, fd);
       
  2175 
       
  2176     struct sockaddr_in sockAddr;
       
  2177     int ret;
       
  2178 
       
  2179     ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
       
  2180 
       
  2181     if (ret < 0) {
       
  2182         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2183         return;
       
  2184     }
       
  2185     log_socket_connect(handle, ntohl(sockAddr.sin_addr.s_addr), port);
       
  2186     int result = connect(handle, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
       
  2187     if (result < 0) {
       
  2188         int err = convertError(errno);
       
  2189         log_socket_close(handle, err);
       
  2190         throwSocketException(env, err);
       
  2191     }
       
  2192 }
       
  2193 
       
  2194 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
       
  2195         jobject fd) {
       
  2196     // LOGD("ENTER disconnectDatagramImpl");
       
  2197 
       
  2198     int handle = jniGetFDFromFileDescriptor(env, fd);
       
  2199 
       
  2200     struct sockaddr_in *sockAddr;
       
  2201     socklen_t sockAddrLen = sizeof(struct sockaddr_in);
       
  2202     sockAddr = (struct sockaddr_in *) malloc(sockAddrLen);
       
  2203     memset(sockAddr, 0, sockAddrLen);
       
  2204 
       
  2205     sockAddr->sin_family = AF_UNSPEC;
       
  2206     int result = connect(handle, (struct sockaddr *)sockAddr, sockAddrLen);
       
  2207     free(sockAddr);
       
  2208 
       
  2209     if (result < 0) {
       
  2210         int err = convertError(errno);
       
  2211         log_socket_close(handle, err);
       
  2212         throwSocketException(env, err);
       
  2213     }
       
  2214 }
       
  2215 
       
  2216 extern "C" jboolean Java_org_sipdroid_net_impl_OSNetworkSystem_socketBindImpl2(JNIEnv* env, jclass clazz,
       
  2217         jobject fileDescriptor, jint port, jboolean bindToDevice,
       
  2218         jobject inetAddress) {
       
  2219     // LOGD("ENTER socketBindImpl2");
       
  2220 
       
  2221     struct sockaddr_in sockaddress;
       
  2222     int ret;
       
  2223     int handle;
       
  2224 
       
  2225     ret = inetAddressToSocketAddress(env, inetAddress, port,
       
  2226             (struct sockaddr_in *) &sockaddress);
       
  2227 
       
  2228     if (ret < 0) {
       
  2229         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2230         return 0;
       
  2231     }
       
  2232 
       
  2233     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2234     if (handle == 0 || handle == -1) {
       
  2235         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2236         return 0;
       
  2237     }
       
  2238 
       
  2239     ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
       
  2240 
       
  2241     if (ret < 0) {
       
  2242         int err = convertError(errno);
       
  2243         log_socket_close(handle, err);
       
  2244         jniThrowException(env, "java/net/BindException", netLookupErrorString(err));
       
  2245         return 0;
       
  2246     }
       
  2247 
       
  2248     return 0;
       
  2249 }
       
  2250 
       
  2251 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
       
  2252         jobject fd, jobject sender, jint receiveTimeout) {
       
  2253     // LOGD("ENTER peekDatagramImpl");
       
  2254 
       
  2255     int port = -1;
       
  2256 
       
  2257     int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
       
  2258     if (0> result) {
       
  2259         return (jint) 0;
       
  2260     }
       
  2261 
       
  2262     int handle = jniGetFDFromFileDescriptor(env, fd);
       
  2263 
       
  2264     if (handle == 0 || handle == -1) {
       
  2265         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2266         return 0;
       
  2267     }
       
  2268 
       
  2269     struct sockaddr_in sockAddr;
       
  2270     socklen_t sockAddrLen = sizeof(sockAddr);
       
  2271 
       
  2272     int length = recvfrom(handle, NULL, 0, MSG_PEEK,
       
  2273             (struct sockaddr *)&sockAddr, &sockAddrLen);
       
  2274 
       
  2275     if (length < 0) {
       
  2276         int err = convertError(errno);
       
  2277         log_socket_close(handle, err);
       
  2278         throwSocketException(env, err);
       
  2279         return 0;
       
  2280     }
       
  2281 
       
  2282     if (socketAddressToInetAddress(env, &sockAddr, sender, &port) < 0) {
       
  2283         throwIOExceptionStr(env, "Address conversion failed");
       
  2284         return -1;
       
  2285     }
       
  2286     add_recv_stats(handle, length);
       
  2287     return port;
       
  2288 }
       
  2289 
       
  2290 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
       
  2291         jobject fd, jobject packet, jint address, jint offset, jint length,
       
  2292         jint receiveTimeout, jboolean peek) {
       
  2293     // LOGD("ENTER receiveDatagramDirectImpl");
       
  2294 
       
  2295     int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
       
  2296     if (0 > result) {
       
  2297         return (jint) 0;
       
  2298     }
       
  2299 
       
  2300     int handle = jniGetFDFromFileDescriptor(env, fd);
       
  2301 
       
  2302     if (handle == 0 || handle == -1) {
       
  2303         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2304         return 0;
       
  2305     }
       
  2306 
       
  2307     struct sockaddr_in sockAddr;
       
  2308     socklen_t sockAddrLen = sizeof(sockAddr);
       
  2309 
       
  2310     int mode = peek ? MSG_PEEK : 0;
       
  2311 
       
  2312     int actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
       
  2313             (struct sockaddr *)&sockAddr, &sockAddrLen);
       
  2314 
       
  2315     if (actualLength < 0) {
       
  2316         int err = convertError(errno);
       
  2317         log_socket_close(handle, err);
       
  2318         throwSocketException(env, err);
       
  2319         return 0;
       
  2320     }
       
  2321 
       
  2322     if (packet != NULL) {
       
  2323         int port = ntohs(sockAddr.sin_port);
       
  2324         jobject sender = env->GetObjectField(packet, gCachedFields.dpack_address);
       
  2325        	//__android_log_print(ANDROID_LOG_INFO,"OSNetwork","Sender address  %x ", sender); 
       
  2326 	if (sender != 0) {
       
  2327 		jbyteArray addr = (jbyteArray)env->GetObjectField(sender, gCachedFields.iaddr_ipaddress);
       
  2328 		//__android_log_print(ANDROID_LOG_INFO,"OSNetwork","Sender Recup"); 
       
  2329 		if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
       
  2330 			jniThrowException(env, "java/net/SocketException",
       
  2331 					"Could not set address of packet.");
       
  2332 			return 0;
       
  2333 		}
       
  2334 	}
       
  2335 	else {
       
  2336 		jbyteArray addr = env->NewByteArray(sizeof(struct in_addr));
       
  2337 		if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
       
  2338 			jniThrowException(env, "java/net/SocketException",
       
  2339 					"Could not set address of packet.");
       
  2340 			return 0;
       
  2341 		}
       
  2342 		sender = env->CallStaticObjectMethod(
       
  2343 		  gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
       
  2344 		  addr);
       
  2345 
       
  2346 	}
       
  2347         env->SetObjectField(packet, gCachedFields.dpack_address, sender);
       
  2348         env->SetIntField(packet, gCachedFields.dpack_port, port);
       
  2349         env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
       
  2350     }
       
  2351     add_recv_stats(handle, actualLength);
       
  2352     return actualLength;
       
  2353 }
       
  2354 
       
  2355 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
       
  2356         jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
       
  2357         jint receiveTimeout, jboolean peek) {
       
  2358     // LOGD("ENTER receiveDatagramImpl");
       
  2359 
       
  2360     int localLength = (length < 65536) ? length : 65536;
       
  2361     jbyte *bytes = (jbyte*) malloc(localLength);
       
  2362     if (bytes == NULL) {
       
  2363         jniThrowException(env, "java/lang/OutOfMemoryError",
       
  2364                 "couldn't allocate enough memory for receiveDatagram");
       
  2365         return 0;
       
  2366     }
       
  2367 
       
  2368     int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
       
  2369             packet, (jint)bytes, offset, localLength, receiveTimeout, peek);
       
  2370 
       
  2371     if (actualLength > 0) {
       
  2372         env->SetByteArrayRegion(data, offset, actualLength, bytes);
       
  2373     }
       
  2374     free(bytes);
       
  2375 
       
  2376     return actualLength;
       
  2377 }
       
  2378 
       
  2379 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramDirectImpl(JNIEnv* env,
       
  2380         jclass clazz, jobject fd, jobject packet, jint address, jint offset,
       
  2381         jint length, jint receiveTimeout, jboolean peek) {
       
  2382     // LOGD("ENTER receiveConnectedDatagramDirectImpl");
       
  2383 
       
  2384     int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
       
  2385 
       
  2386     if (0 > result) {
       
  2387         return 0;
       
  2388     }
       
  2389 
       
  2390     int handle = jniGetFDFromFileDescriptor(env, fd);
       
  2391 
       
  2392     if (handle == 0 || handle == -1) {
       
  2393         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2394         return 0;
       
  2395     }
       
  2396 
       
  2397     int mode = peek ? MSG_PEEK : 0;
       
  2398 
       
  2399     int actualLength = recvfrom(handle,
       
  2400             (char*)(address + offset), length, mode, NULL, NULL);
       
  2401 
       
  2402     if (actualLength < 0) {
       
  2403         jniThrowException(env, "java/net/PortUnreachableException", "");
       
  2404         return 0;
       
  2405     }
       
  2406 
       
  2407     if ( packet != NULL) {
       
  2408         env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
       
  2409     }
       
  2410     add_recv_stats(handle, actualLength);
       
  2411     return actualLength;
       
  2412 }
       
  2413 
       
  2414 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramImpl(JNIEnv* env, jclass clazz,
       
  2415         jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
       
  2416         jint receiveTimeout, jboolean peek) {
       
  2417     // LOGD("ENTER receiveConnectedDatagramImpl");
       
  2418 
       
  2419     int localLength = (length < 65536) ? length : 65536;
       
  2420     jbyte *bytes = (jbyte*) malloc(localLength);
       
  2421     if (bytes == NULL) {
       
  2422         jniThrowException(env, "java/lang/OutOfMemoryError",
       
  2423                 "couldn't allocate enough memory for recvConnectedDatagram");
       
  2424         return 0;
       
  2425     }
       
  2426 
       
  2427     int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramDirectImpl(env,
       
  2428             clazz, fd, packet, (jint)bytes, offset, localLength,
       
  2429             receiveTimeout, peek);
       
  2430 
       
  2431     if (actualLength > 0) {
       
  2432         env->SetByteArrayRegion(data, offset, actualLength, bytes);
       
  2433     }
       
  2434     free(bytes);
       
  2435 
       
  2436     return actualLength;
       
  2437 }
       
  2438 
       
  2439 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
       
  2440         jobject fd, jint address, jint offset, jint length, jint port,
       
  2441         jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
       
  2442     // LOGD("ENTER sendDatagramDirectImpl");
       
  2443 
       
  2444     int result = 0;
       
  2445 
       
  2446     int handle = jniGetFDFromFileDescriptor(env, fd);
       
  2447 
       
  2448     if (handle == 0 || handle == -1) {
       
  2449         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2450         return 0;
       
  2451     }
       
  2452 
       
  2453     struct sockaddr_in receiver;
       
  2454 
       
  2455     if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
       
  2456         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2457         return 0;
       
  2458     }
       
  2459 
       
  2460     result = sendto(handle, (char*)(address + offset), length, SOCKET_NOFLAGS,
       
  2461             (struct sockaddr*)&receiver, sizeof(receiver));
       
  2462 
       
  2463     if (result < 0) {
       
  2464         int err = convertError(errno);
       
  2465         if ((SOCKERR_CONNRESET == err)
       
  2466                 || (SOCKERR_CONNECTION_REFUSED == err)) {
       
  2467             return 0;
       
  2468         } else {
       
  2469             log_socket_close(handle, err);
       
  2470             throwSocketException(env, err);
       
  2471             return 0;
       
  2472         }
       
  2473     }
       
  2474     add_send_stats(handle, result);
       
  2475     return result;
       
  2476 }
       
  2477 
       
  2478 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
       
  2479         jobject fd, jbyteArray data, jint offset, jint length, jint port,
       
  2480         jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
       
  2481     // LOGD("ENTER sendDatagramImpl");
       
  2482 
       
  2483     jbyte *bytes = env->GetByteArrayElements(data, NULL);
       
  2484     int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramDirectImpl(env, clazz, fd,
       
  2485             (jint)bytes, offset, length, port, bindToDevice, trafficClass,
       
  2486             inetAddress);
       
  2487     env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
       
  2488 
       
  2489     return actualLength;
       
  2490 }
       
  2491 
       
  2492 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramDirectImpl(JNIEnv* env,
       
  2493         jclass clazz, jobject fd, jint address, jint offset, jint length,
       
  2494         jboolean bindToDevice) {
       
  2495     // LOGD("ENTER sendConnectedDatagramDirectImpl");
       
  2496 
       
  2497     int handle = jniGetFDFromFileDescriptor(env, fd);
       
  2498 
       
  2499     if (handle == 0 || handle == -1) {
       
  2500         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2501         return 0;
       
  2502     }
       
  2503 
       
  2504     int result = send(handle, (char*)(address + offset), length, 0);
       
  2505 
       
  2506     if (result < 0) {
       
  2507         int err = convertError(errno);
       
  2508         if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
       
  2509             return 0;
       
  2510         } else {
       
  2511             log_socket_close(handle, err);
       
  2512             throwSocketException(env, err);
       
  2513             return 0;
       
  2514         }
       
  2515     }
       
  2516     add_send_stats(handle, length);
       
  2517     return result;
       
  2518 }
       
  2519 
       
  2520 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramImpl(JNIEnv* env, jclass clazz,
       
  2521         jobject fd, jbyteArray data, jint offset, jint length,
       
  2522         jboolean bindToDevice) {
       
  2523     // LOGD("ENTER sendConnectedDatagramImpl");
       
  2524 
       
  2525     jbyte *bytes = env->GetByteArrayElements(data, NULL);
       
  2526     int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramDirectImpl(env,
       
  2527             clazz, fd, (jint)bytes, offset, length, bindToDevice);
       
  2528     env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
       
  2529 
       
  2530     return actualLength;
       
  2531 }
       
  2532 
       
  2533 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
       
  2534         jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
       
  2535     // LOGD("ENTER createServerStreamSocketImpl");
       
  2536 
       
  2537     if (fileDescriptor == NULL) {
       
  2538         throwNullPointerException(env);
       
  2539         return;
       
  2540     }
       
  2541 
       
  2542     int handle = socket(PF_INET, SOCK_STREAM, 0);
       
  2543 
       
  2544     if (handle < 0) {
       
  2545         int err = convertError(errno);
       
  2546         throwSocketException(env, err);
       
  2547         return;
       
  2548     }
       
  2549 
       
  2550     jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
       
  2551 
       
  2552     int value = 1;
       
  2553 
       
  2554     setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
       
  2555 }
       
  2556 
       
  2557 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createMulticastSocketImpl(JNIEnv* env,
       
  2558         jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
       
  2559     // LOGD("ENTER createMulticastSocketImpl");
       
  2560 
       
  2561     int handle = socket(PF_INET, SOCK_DGRAM, 0);
       
  2562 
       
  2563     if (handle < 0) {
       
  2564         int err = convertError(errno);
       
  2565         throwSocketException(env, err);
       
  2566         return;
       
  2567     }
       
  2568 
       
  2569     jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
       
  2570 
       
  2571     int value = 1;
       
  2572 
       
  2573     // setsockopt(handle, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(jbyte));
       
  2574     setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
       
  2575 }
       
  2576 
       
  2577 /*
       
  2578  * @param timeout in milliseconds.  If zero, block until data received
       
  2579  */
       
  2580 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
       
  2581         jobject fileDescriptor, jbyteArray data, jint offset, jint count,
       
  2582         jint timeout) {
       
  2583     // LOGD("ENTER receiveStreamImpl");
       
  2584 
       
  2585     int result;
       
  2586     int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2587 
       
  2588     if (handle == 0 || handle == -1) {
       
  2589         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2590         return 0;
       
  2591     }
       
  2592 
       
  2593     // Cap read length to available buf size
       
  2594     int spaceAvailable = env->GetArrayLength(data) - offset;
       
  2595     int localCount = count < spaceAvailable? count : spaceAvailable;
       
  2596 
       
  2597     jboolean isCopy;
       
  2598     jbyte *body = env->GetByteArrayElements(data, &isCopy);
       
  2599 
       
  2600     // set timeout
       
  2601     struct timeval tv;
       
  2602     tv.tv_sec = timeout / 1000;
       
  2603     tv.tv_usec = (timeout % 1000) * 1000;
       
  2604     setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv,
       
  2605                sizeof(struct timeval));
       
  2606 
       
  2607     do {
       
  2608         result = recv(handle, body + offset, localCount, SOCKET_NOFLAGS);
       
  2609     } while (result < 0 && errno == EINTR);
       
  2610 
       
  2611     env->ReleaseByteArrayElements(data, body, 0);
       
  2612 
       
  2613     /*
       
  2614      * If no bytes are read, return -1 to signal 'endOfFile'
       
  2615      * to the Java input stream
       
  2616      */
       
  2617     if (0 < result) {
       
  2618         add_recv_stats(handle, result);
       
  2619         return result;
       
  2620     } else if (0 == result) {
       
  2621         return -1;
       
  2622     } else {
       
  2623         // If EAGAIN or EWOULDBLOCK, read timed out
       
  2624         if (errno == EAGAIN || errno == EWOULDBLOCK) {
       
  2625             jniThrowException(env, "java/net/SocketTimeoutException",
       
  2626                               netLookupErrorString(SOCKERR_TIMEOUT));
       
  2627         } else {
       
  2628             int err = convertError(errno);
       
  2629             log_socket_close(handle, err);
       
  2630             throwSocketException(env, err);
       
  2631         }
       
  2632         return 0;
       
  2633     }
       
  2634 }
       
  2635 
       
  2636 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
       
  2637         jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
       
  2638     // LOGD("ENTER sendStreamImpl");
       
  2639 
       
  2640     int handle = 0;
       
  2641     int result = 0, sent = 0;
       
  2642 
       
  2643     jboolean isCopy;
       
  2644     jbyte *message = env->GetByteArrayElements(data, &isCopy);
       
  2645 
       
  2646     // Cap write length to available buf size
       
  2647     int spaceAvailable = env->GetArrayLength(data) - offset;
       
  2648     if (count > spaceAvailable) count = spaceAvailable;
       
  2649 
       
  2650     while (sent < count) {
       
  2651 
       
  2652         handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2653         if (handle == 0 || handle == -1) {
       
  2654             throwSocketException(env,
       
  2655                     sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
       
  2656             env->ReleaseByteArrayElements(data, message, 0);
       
  2657             return 0;
       
  2658         }
       
  2659 
       
  2660         // LOGD("before select %d", count);
       
  2661         selectWait(handle, SEND_RETRY_TIME, SELECT_WRITE_TYPE);
       
  2662         result = send(handle, (jbyte *)message + offset + sent,
       
  2663                 (int) count - sent, SOCKET_NOFLAGS);
       
  2664 
       
  2665         if (result < 0) {
       
  2666             result = errno;
       
  2667             if (result == EAGAIN ||result == EWOULDBLOCK) {
       
  2668                 // LOGD("write blocked %d", sent);
       
  2669                 continue;
       
  2670             }
       
  2671             env->ReleaseByteArrayElements(data, message, 0);
       
  2672             int err = convertError(result);
       
  2673             log_socket_close(handle, err);
       
  2674             throwSocketException(env, err);
       
  2675             return 0;
       
  2676         }
       
  2677         sent += result;
       
  2678     }
       
  2679 
       
  2680     env->ReleaseByteArrayElements(data, message, 0);
       
  2681     add_send_stats(handle, sent);
       
  2682     return sent;
       
  2683 }
       
  2684 
       
  2685 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject obj,
       
  2686         jobject fileDescriptor) {
       
  2687     // LOGD("ENTER shutdownInputImpl");
       
  2688 
       
  2689     int ret;
       
  2690     int handle;
       
  2691 
       
  2692     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2693 
       
  2694     if (handle == 0 || handle == -1) {
       
  2695         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2696         return;
       
  2697     }
       
  2698 
       
  2699     ret = shutdown(handle, SHUT_RD);
       
  2700 
       
  2701     if (ret < 0) {
       
  2702         int err = convertError(errno);
       
  2703         log_socket_close(handle, err);
       
  2704         throwSocketException(env, err);
       
  2705         return;
       
  2706     }
       
  2707 }
       
  2708 
       
  2709 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject obj,
       
  2710         jobject fileDescriptor) {
       
  2711     // LOGD("ENTER shutdownOutputImpl");
       
  2712 
       
  2713     int ret;
       
  2714     int handle;
       
  2715 
       
  2716     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2717 
       
  2718     if (handle == 0 || handle == -1) {
       
  2719         return;
       
  2720     }
       
  2721 
       
  2722     ret = shutdown(handle, SHUT_WR);
       
  2723 
       
  2724     if (ret < 0) {
       
  2725         int err = convertError(errno);
       
  2726         log_socket_close(handle, err);
       
  2727         throwSocketException(env, err);
       
  2728         return;
       
  2729     }
       
  2730 }
       
  2731 
       
  2732 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
       
  2733         jobject fd, jbyteArray data, jint offset, jint length, jint port,
       
  2734         jobject inetAddress) {
       
  2735     // LOGD("ENTER sendDatagramImpl2");
       
  2736 
       
  2737     jbyte *message;
       
  2738     jbyte nhostAddrBytes[4];
       
  2739     unsigned short nPort;
       
  2740     int result = 0, sent = 0;
       
  2741     int handle = 0;
       
  2742     struct sockaddr_in sockaddrP;
       
  2743 
       
  2744     if (inetAddress != NULL) {
       
  2745 
       
  2746         result = inetAddressToSocketAddress(env, inetAddress, port,
       
  2747                 (struct sockaddr_in *) &sockaddrP);
       
  2748 
       
  2749         if (result < 0) {
       
  2750             throwSocketException(env, SOCKERR_BADSOCKET);
       
  2751             return 0;
       
  2752         }
       
  2753 
       
  2754         handle = jniGetFDFromFileDescriptor(env, fd);
       
  2755 
       
  2756         if (handle == 0 || handle == -1) {
       
  2757             throwSocketException(env, SOCKERR_BADSOCKET);
       
  2758             return 0;
       
  2759         }
       
  2760     }
       
  2761 
       
  2762     message = (jbyte*) malloc(length * sizeof(jbyte));
       
  2763     if (message == NULL) {
       
  2764         jniThrowException(env, "java/lang/OutOfMemoryError",
       
  2765                 "couldn't allocate enough memory for readSocket");
       
  2766         return 0;
       
  2767     }
       
  2768 
       
  2769     env->GetByteArrayRegion(data, offset, length, message);
       
  2770 
       
  2771     while (sent < length) {
       
  2772         handle = jniGetFDFromFileDescriptor(env, fd);
       
  2773 
       
  2774         if (handle == 0 || handle == -1) {
       
  2775             throwSocketException(env,
       
  2776                     sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
       
  2777             free(message);
       
  2778             return 0;
       
  2779         }
       
  2780 
       
  2781         result = sendto(handle, (char *) (message + sent),
       
  2782                 (int) (length - sent), SOCKET_NOFLAGS,
       
  2783                 (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
       
  2784 
       
  2785         if (result < 0) {
       
  2786             int err = convertError(errno);
       
  2787             log_socket_close(handle, err);
       
  2788             throwSocketException(env, err);
       
  2789             free(message);
       
  2790             return 0;
       
  2791         }
       
  2792 
       
  2793         sent += result;
       
  2794     }
       
  2795 
       
  2796     free(message);
       
  2797     add_send_stats(handle, sent);
       
  2798     return sent;
       
  2799 }
       
  2800 
       
  2801 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
       
  2802         jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
       
  2803         jint countWriteC, jintArray outFlags, jlong timeout) {
       
  2804     // LOGD("ENTER selectImpl");
       
  2805 
       
  2806     struct timeval timeP;
       
  2807     int result = 0;
       
  2808     int size = 0;
       
  2809     jobject gotFD;
       
  2810     fd_set *fdset_read,*fdset_write;
       
  2811     int handle;
       
  2812     jboolean isCopy ;
       
  2813     jint *flagArray;
       
  2814     int val;
       
  2815     unsigned int time_sec = (unsigned int)timeout/1000;
       
  2816     unsigned int time_msec = (unsigned int)(timeout%1000);
       
  2817 
       
  2818     fdset_read = (fd_set *)malloc(sizeof(fd_set));
       
  2819     fdset_write = (fd_set *)malloc(sizeof(fd_set));
       
  2820 
       
  2821     FD_ZERO(fdset_read);
       
  2822     FD_ZERO(fdset_write);
       
  2823 
       
  2824     for (val = 0; val<countReadC; val++) {
       
  2825 
       
  2826         gotFD = env->GetObjectArrayElement(readFDArray,val);
       
  2827 
       
  2828         handle = jniGetFDFromFileDescriptor(env, gotFD);
       
  2829 
       
  2830         FD_SET(handle, fdset_read);
       
  2831 
       
  2832         if (0 > (size - handle)) {
       
  2833             size = handle;
       
  2834         }
       
  2835     }
       
  2836 
       
  2837     for (val = 0; val<countWriteC; val++) {
       
  2838 
       
  2839         gotFD = env->GetObjectArrayElement(writeFDArray,val);
       
  2840 
       
  2841         handle = jniGetFDFromFileDescriptor(env, gotFD);
       
  2842 
       
  2843         FD_SET(handle, fdset_write);
       
  2844 
       
  2845         if (0 > (size - handle)) {
       
  2846             size = handle;
       
  2847         }
       
  2848     }
       
  2849 
       
  2850     /* the size is the max_fd + 1 */
       
  2851     size =size + 1;
       
  2852 
       
  2853     if (0 > size) {
       
  2854         result = SOCKERR_FDSET_SIZEBAD;
       
  2855     } else {
       
  2856       /* only set when timeout >= 0 (non-block)*/
       
  2857         if (0 <= timeout) {
       
  2858 
       
  2859             timeP.tv_sec = time_sec;
       
  2860             timeP.tv_usec = time_msec*1000;
       
  2861 
       
  2862             result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
       
  2863 
       
  2864         } else {
       
  2865             result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
       
  2866         }
       
  2867     }
       
  2868 
       
  2869     if (0 < result) {
       
  2870        /*output the result to a int array*/
       
  2871        flagArray = env->GetIntArrayElements(outFlags, &isCopy);
       
  2872 
       
  2873        for (val=0; val<countReadC; val++) {
       
  2874             gotFD = env->GetObjectArrayElement(readFDArray,val);
       
  2875 
       
  2876             handle = jniGetFDFromFileDescriptor(env, gotFD);
       
  2877 
       
  2878             if (FD_ISSET(handle,fdset_read)) {
       
  2879                 flagArray[val] = SOCKET_OP_READ;
       
  2880             } else {
       
  2881                 flagArray[val] = SOCKET_OP_NONE;
       
  2882             }
       
  2883         }
       
  2884 
       
  2885         for (val=0; val<countWriteC; val++) {
       
  2886 
       
  2887             gotFD = env->GetObjectArrayElement(writeFDArray,val);
       
  2888 
       
  2889             handle = jniGetFDFromFileDescriptor(env, gotFD);
       
  2890 
       
  2891             if (FD_ISSET(handle,fdset_write)) {
       
  2892                 flagArray[val+countReadC] = SOCKET_OP_WRITE;
       
  2893             } else {
       
  2894                 flagArray[val+countReadC] = SOCKET_OP_NONE;
       
  2895             }
       
  2896         }
       
  2897 
       
  2898         env->ReleaseIntArrayElements(outFlags, flagArray, 0);
       
  2899     }
       
  2900 
       
  2901     free(fdset_write);
       
  2902     free(fdset_read);
       
  2903 
       
  2904     /* return both correct and error result, let java handle the exception*/
       
  2905     return result;
       
  2906 }
       
  2907 
       
  2908 extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
       
  2909         jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
       
  2910     // LOGD("ENTER getSocketLocalAddressImpl");
       
  2911 
       
  2912     struct sockaddr_in addr;
       
  2913     socklen_t addrLen = sizeof(addr);
       
  2914 
       
  2915     memset(&addr, 0, addrLen);
       
  2916 
       
  2917     int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2918 
       
  2919     int result;
       
  2920 
       
  2921     if (handle == 0 || handle == -1) {
       
  2922         throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
       
  2923         return NULL;
       
  2924     }
       
  2925 
       
  2926     result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
       
  2927 
       
  2928     // Spec says ignore all errors
       
  2929 
       
  2930     return structInToInetAddress(env, &(addr.sin_addr));
       
  2931 
       
  2932 }
       
  2933 
       
  2934 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
       
  2935         jobject fileDescriptor, jboolean preferIPv6Addresses) {
       
  2936     // LOGD("ENTER getSocketLocalPortImpl");
       
  2937 
       
  2938     struct sockaddr_in addr;
       
  2939     socklen_t addrLen = sizeof(addr);
       
  2940 
       
  2941     int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2942     int result;
       
  2943 
       
  2944     if (handle == 0 || handle == -1) {
       
  2945         throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
       
  2946         return 0;
       
  2947     }
       
  2948 
       
  2949     result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
       
  2950 
       
  2951     if (0 != result) {
       
  2952         // The java spec does not indicate any exceptions on this call
       
  2953         return 0;
       
  2954     } else {
       
  2955         return ntohs(addr.sin_port);
       
  2956     }
       
  2957 }
       
  2958 
       
  2959 extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
       
  2960         jobject fileDescriptor, jint anOption) {
       
  2961     // LOGD("ENTER getSocketOptionImpl");
       
  2962 
       
  2963     int handle;
       
  2964     int intValue = 0;
       
  2965     socklen_t intSize = sizeof(int);
       
  2966     unsigned char byteValue = 0;
       
  2967     socklen_t byteSize = sizeof(unsigned char);
       
  2968     int result;
       
  2969     struct sockaddr_in sockVal;
       
  2970     socklen_t sockSize = sizeof(sockVal);
       
  2971 
       
  2972     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  2973     if (handle == 0 || handle == -1) {
       
  2974         throwSocketException(env, SOCKERR_BADSOCKET);
       
  2975         return NULL;
       
  2976     }
       
  2977 
       
  2978     switch ((int) anOption & 0xffff) {
       
  2979         case JAVASOCKOPT_SO_LINGER: {
       
  2980             struct linger lingr;
       
  2981             socklen_t size = sizeof(struct linger);
       
  2982             result = getsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr, &size);
       
  2983             if (0 != result) {
       
  2984                 throwSocketException(env, convertError(errno));
       
  2985                 return NULL;
       
  2986             }
       
  2987             if (!lingr.l_onoff) {
       
  2988                 intValue = -1;
       
  2989             } else {
       
  2990                 intValue = lingr.l_linger;
       
  2991             }
       
  2992             return newJavaLangInteger(env, intValue);
       
  2993         }
       
  2994         case JAVASOCKOPT_TCP_NODELAY: {
       
  2995             if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
       
  2996                 return NULL;
       
  2997             }
       
  2998             result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
       
  2999             if (0 != result) {
       
  3000                 throwSocketException(env, convertError(errno));
       
  3001                 return NULL;
       
  3002             }
       
  3003             return newJavaLangBoolean(env, intValue);
       
  3004         }
       
  3005         case JAVASOCKOPT_MCAST_TTL: {
       
  3006             if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
       
  3007                 return newJavaLangByte(env, 0);
       
  3008             }
       
  3009             result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteValue, &byteSize);
       
  3010             if (0 != result) {
       
  3011                 throwSocketException(env, convertError(errno));
       
  3012                 return NULL;
       
  3013             }
       
  3014             return newJavaLangByte(env, (jbyte)(byteValue & 0xFF));
       
  3015         }
       
  3016         case JAVASOCKOPT_MCAST_INTERFACE: {
       
  3017             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
       
  3018                 return NULL;
       
  3019             }
       
  3020             result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
       
  3021             if (0 != result) {
       
  3022                 throwSocketException(env, convertError(errno));
       
  3023                 return NULL;
       
  3024             }
       
  3025             return structInToInetAddress(env, &(sockVal.sin_addr));
       
  3026         }
       
  3027         case JAVASOCKOPT_SO_SNDBUF: {
       
  3028             result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
       
  3029             if (0 != result) {
       
  3030                 throwSocketException(env, convertError(errno));
       
  3031                 return NULL;
       
  3032             }
       
  3033             return newJavaLangInteger(env, intValue);
       
  3034         }
       
  3035         case JAVASOCKOPT_SO_RCVBUF: {
       
  3036             result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
       
  3037             if (0 != result) {
       
  3038                 throwSocketException(env, convertError(errno));
       
  3039                 return NULL;
       
  3040             }
       
  3041             return newJavaLangInteger(env, intValue);
       
  3042         }
       
  3043         case JAVASOCKOPT_SO_BROADCAST: {
       
  3044             result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
       
  3045             if (0 != result) {
       
  3046                 throwSocketException(env, convertError(errno));
       
  3047                 return NULL;
       
  3048             }
       
  3049             return newJavaLangBoolean(env, intValue);
       
  3050         }
       
  3051         case JAVASOCKOPT_SO_REUSEADDR: {
       
  3052             result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
       
  3053             if (0 != result) {
       
  3054                 throwSocketException(env, convertError(errno));
       
  3055                 return NULL;
       
  3056             }
       
  3057             return newJavaLangBoolean(env, intValue);
       
  3058         }
       
  3059         case JAVASOCKOPT_SO_KEEPALIVE: {
       
  3060             result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
       
  3061             if (0 != result) {
       
  3062                 throwSocketException(env, convertError(errno));
       
  3063                 return NULL;
       
  3064             }
       
  3065             return newJavaLangBoolean(env, intValue);
       
  3066         }
       
  3067         case JAVASOCKOPT_SO_OOBINLINE: {
       
  3068             result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
       
  3069             if (0 != result) {
       
  3070                 throwSocketException(env, convertError(errno));
       
  3071                 return NULL;
       
  3072             }
       
  3073             return newJavaLangBoolean(env, intValue);
       
  3074         }
       
  3075         case JAVASOCKOPT_IP_MULTICAST_LOOP: {
       
  3076             result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intValue, &intSize);
       
  3077             if (0 != result) {
       
  3078                 throwSocketException(env, convertError(errno));
       
  3079                 return NULL;
       
  3080             }
       
  3081             return newJavaLangBoolean(env, intValue);
       
  3082         }
       
  3083         case JAVASOCKOPT_IP_TOS: {
       
  3084             result = getsockopt(handle, IPPROTO_IP, IP_TOS, &intValue, &intSize);
       
  3085             if (0 != result) {
       
  3086                 throwSocketException(env, convertError(errno));
       
  3087                 return NULL;
       
  3088             }
       
  3089             return newJavaLangInteger(env, intValue);
       
  3090         }
       
  3091         case JAVASOCKOPT_SO_RCVTIMEOUT: {
       
  3092             struct timeval timeout;
       
  3093             socklen_t size = sizeof(timeout);
       
  3094             result = getsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size);
       
  3095             if (0 != result) {
       
  3096                 throwSocketException(env, convertError(errno));
       
  3097                 return NULL;
       
  3098             }
       
  3099             return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
       
  3100         }
       
  3101         default: {
       
  3102             throwSocketException(env, SOCKERR_OPTUNSUPP);
       
  3103             return NULL;
       
  3104         }
       
  3105     }
       
  3106 
       
  3107 }
       
  3108 
       
  3109 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
       
  3110         jobject fileDescriptor, jint anOption, jobject optVal) {
       
  3111     // LOGD("ENTER setSocketOptionImpl");
       
  3112 
       
  3113     int handle, result;
       
  3114     int intVal, intSize = sizeof(int);
       
  3115     unsigned char byteVal, byteSize = sizeof(unsigned char);
       
  3116     struct sockaddr_in sockVal;
       
  3117     int sockSize = sizeof(sockVal);
       
  3118 
       
  3119     if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
       
  3120         intVal = (int) env->GetIntField(optVal, gCachedFields.integer_class_value);
       
  3121     } else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
       
  3122         intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
       
  3123     } else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
       
  3124         byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
       
  3125     } else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
       
  3126         if (inetAddressToSocketAddress(env, optVal, 0, &sockVal) < 0) {
       
  3127             throwSocketException(env, SOCKERR_BADSOCKET);
       
  3128             return;
       
  3129         }
       
  3130     } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
       
  3131         // we'll use optVal directly
       
  3132     } else {
       
  3133         throwSocketException(env, SOCKERR_OPTUNSUPP);
       
  3134         return;
       
  3135     }
       
  3136 
       
  3137     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  3138     if (handle == 0 || handle == -1) {
       
  3139         throwSocketException(env, SOCKERR_BADSOCKET);
       
  3140         return;
       
  3141     }
       
  3142 
       
  3143     switch ((int) anOption & 0xffff) {
       
  3144         case JAVASOCKOPT_SO_LINGER: {
       
  3145             struct linger lingr;
       
  3146             lingr.l_onoff = intVal > 0 ? 1 : 0;
       
  3147             lingr.l_linger = intVal;
       
  3148             result = setsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr,
       
  3149                     sizeof(struct linger));
       
  3150             if (0 != result) {
       
  3151                 throwSocketException(env, convertError(errno));
       
  3152                 return;
       
  3153             }
       
  3154             break;
       
  3155         }
       
  3156 
       
  3157         case JAVASOCKOPT_TCP_NODELAY: {
       
  3158             if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
       
  3159                 return;
       
  3160             }
       
  3161             result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
       
  3162             if (0 != result) {
       
  3163                 throwSocketException(env, convertError(errno));
       
  3164                 return;
       
  3165             }
       
  3166             break;
       
  3167         }
       
  3168 
       
  3169       case JAVASOCKOPT_MCAST_TTL: {
       
  3170             if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
       
  3171                 return;
       
  3172             }
       
  3173             result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteVal, byteSize);
       
  3174             if (0 != result) {
       
  3175                 throwSocketException(env, convertError(errno));
       
  3176                 return;
       
  3177             }
       
  3178             break;
       
  3179         }
       
  3180 
       
  3181         case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
       
  3182             mcastAddDropMembership(env, handle, optVal,
       
  3183                     (anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
       
  3184             return;
       
  3185         }
       
  3186 
       
  3187         case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
       
  3188             mcastAddDropMembership(env, handle, optVal,
       
  3189                     (anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
       
  3190             return;
       
  3191         }
       
  3192 
       
  3193         case JAVASOCKOPT_MCAST_INTERFACE: {
       
  3194             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
       
  3195                 return;
       
  3196             }
       
  3197             result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, sockSize);
       
  3198             if (0 != result) {
       
  3199                 throwSocketException(env, convertError(errno));
       
  3200                 return;
       
  3201             }
       
  3202             break;
       
  3203         }
       
  3204 
       
  3205         case JAVASOCKOPT_SO_SNDBUF: {
       
  3206             result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
       
  3207             if (0 != result) {
       
  3208                 throwSocketException(env, convertError(errno));
       
  3209                 return;
       
  3210             }
       
  3211             break;
       
  3212         }
       
  3213 
       
  3214         case JAVASOCKOPT_SO_RCVBUF: {
       
  3215             result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
       
  3216             if (0 != result) {
       
  3217                 throwSocketException(env, convertError(errno));
       
  3218                 return;
       
  3219             }
       
  3220             break;
       
  3221         }
       
  3222 
       
  3223         case JAVASOCKOPT_SO_BROADCAST: {
       
  3224             result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
       
  3225             if (0 != result) {
       
  3226                 throwSocketException(env, convertError(errno));
       
  3227                 return;
       
  3228             }
       
  3229             break;
       
  3230         }
       
  3231 
       
  3232         case JAVASOCKOPT_SO_REUSEADDR: {
       
  3233             result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
       
  3234             if (0 != result) {
       
  3235                 throwSocketException(env, convertError(errno));
       
  3236                 return;
       
  3237             }
       
  3238             break;
       
  3239         }
       
  3240         case JAVASOCKOPT_SO_KEEPALIVE: {
       
  3241             result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
       
  3242             if (0 != result) {
       
  3243                 throwSocketException(env, convertError(errno));
       
  3244                 return;
       
  3245             }
       
  3246             break;
       
  3247         }
       
  3248 
       
  3249         case JAVASOCKOPT_SO_OOBINLINE: {
       
  3250             result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
       
  3251             if (0 != result) {
       
  3252                 throwSocketException(env, convertError(errno));
       
  3253                 return;
       
  3254             }
       
  3255             break;
       
  3256         }
       
  3257 
       
  3258         case JAVASOCKOPT_IP_MULTICAST_LOOP: {
       
  3259             result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intVal, intSize);
       
  3260             if (0 != result) {
       
  3261                 throwSocketException(env, convertError(errno));
       
  3262                 return;
       
  3263             }
       
  3264             break;
       
  3265         }
       
  3266 
       
  3267         case JAVASOCKOPT_IP_TOS: {
       
  3268             result = setsockopt(handle, IPPROTO_IP, IP_TOS, &intVal, intSize);
       
  3269             if (0 != result) {
       
  3270                 throwSocketException(env, convertError(errno));
       
  3271                 return;
       
  3272             }
       
  3273             break;
       
  3274         }
       
  3275 
       
  3276         case JAVASOCKOPT_REUSEADDR_AND_REUSEPORT: {
       
  3277             // SO_REUSEPORT doesn't need to get set on this System
       
  3278             result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
       
  3279             if (0 != result) {
       
  3280                 throwSocketException(env, convertError(errno));
       
  3281                 return;
       
  3282             }
       
  3283             break;
       
  3284         }
       
  3285 
       
  3286         case JAVASOCKOPT_SO_RCVTIMEOUT: {
       
  3287             struct timeval timeout;
       
  3288             timeout.tv_sec = intVal / 1000;
       
  3289             timeout.tv_usec = (intVal % 1000) * 1000;
       
  3290             result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
       
  3291                     sizeof(struct timeval));
       
  3292             if (0 != result) {
       
  3293                 throwSocketException(env, convertError(errno));
       
  3294                 return;
       
  3295             }
       
  3296             break;
       
  3297         }
       
  3298 
       
  3299         default: {
       
  3300             throwSocketException(env, SOCKERR_OPTUNSUPP);
       
  3301         }
       
  3302     }
       
  3303 }
       
  3304 
       
  3305 extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
       
  3306     // LOGD("ENTER getSocketFlagsImpl");
       
  3307 
       
  3308     // Not implemented by harmony
       
  3309     return 0;
       
  3310 }
       
  3311 
       
  3312 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
       
  3313         jobject fileDescriptor) {
       
  3314     // LOGD("ENTER socketCloseImpl");
       
  3315 
       
  3316     int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
       
  3317 
       
  3318     if (handle == 0 || handle == -1) {
       
  3319         throwSocketException(env, SOCKERR_BADSOCKET);
       
  3320         return;
       
  3321     }
       
  3322 
       
  3323     log_socket_close(handle, SOCKET_CLOSE_LOCAL);
       
  3324 
       
  3325     jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
       
  3326 
       
  3327     close(handle);
       
  3328 }
       
  3329 
       
  3330 extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz,
       
  3331         jbyteArray addrStr) {
       
  3332     // LOGD("ENTER getHostByAddrImpl");
       
  3333 
       
  3334     if (addrStr == NULL) {
       
  3335         throwNullPointerException(env);
       
  3336         return JNI_FALSE;
       
  3337     }
       
  3338 
       
  3339     jstring address = (jstring)newJavaLangString(env, addrStr);
       
  3340     jstring result;
       
  3341     const char* addr = env->GetStringUTFChars(address, NULL);
       
  3342 
       
  3343     struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET);
       
  3344 
       
  3345     if (ent != NULL  && ent->h_name != NULL) {
       
  3346         result = env->NewStringUTF(ent->h_name);
       
  3347     } else {
       
  3348         result = NULL;
       
  3349     }
       
  3350 
       
  3351     env->ReleaseStringUTFChars(address, addr);
       
  3352 
       
  3353     return result;
       
  3354 }
       
  3355 
       
  3356 extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz,
       
  3357         jstring nameStr, jboolean preferIPv6Addresses) {
       
  3358     // LOGD("ENTER getHostByNameImpl");
       
  3359 
       
  3360     if (nameStr == NULL) {
       
  3361         throwNullPointerException(env);
       
  3362         return NULL;
       
  3363     }
       
  3364 
       
  3365     const char* name = env->GetStringUTFChars(nameStr, NULL);
       
  3366 
       
  3367     if (useAdbNetworking) {
       
  3368 
       
  3369         union {
       
  3370             struct in_addr a;
       
  3371             jbyte j[4];
       
  3372         } outaddr;
       
  3373 
       
  3374         // LOGD("ADB networking: +gethostbyname '%s'", name);
       
  3375         int err;
       
  3376         err = adb_networking_gethostbyname(name, &(outaddr.a));
       
  3377 
       
  3378         env->ReleaseStringUTFChars(nameStr, name);
       
  3379 #if 0
       
  3380         LOGD("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
       
  3381                 err, (unsigned int)outaddr.a.s_addr,
       
  3382                 outaddr.j[0],outaddr.j[1],
       
  3383                 outaddr.j[2],outaddr.j[3]);
       
  3384 #endif
       
  3385 
       
  3386         if (err < 0) {
       
  3387             return NULL;
       
  3388         } else {
       
  3389             jbyteArray addr = env->NewByteArray(4);
       
  3390             env->SetByteArrayRegion(addr, 0, 4, outaddr.j);
       
  3391             return addr;
       
  3392         }
       
  3393     } else {
       
  3394 
       
  3395         // normal case...no adb networking
       
  3396         struct hostent* ent = gethostbyname(name);
       
  3397 
       
  3398         env->ReleaseStringUTFChars(nameStr, name);
       
  3399 
       
  3400         if (ent != NULL  && ent->h_length > 0) {
       
  3401             jbyteArray addr = env->NewByteArray(4);
       
  3402             jbyte v[4];
       
  3403             memcpy(v, ent->h_addr, 4);
       
  3404             env->SetByteArrayRegion(addr, 0, 4, v);
       
  3405             return addr;
       
  3406         } else {
       
  3407             return NULL;
       
  3408         }
       
  3409     }
       
  3410 }
       
  3411 
       
  3412 extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
       
  3413         jobject sender, jbyteArray address) {
       
  3414     // LOGD("ENTER setInetAddressImpl");
       
  3415 
       
  3416     env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
       
  3417 }
       
  3418 
       
  3419 /*
       
  3420 extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
       
  3421     // LOGD("ENTER inheritedChannelImpl");
       
  3422 
       
  3423     int socket = 0;
       
  3424     int opt;
       
  3425     socklen_t length = sizeof(opt);
       
  3426     int socket_type;
       
  3427     struct sockaddr_in local_addr;
       
  3428     struct sockaddr_in remote_addr;
       
  3429     jclass channel_class, socketaddr_class, serverSocket_class, socketImpl_class;
       
  3430     jobject channel_object = NULL, socketaddr_object, serverSocket_object;
       
  3431     jobject fd_object, addr_object, localAddr_object, socketImpl_object;
       
  3432     jfieldID port_field, socketaddr_field, bound_field, fd_field;
       
  3433     jfieldID serverSocket_field, socketImpl_field, addr_field, localAddr_field;
       
  3434     jmethodID channel_new;
       
  3435     jbyteArray addr_array;
       
  3436     struct sockaddr_in *sock;
       
  3437     jbyte * address;
       
  3438     jbyte * localAddr;
       
  3439     jboolean jtrue = JNI_TRUE;
       
  3440 
       
  3441     if (0 != getsockopt(socket, SOL_SOCKET, SO_TYPE, &opt, &length)) {
       
  3442         return NULL;
       
  3443     }
       
  3444     if (SOCK_STREAM !=opt && SOCK_DGRAM !=opt) {
       
  3445         return NULL;
       
  3446     }
       
  3447     socket_type = opt;
       
  3448 
       
  3449     length  = sizeof(struct sockaddr);
       
  3450     if (0 != getsockname(socket, (struct sockaddr *)&local_addr, &length)) {
       
  3451         return NULL;
       
  3452     } else {
       
  3453         if (AF_INET != local_addr.sin_family || length != sizeof(struct sockaddr)) {
       
  3454             return NULL;
       
  3455         }
       
  3456         localAddr = (jbyte*) malloc(sizeof(jbyte)*4);
       
  3457         if (NULL == localAddr) {
       
  3458             return NULL;
       
  3459         }
       
  3460         memcpy (localAddr, &(local_addr.sin_addr.s_addr), 4);
       
  3461     }
       
  3462     if (0 != getpeername(socket, (struct sockaddr *)&remote_addr, &length)) {
       
  3463         remote_addr.sin_port = 0;
       
  3464         remote_addr.sin_addr.s_addr = 0;
       
  3465         address = (jbyte*) malloc(sizeof(jbyte)*4);
       
  3466         bzero(address, sizeof(jbyte)*4);
       
  3467     } else {
       
  3468         if (AF_INET != remote_addr.sin_family
       
  3469                 || length != sizeof(struct sockaddr)) {
       
  3470             return NULL;
       
  3471         }
       
  3472         address = (jbyte*) malloc(sizeof(jbyte)*4);
       
  3473         memcpy (address, &(remote_addr.sin_addr.s_addr), 4);
       
  3474     }
       
  3475 
       
  3476     // analysis end, begin pack to java
       
  3477     if (SOCK_STREAM == opt) {
       
  3478         if (remote_addr.sin_port!=0) {
       
  3479             //socket
       
  3480             channel_class = env->FindClass(
       
  3481                     "org/apache/harmony/nio/internal/SocketChannelImpl");
       
  3482             if (NULL == channel_class) {
       
  3483                 goto clean;
       
  3484             }
       
  3485 
       
  3486             channel_new = env->GetMethodID(channel_class, "<init>", "()V");
       
  3487             if (NULL == channel_new) {
       
  3488                 goto clean;
       
  3489             }
       
  3490             channel_object = env->NewObject(channel_class, channel_new);
       
  3491             if (NULL == channel_object) {
       
  3492                 goto clean;
       
  3493             }
       
  3494             // new and set FileDescript
       
  3495 
       
  3496             fd_field = env->GetFieldID(channel_class, "fd",
       
  3497                     "java/io/FielDescriptor");
       
  3498             fd_object = env->GetObjectField(channel_object, fd_field);
       
  3499             if (NULL == fd_object) {
       
  3500                 goto clean;
       
  3501             }
       
  3502 
       
  3503             jniSetFileDescriptorOfFD(env, fd_object, socket);
       
  3504 
       
  3505             // local port
       
  3506             port_field = env->GetFieldID(channel_class, "localPort", "I");
       
  3507             env->SetIntField(channel_object, port_field,
       
  3508                     ntohs(local_addr.sin_port));
       
  3509 
       
  3510             // new and set remote addr
       
  3511             addr_object = env->NewObject(gCachedFields.iaddr_class,
       
  3512                     gCachedFields.iaddr_class_init);
       
  3513             if (NULL == addr_object) {
       
  3514                 goto clean;
       
  3515             }
       
  3516             socketaddr_class = env->FindClass("java/net/InetSocketAddress");
       
  3517             socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
       
  3518                     "Ljava/net/InetSocketAddress;");
       
  3519             socketaddr_object = env->GetObjectField(channel_object,
       
  3520                     socketaddr_field);
       
  3521             if (NULL == socketaddr_object) {
       
  3522                 goto clean;
       
  3523             }
       
  3524             addr_field = env->GetFieldID(socketaddr_class, "addr",
       
  3525                     "Ljava/net/InetAddress;");
       
  3526             env->SetObjectField(socketaddr_object, addr_field, addr_object);
       
  3527             addr_array = env->NewByteArray((jsize)4);
       
  3528             env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
       
  3529             env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress,
       
  3530                      addr_array);
       
  3531 
       
  3532             // localAddr
       
  3533             socketaddr_class = env->FindClass("java/net/InetSocketAddress");
       
  3534             socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
       
  3535                      "Ljava/net/InetSocketAddress;");
       
  3536             socketaddr_object = env->GetObjectField(channel_object,
       
  3537                      socketaddr_field);
       
  3538 
       
  3539             localAddr_field = env->GetFieldID(channel_class, "localAddress",
       
  3540                      "Ljava/net/InetAddress;");
       
  3541             localAddr_object = env->NewObject(gCachedFields.iaddr_class,
       
  3542                      gCachedFields.iaddr_class_init);
       
  3543             jfieldID socketaddr_field = env->GetFieldID(channel_class,
       
  3544                      "connectAddress", "Ljava/net/InetSocketAddress;");
       
  3545             jobject socketaddr_object = env->GetObjectField(channel_object,
       
  3546                      socketaddr_field);
       
  3547             env->SetObjectField(socketaddr_object, localAddr_field,
       
  3548                      localAddr_object);
       
  3549             if (NULL == localAddr_object) {
       
  3550                 goto clean;
       
  3551             }
       
  3552             addr_array = env->NewByteArray((jsize)4);
       
  3553             env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
       
  3554             env->SetObjectField(localAddr_object, gCachedFields.iaddr_ipaddress,
       
  3555                     addr_array);
       
  3556 
       
  3557 
       
  3558             // set port
       
  3559             port_field = env->GetFieldID(socketaddr_class, "port", "I");
       
  3560             env->SetIntField(socketaddr_object, port_field,
       
  3561                     ntohs(remote_addr.sin_port));
       
  3562 
       
  3563             // set bound
       
  3564             if (0 != local_addr.sin_port) {
       
  3565                 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
       
  3566                 env->SetBooleanField(channel_object, bound_field, jtrue);
       
  3567             }
       
  3568 
       
  3569         } else {
       
  3570             //serverSocket
       
  3571             channel_class = env->FindClass(
       
  3572                     "org/apache/harmony/nio/internal/ServerSocketChannelImpl");
       
  3573             if (NULL == channel_class) {
       
  3574                 goto clean;
       
  3575             }
       
  3576 
       
  3577             channel_new = env->GetMethodID(channel_class, "<init>", "()V");
       
  3578             if (NULL == channel_new) {
       
  3579                 goto clean;
       
  3580             }
       
  3581             channel_object = env->NewObject(channel_class, channel_new);
       
  3582             if (NULL == channel_object) {
       
  3583                 goto clean;
       
  3584             }
       
  3585 
       
  3586             serverSocket_field = env->GetFieldID(channel_class, "socket",
       
  3587                     "Ljava/net/ServerSocket;");
       
  3588             serverSocket_class = env->FindClass("Ljava/net/ServerSocket;");
       
  3589             serverSocket_object = env->GetObjectField(channel_object,
       
  3590                     serverSocket_field);
       
  3591             // set bound
       
  3592             if (0 != local_addr.sin_port) {
       
  3593                 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
       
  3594                 env->SetBooleanField(channel_object, bound_field, jtrue);
       
  3595                 bound_field = env->GetFieldID(serverSocket_class, "isBound", "Z");
       
  3596                 env->SetBooleanField(serverSocket_object, bound_field, jtrue);
       
  3597             }
       
  3598             // localAddr
       
  3599             socketImpl_class = env->FindClass("java/net/SocketImpl");
       
  3600             socketImpl_field = env->GetFieldID(channel_class, "impl",
       
  3601                     "Ljava/net/SocketImpl;");
       
  3602             socketImpl_object =  env->GetObjectField(channel_object,
       
  3603                     socketImpl_field);
       
  3604             if (NULL == socketImpl_object) {
       
  3605                  goto clean;
       
  3606             }
       
  3607 
       
  3608             localAddr_field = env->GetFieldID(channel_class, "localAddress",
       
  3609                     "Ljava/net/InetAddress;");
       
  3610             localAddr_object = env->NewObject(gCachedFields.iaddr_class,
       
  3611                     gCachedFields.iaddr_class_init);
       
  3612             if (NULL == localAddr_object) {
       
  3613                  goto clean;
       
  3614             }
       
  3615             env->SetObjectField(socketImpl_object, localAddr_field,
       
  3616                     localAddr_object);
       
  3617             addr_array = env->NewByteArray((jsize)4);
       
  3618             env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
       
  3619             env->SetObjectField(localAddr_object,
       
  3620                     gCachedFields.iaddr_ipaddress, addr_array);
       
  3621 
       
  3622             // set port
       
  3623             port_field = env->GetFieldID(socketImpl_class, "localport", "I");
       
  3624             env->SetIntField(socketImpl_object, port_field,
       
  3625                     ntohs(local_addr.sin_port));
       
  3626         }
       
  3627     } else {
       
  3628         //Datagram Socket
       
  3629         // new DatagramChannel
       
  3630         channel_class = env->FindClass(
       
  3631                 "org/apache/harmony/nio/internal/DatagramChannelImpl");
       
  3632         if (NULL == channel_class) {
       
  3633             goto clean;
       
  3634         }
       
  3635 
       
  3636         channel_new = env->GetMethodID(channel_class, "<init>", "()V");
       
  3637         if (NULL == channel_new) {
       
  3638             goto clean;
       
  3639         }
       
  3640         channel_object = env->NewObject(channel_class, channel_new);
       
  3641         if (NULL == channel_object) {
       
  3642             goto clean;
       
  3643         }
       
  3644 
       
  3645         // new and set FileDescript
       
  3646         fd_field = env->GetFieldID(channel_class, "fd", "java/io/FileDescriptor");
       
  3647         fd_object = env->GetObjectField(channel_object, fd_field);
       
  3648         if (NULL == fd_object) {
       
  3649             goto clean;
       
  3650         }
       
  3651 
       
  3652         jniSetFileDescriptorOfFD(env, fd_object, socket);
       
  3653 
       
  3654         port_field = env->GetFieldID(channel_class, "localPort", "I");
       
  3655         env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
       
  3656 
       
  3657         // new and set remote addr
       
  3658         addr_object = env->NewObject(gCachedFields.iaddr_class,
       
  3659                 gCachedFields.iaddr_class_init);
       
  3660         if (NULL == addr_object) {
       
  3661             goto clean;
       
  3662         }
       
  3663         socketaddr_class = env->FindClass("java/net/InetSocketAddress");
       
  3664         socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
       
  3665                 "Ljava/net/InetSocketAddress;");
       
  3666         socketaddr_object = env->GetObjectField(channel_object, socketaddr_field);
       
  3667         if (NULL == socketaddr_object) {
       
  3668             goto clean;
       
  3669         }
       
  3670         addr_field = env->GetFieldID(socketaddr_class, "addr",
       
  3671                 "Ljava/net/InetAddress;");
       
  3672         env->SetObjectField(socketaddr_object, addr_field, addr_object);
       
  3673         addr_array = env->NewByteArray((jsize)4);
       
  3674         env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
       
  3675         env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress, addr_array);
       
  3676 
       
  3677         // set bound
       
  3678         if (0 != local_addr.sin_port) {
       
  3679             bound_field = env->GetFieldID(channel_class, "isBound", "Z");
       
  3680             env->SetBooleanField(channel_object, bound_field, jtrue);
       
  3681         }
       
  3682     }
       
  3683 clean:
       
  3684     free(address);
       
  3685     free(localAddr);
       
  3686     return channel_object;
       
  3687 }
       
  3688 */