|
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 */ |