Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c
+++ new/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c
1 1 /*
2 2 * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Sun designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Sun in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 23 * have any questions.
24 24 */
25 25
26 26 #include <windows.h>
27 27 #include <winsock2.h>
28 28 #include <ws2tcpip.h>
29 29 #include <ctype.h>
30 30 #include <stdio.h>
31 31 #include <stdlib.h>
32 32 #include <malloc.h>
33 33 #include <sys/types.h>
34 34
35 35 #ifndef IPTOS_TOS_MASK
36 36 #define IPTOS_TOS_MASK 0x1e
37 37 #endif
38 38 #ifndef IPTOS_PREC_MASK
39 39 #define IPTOS_PREC_MASK 0xe0
40 40 #endif
41 41
42 42 #include "java_net_TwoStacksPlainDatagramSocketImpl.h"
43 43 #include "java_net_SocketOptions.h"
44 44 #include "java_net_NetworkInterface.h"
45 45
46 46 #include "jvm.h"
47 47 #include "jni_util.h"
48 48 #include "net_util.h"
49 49
50 50 #define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000)
51 51 #define IN_MULTICAST(i) IN_CLASSD(i)
52 52
53 53 /************************************************************************
54 54 * TwoStacksPlainDatagramSocketImpl
55 55 */
56 56
57 57 static jfieldID IO_fd_fdID;
↓ open down ↓ |
57 lines elided |
↑ open up ↑ |
58 58 static jfieldID pdsi_trafficClassID;
59 59 jfieldID pdsi_fdID;
60 60 jfieldID pdsi_fd1ID;
61 61 jfieldID pdsi_fduseID;
62 62 jfieldID pdsi_lastfdID;
63 63 jfieldID pdsi_timeoutID;
64 64
65 65 jfieldID pdsi_localPortID;
66 66 jfieldID pdsi_connected;
67 67
68 -static jclass ia4_clazz;
69 -static jmethodID ia4_ctor;
70 -
71 68 static CRITICAL_SECTION sizeCheckLock;
72 69
73 70 /* Windows OS version is XP or better */
74 71 static int xp_or_later = 0;
75 72 /* Windows OS version is Windows 2000 or better */
76 73 static int w2k_or_later = 0;
77 74
78 75 /*
79 76 * Notes about UDP/IPV6 on Windows (XP and 2003 server):
80 77 *
81 78 * fd always points to the IPv4 fd, and fd1 points to the IPv6 fd.
82 79 * Both fds are used when we bind to a wild-card address. When a specific
83 80 * address is used, only one of them is used.
84 81 */
85 82
86 -/*
87 - * Returns a java.lang.Integer based on 'i'
88 - */
89 -jobject createInteger(JNIEnv *env, int i) {
90 - static jclass i_class;
91 - static jmethodID i_ctrID;
92 - static jfieldID i_valueID;
83 +static jclass i_class;
84 +static jmethodID i_ctrID;
85 +static jfieldID i_valueID;
93 86
87 +int initIntegerIDs(JNIEnv* env) {
94 88 if (i_class == NULL) {
95 89 jclass c = (*env)->FindClass(env, "java/lang/Integer");
96 90 CHECK_NULL_RETURN(c, NULL);
97 91 i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
98 92 CHECK_NULL_RETURN(i_ctrID, NULL);
93 + i_valueID = (*env)->GetFieldID(env, c, "value", "I");
94 + CHECK_NULL_RETURN(i_valueID, NULL);
99 95 i_class = (*env)->NewGlobalRef(env, c);
100 96 CHECK_NULL_RETURN(i_class, NULL);
101 97 }
98 + return 1;
99 +}
102 100
101 +/* Returns a java.lang.Integer based on 'i' */
102 +static jobject createInteger(JNIEnv *env, int i) {
103 + CHECK_NULL_RETURN(initIntegerIDs(env), NULL);
103 104 return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
104 105 }
105 106
106 -/*
107 - * Returns a java.lang.Boolean based on 'b'
108 - */
109 -jobject createBoolean(JNIEnv *env, int b) {
110 - static jclass b_class;
111 - static jmethodID b_ctrID;
112 - static jfieldID b_valueID;
107 +/* Returns a jint based on the given java.lang.Integer */
108 +static jint retrieveInteger(JNIEnv *env, jobject i) {
109 + CHECK_NULL_RETURN(initIntegerIDs(env), NULL);
110 + return (*env)->GetIntField(env, i, i_valueID);
111 +}
113 112
113 +static jclass b_class;
114 +static jmethodID b_ctrID;
115 +static jfieldID b_valueID;
116 +
117 +int initBooleanIDs(JNIEnv* env) {
114 118 if (b_class == NULL) {
115 119 jclass c = (*env)->FindClass(env, "java/lang/Boolean");
116 120 CHECK_NULL_RETURN(c, NULL);
117 121 b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
118 122 CHECK_NULL_RETURN(b_ctrID, NULL);
123 + b_valueID = (*env)->GetFieldID(env, c, "value", "Z");
124 + CHECK_NULL_RETURN(b_valueID, NULL);
119 125 b_class = (*env)->NewGlobalRef(env, c);
120 126 CHECK_NULL_RETURN(b_class, NULL);
121 127 }
128 + return 1;
129 +}
122 130
131 +/* Returns a java.lang.Boolean based on 'b' */
132 +static jobject createBoolean(JNIEnv *env, int b) {
133 + CHECK_NULL_RETURN(initBooleanIDs(env), NULL);
123 134 return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
124 135 }
125 136
137 +/* Returns a jboolean based on the given java.lang.Boolean */
138 +static jboolean retrieveBoolean(JNIEnv *env, jobject b) {
139 + CHECK_NULL_RETURN(initBooleanIDs(env), NULL);
140 + return (*env)->GetBooleanField(env, b, b_valueID);
141 +}
126 142
127 143 static int getFD(JNIEnv *env, jobject this) {
128 144 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
129 145
130 146 if (fdObj == NULL) {
131 147 return -1;
132 148 }
133 149 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
134 150 }
135 151
136 152 static int getFD1(JNIEnv *env, jobject this) {
137 153 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
138 154
139 155 if (fdObj == NULL) {
140 156 return -1;
141 157 }
142 158 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
143 159 }
144 160
145 161 /*
146 162 * This function returns JNI_TRUE if the datagram size exceeds the underlying
147 163 * provider's ability to send to the target address. The following OS
148 164 * oddies have been observed :-
149 165 *
150 166 * 1. On Windows 95/98 if we try to send a datagram > 12k to an application
151 167 * on the same machine then the send will fail silently.
152 168 *
153 169 * 2. On Windows ME if we try to send a datagram > supported by underlying
154 170 * provider then send will not return an error.
155 171 *
156 172 * 3. On Windows NT/2000 if we exceeds the maximum size then send will fail
157 173 * with WSAEADDRNOTAVAIL.
158 174 *
159 175 * 4. On Windows 95/98 if we exceed the maximum size when sending to
160 176 * another machine then WSAEINVAL is returned.
161 177 *
162 178 */
163 179 jboolean exceedSizeLimit(JNIEnv *env, jint fd, jint addr, jint size)
164 180 {
165 181 #define DEFAULT_MSG_SIZE 65527
166 182 static jboolean initDone;
167 183 static jboolean is95or98;
168 184 static int maxmsg;
169 185
170 186 typedef struct _netaddr { /* Windows 95/98 only */
171 187 unsigned long addr;
172 188 struct _netaddr *next;
173 189 } netaddr;
174 190 static netaddr *addrList;
175 191 netaddr *curr;
176 192
177 193 /*
178 194 * First time we are called we must determine which OS this is and also
179 195 * get the maximum size supported by the underlying provider.
180 196 *
181 197 * In addition on 95/98 we must enumerate our IP addresses.
182 198 */
183 199 if (!initDone) {
184 200 EnterCriticalSection(&sizeCheckLock);
185 201
186 202 if (initDone) {
187 203 /* another thread got there first */
188 204 LeaveCriticalSection(&sizeCheckLock);
189 205
190 206 } else {
191 207 OSVERSIONINFO ver;
192 208 int len;
193 209
194 210 /*
195 211 * Step 1: Determine which OS this is.
196 212 */
197 213 ver.dwOSVersionInfoSize = sizeof(ver);
198 214 GetVersionEx(&ver);
199 215
200 216 is95or98 = JNI_FALSE;
201 217 if (ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
202 218 ver.dwMajorVersion == 4 &&
203 219 (ver.dwMinorVersion == 0 || ver.dwMinorVersion == 10)) {
204 220
205 221 is95or98 = JNI_TRUE;
206 222 }
207 223
208 224 /*
209 225 * Step 2: Determine the maximum datagram supported by the
210 226 * underlying provider. On Windows 95 if winsock hasn't been
211 227 * upgraded (ie: unsupported configuration) then we assume
212 228 * the default 64k limit.
213 229 */
214 230 len = sizeof(maxmsg);
215 231 if (NET_GetSockOpt(fd, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&maxmsg, &len) < 0) {
216 232 maxmsg = DEFAULT_MSG_SIZE;
217 233 }
218 234
219 235 /*
220 236 * Step 3: On Windows 95/98 then enumerate the IP addresses on
221 237 * this machine. This is necesary because we need to check if the
222 238 * datagram is being sent to an application on the same machine.
223 239 */
224 240 if (is95or98) {
225 241 char hostname[255];
226 242 struct hostent *hp;
227 243
228 244 if (gethostname(hostname, sizeof(hostname)) == -1) {
229 245 LeaveCriticalSection(&sizeCheckLock);
230 246 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unable to obtain hostname");
231 247 return JNI_TRUE;
232 248 }
233 249 hp = (struct hostent *)gethostbyname(hostname);
234 250 if (hp != NULL) {
235 251 struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
236 252
237 253 while (*addrp != (struct in_addr *) 0) {
238 254 curr = (netaddr *)malloc(sizeof(netaddr));
239 255 if (curr == NULL) {
240 256 while (addrList != NULL) {
241 257 curr = addrList->next;
242 258 free(addrList);
243 259 addrList = curr;
244 260 }
245 261 LeaveCriticalSection(&sizeCheckLock);
246 262 JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
247 263 return JNI_TRUE;
248 264 }
249 265 curr->addr = htonl((*addrp)->S_un.S_addr);
250 266 curr->next = addrList;
251 267 addrList = curr;
252 268 addrp++;
253 269 }
254 270 }
255 271 }
256 272
257 273 /*
258 274 * Step 4: initialization is done so set flag and unlock cs
259 275 */
260 276 initDone = JNI_TRUE;
261 277 LeaveCriticalSection(&sizeCheckLock);
262 278 }
263 279 }
264 280
265 281 /*
266 282 * Now examine the size of the datagram :-
267 283 *
268 284 * (a) If exceeds size of service provider return 'false' to indicate that
269 285 * we exceed the limit.
270 286 * (b) If not 95/98 then return 'true' to indicate that the size is okay.
271 287 * (c) On 95/98 if the size is <12k we are okay.
272 288 * (d) On 95/98 if size > 12k then check if the destination is the current
273 289 * machine.
274 290 */
275 291 if (size > maxmsg) { /* step (a) */
276 292 return JNI_TRUE;
277 293 }
278 294 if (!is95or98) { /* step (b) */
279 295 return JNI_FALSE;
280 296 }
281 297 if (size <= 12280) { /* step (c) */
282 298 return JNI_FALSE;
283 299 }
284 300
285 301 /* step (d) */
286 302
287 303 if ((addr & 0x7f000000) == 0x7f000000) {
288 304 return JNI_TRUE;
289 305 }
290 306 curr = addrList;
291 307 while (curr != NULL) {
292 308 if (curr->addr == addr) {
293 309 return JNI_TRUE;
294 310 }
295 311 curr = curr->next;
296 312 }
297 313 return JNI_FALSE;
298 314 }
299 315
300 316 /*
301 317 * Return JNI_TRUE if this Windows edition supports ICMP Port Unreachable
302 318 */
303 319 __inline static jboolean supportPortUnreachable() {
304 320 static jboolean initDone;
305 321 static jboolean portUnreachableSupported;
306 322
307 323 if (!initDone) {
308 324 OSVERSIONINFO ver;
309 325 ver.dwOSVersionInfoSize = sizeof(ver);
310 326 GetVersionEx(&ver);
311 327 if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ver.dwMajorVersion >= 5) {
312 328 portUnreachableSupported = JNI_TRUE;
313 329 } else {
314 330 portUnreachableSupported = JNI_FALSE;
315 331 }
316 332 initDone = JNI_TRUE;
317 333 }
318 334 return portUnreachableSupported;
319 335 }
320 336
321 337 /*
322 338 * This function "purges" all outstanding ICMP port unreachable packets
323 339 * outstanding on a socket and returns JNI_TRUE if any ICMP messages
324 340 * have been purged. The rational for purging is to emulate normal BSD
325 341 * behaviour whereby receiving a "connection reset" status resets the
326 342 * socket.
327 343 */
328 344 static jboolean purgeOutstandingICMP(JNIEnv *env, jobject this, jint fd)
329 345 {
330 346 jboolean got_icmp = JNI_FALSE;
331 347 char buf[1];
332 348 fd_set tbl;
333 349 struct timeval t = { 0, 0 };
334 350 struct sockaddr_in rmtaddr;
335 351 int addrlen = sizeof(rmtaddr);
336 352
337 353 /*
338 354 * A no-op if this OS doesn't support it.
339 355 */
340 356 if (!supportPortUnreachable()) {
341 357 return JNI_FALSE;
342 358 }
343 359
344 360 /*
345 361 * Peek at the queue to see if there is an ICMP port unreachable. If there
346 362 * is then receive it.
347 363 */
348 364 FD_ZERO(&tbl);
349 365 FD_SET(fd, &tbl);
350 366 while(1) {
351 367 if (select(/*ignored*/fd+1, &tbl, 0, 0, &t) <= 0) {
352 368 break;
353 369 }
354 370 if (recvfrom(fd, buf, 1, MSG_PEEK,
355 371 (struct sockaddr *)&rmtaddr, &addrlen) != JVM_IO_ERR) {
356 372 break;
357 373 }
358 374 if (WSAGetLastError() != WSAECONNRESET) {
359 375 /* some other error - we don't care here */
360 376 break;
361 377 }
362 378
363 379 recvfrom(fd, buf, 1, 0, (struct sockaddr *)&rmtaddr, &addrlen);
364 380 got_icmp = JNI_TRUE;
365 381 }
366 382
367 383 return got_icmp;
368 384 }
369 385
370 386
371 387 /*
372 388 * Class: java_net_TwoStacksPlainDatagramSocketImpl
373 389 * Method: init
374 390 * Signature: ()V
375 391 */
376 392 JNIEXPORT void JNICALL
377 393 Java_java_net_TwoStacksPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
378 394
379 395 OSVERSIONINFO ver;
380 396 int version;
381 397 ver.dwOSVersionInfoSize = sizeof(ver);
382 398 GetVersionEx(&ver);
383 399
384 400 version = ver.dwMajorVersion * 10 + ver.dwMinorVersion;
385 401 xp_or_later = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (version >= 51);
386 402 w2k_or_later = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (version >= 50);
387 403
388 404 /* get fieldIDs */
389 405 pdsi_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;");
390 406 CHECK_NULL(pdsi_fdID);
391 407 pdsi_fd1ID = (*env)->GetFieldID(env, cls, "fd1", "Ljava/io/FileDescriptor;");
392 408 CHECK_NULL(pdsi_fd1ID);
393 409 pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
394 410 CHECK_NULL(pdsi_timeoutID);
395 411 pdsi_fduseID = (*env)->GetFieldID(env, cls, "fduse", "I");
396 412 CHECK_NULL(pdsi_fduseID);
397 413 pdsi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I");
398 414 CHECK_NULL(pdsi_lastfdID);
399 415 pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
400 416 CHECK_NULL(pdsi_trafficClassID);
↓ open down ↓ |
265 lines elided |
↑ open up ↑ |
401 417 pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I");
402 418 CHECK_NULL(pdsi_localPortID);
403 419 pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z");
404 420 CHECK_NULL(pdsi_connected);
405 421
406 422 cls = (*env)->FindClass(env, "java/io/FileDescriptor");
407 423 CHECK_NULL(cls);
408 424 IO_fd_fdID = NET_GetFileDescriptorID(env);
409 425 CHECK_NULL(IO_fd_fdID);
410 426
411 - ia4_clazz = (*env)->FindClass(env, "java/net/Inet4Address");
412 - CHECK_NULL(ia4_clazz);
413 - ia4_clazz = (*env)->NewGlobalRef(env, ia4_clazz);
414 - CHECK_NULL(ia4_clazz);
415 - ia4_ctor = (*env)->GetMethodID(env, ia4_clazz, "<init>", "()V");
416 - CHECK_NULL(ia4_ctor);
427 + // Load static data (jclass, methodIDs, fieldID ) from InetAddress,
428 + // Inet4Address, Inet6Address and NetorkInterface.
429 + init(env);
430 + (*env)->FindClass(env, "java/net/NetworkInterface");
417 431
418 -
419 - InitializeCriticalSection(&sizeCheckLock);
432 + InitializeCriticalSection(&sizeCheckLock);
420 433 }
421 434
422 435 JNIEXPORT void JNICALL
423 436 Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
424 437 jint port, jobject addressObj) {
425 438 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
426 439 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
427 440
428 441 int fd, fd1, family;
429 442 int ipv6_supported = ipv6_available();
430 443
431 444 SOCKETADDRESS lcladdr;
432 445 int lcladdrlen;
433 446 int address;
434 447
435 448 family = (*env)->GetIntField(env, addressObj, ia_familyID);
436 449 if (family == IPv6 && !ipv6_supported) {
437 450 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
438 451 "Protocol family not supported");
439 452 return;
440 453 }
441 454
442 455 if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
443 456 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
444 457 return;
445 458 } else {
446 459 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
447 460 if (ipv6_supported) {
448 461 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
449 462 }
450 463 }
451 464 if (IS_NULL(addressObj)) {
452 465 JNU_ThrowNullPointerException(env, "argument address");
453 466 return;
454 467 } else {
455 468 address = (*env)->GetIntField(env, addressObj, ia_addressID);
456 469 }
457 470
458 471 if (NET_InetAddressToSockaddr(env, addressObj, port, (struct sockaddr *)&lcladdr, &lcladdrlen, JNI_FALSE) != 0) {
459 472 return;
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
460 473 }
461 474
462 475 if (ipv6_supported) {
463 476 struct ipv6bind v6bind;
464 477 v6bind.addr = &lcladdr;
465 478 v6bind.ipv4_fd = fd;
466 479 v6bind.ipv6_fd = fd1;
467 480 if (NET_BindV6(&v6bind) != -1) {
468 481 /* check if the fds have changed */
469 482 if (v6bind.ipv4_fd != fd) {
470 - fd = v6bind.ipv4_fd;
483 + fd = (int)v6bind.ipv4_fd;
471 484 if (fd == -1) {
472 485 /* socket is closed. */
473 486 (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
474 487 } else {
475 488 /* socket was re-created */
476 489 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
477 490 }
478 491 }
479 492 if (v6bind.ipv6_fd != fd1) {
480 - fd1 = v6bind.ipv6_fd;
493 + fd1 = (int)v6bind.ipv6_fd;
481 494 if (fd1 == -1) {
482 495 /* socket is closed. */
483 496 (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
484 497 } else {
485 498 /* socket was re-created */
486 499 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
487 500 }
488 501 }
489 502 } else {
490 503 NET_ThrowCurrent (env, "Cannot bind");
491 504 return;
492 505 }
493 506 } else {
494 507 if (bind(fd, (struct sockaddr *)&lcladdr, lcladdrlen) == -1) {
495 508 if (WSAGetLastError() == WSAEACCES) {
496 509 WSASetLastError(WSAEADDRINUSE);
497 510 }
498 511 NET_ThrowCurrent(env, "Cannot bind");
499 512 return;
500 513 }
501 514 }
502 515
503 516 if (port == 0) {
504 517 if (fd == -1) {
505 518 /* must be an IPV6 only socket. */
506 519 fd = fd1;
507 520 }
508 521 if (getsockname(fd, (struct sockaddr *)&lcladdr, &lcladdrlen) == -1) {
509 522 NET_ThrowCurrent(env, "JVM_GetSockName");
510 523 return;
511 524 }
512 525 port = ntohs((u_short) GET_PORT (&lcladdr));
513 526 }
514 527 (*env)->SetIntField(env, this, pdsi_localPortID, port);
515 528 }
516 529
517 530
518 531 /*
519 532 * Class: java_net_TwoStacksPlainDatagramSocketImpl
520 533 * Method: connect0
521 534 * Signature: (Ljava/net/InetAddress;I)V
522 535 */
523 536
524 537 JNIEXPORT void JNICALL
525 538 Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
526 539 jobject address, jint port) {
527 540 /* The object's field */
528 541 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
529 542 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
530 543 /* The fdObj'fd */
531 544 jint fd=-1, fd1=-1, fdc;
532 545 /* The packetAddress address, family and port */
533 546 jint addr, family;
534 547 SOCKETADDRESS rmtaddr;
535 548 int rmtaddrlen;
536 549 int ipv6_supported = ipv6_available();
537 550
538 551 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
539 552 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
540 553 "Socket closed");
541 554 return;
542 555 }
543 556 if (!IS_NULL(fdObj)) {
544 557 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
545 558 }
546 559 if (!IS_NULL(fd1Obj)) {
547 560 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
548 561 }
549 562
550 563 if (IS_NULL(address)) {
551 564 JNU_ThrowNullPointerException(env, "address");
552 565 return;
553 566 }
554 567
555 568 addr = (*env)->GetIntField(env, address, ia_addressID);
556 569
557 570 family = (*env)->GetIntField(env, address, ia_familyID);
558 571 if (family == IPv6 && !ipv6_supported) {
559 572 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
560 573 "Protocol family not supported");
561 574 return;
562 575 }
563 576
564 577 fdc = family == IPv4? fd: fd1;
565 578
566 579 if (xp_or_later) {
567 580 /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
568 581 * returns connection reset errors un connected UDP sockets (as well
569 582 * as connected sockets. The solution is to only enable this feature
570 583 * when the socket is connected
571 584 */
572 585 DWORD x1, x2; /* ignored result codes */
573 586 int res, t = TRUE;
574 587 res = WSAIoctl(fdc,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
575 588 }
576 589
577 590 if (NET_InetAddressToSockaddr(env, address, port,(struct sockaddr *)&rmtaddr, &rmtaddrlen, JNI_FALSE) != 0) {
578 591 return;
579 592 }
580 593
581 594 if (connect(fdc, (struct sockaddr *)&rmtaddr, sizeof(rmtaddr)) == -1) {
582 595 NET_ThrowCurrent(env, "connect");
583 596 return;
584 597 }
585 598 }
586 599
587 600 /*
588 601 * Class: java_net_TwoStacksPlainDatagramSocketImpl
589 602 * Method: disconnect0
590 603 * Signature: ()V
591 604 */
592 605
593 606 JNIEXPORT void JNICALL
594 607 Java_java_net_TwoStacksPlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
595 608 /* The object's field */
596 609 jobject fdObj;
597 610 /* The fdObj'fd */
598 611 jint fd, len;
599 612 SOCKETADDRESS addr;
600 613
601 614 if (family == IPv4) {
602 615 fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
603 616 len = sizeof (struct sockaddr_in);
604 617 } else {
605 618 fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
606 619 len = sizeof (struct SOCKADDR_IN6);
607 620 }
608 621
609 622 if (IS_NULL(fdObj)) {
610 623 /* disconnect doesn't throw any exceptions */
611 624 return;
612 625 }
613 626 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
614 627
615 628 memset(&addr, 0, len);
616 629 connect(fd, (struct sockaddr *)&addr, len);
617 630
618 631 /*
619 632 * use SIO_UDP_CONNRESET
620 633 * to disable ICMP port unreachable handling here.
621 634 */
622 635 if (xp_or_later) {
623 636 DWORD x1, x2; /* ignored result codes */
624 637 int t = FALSE;
625 638 WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
626 639 }
627 640 }
628 641
629 642 /*
630 643 * Class: java_net_TwoStacksPlainDatagramSocketImpl
631 644 * Method: send
632 645 * Signature: (Ljava/net/DatagramPacket;)V
633 646 */
634 647 JNIEXPORT void JNICALL
635 648 Java_java_net_TwoStacksPlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
636 649 jobject packet) {
637 650
638 651 char BUF[MAX_BUFFER_LEN];
639 652 char *fullPacket;
640 653 jobject fdObj;
641 654 jint fd;
642 655
643 656 jobject iaObj;
644 657 jint address;
645 658 jint family;
646 659
647 660 jint packetBufferOffset, packetBufferLen, packetPort;
648 661 jbyteArray packetBuffer;
649 662 jboolean connected;
650 663
651 664 SOCKETADDRESS rmtaddr;
652 665 SOCKETADDRESS *addrp = &rmtaddr;
653 666 int addrlen;
654 667
655 668
656 669 if (IS_NULL(packet)) {
657 670 JNU_ThrowNullPointerException(env, "null packet");
658 671 return;
659 672 }
660 673
661 674 iaObj = (*env)->GetObjectField(env, packet, dp_addressID);
662 675
663 676 packetPort = (*env)->GetIntField(env, packet, dp_portID);
664 677 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
665 678 packetBuffer = (jbyteArray)(*env)->GetObjectField(env, packet, dp_bufID);
666 679 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
667 680
668 681 if (IS_NULL(iaObj) || IS_NULL(packetBuffer)) {
669 682 JNU_ThrowNullPointerException(env, "null address || null buffer");
670 683 return;
671 684 }
672 685
673 686 family = (*env)->GetIntField(env, iaObj, ia_familyID);
674 687 if (family == IPv4) {
675 688 fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
676 689 } else {
677 690 if (!ipv6_available()) {
678 691 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
679 692 "Protocol not allowed");
680 693 return;
681 694 }
682 695 fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
683 696 }
684 697
685 698 if (IS_NULL(fdObj)) {
686 699 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
687 700 "Socket closed");
688 701 return;
689 702 }
690 703 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
691 704
692 705 packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
693 706
694 707 if (connected) {
695 708 addrp = 0; /* arg to JVM_Sendto () null in this case */
696 709 addrlen = 0;
697 710 } else {
698 711 if (NET_InetAddressToSockaddr(env, iaObj, packetPort, (struct sockaddr *)&rmtaddr, &addrlen, JNI_FALSE) != 0) {
699 712 return;
700 713 }
701 714 }
702 715
703 716 if (packetBufferLen > MAX_BUFFER_LEN) {
704 717
705 718 /*
706 719 * On 95/98 if we try to send a datagram >12k to an application
707 720 * on the same machine then this will fail silently. Thus we
708 721 * catch this situation here so that we can throw an exception
709 722 * when this arises.
710 723 * On ME if we try to send a datagram with a size greater than
711 724 * that supported by the service provider then no error is
712 725 * returned.
713 726 */
714 727 if (!w2k_or_later) { /* avoid this check on Win 2K or better. Does not work with IPv6.
715 728 * Check is not necessary on these OSes */
716 729 if (connected) {
717 730 address = (*env)->GetIntField(env, iaObj, ia_addressID);
718 731 } else {
719 732 address = ntohl(rmtaddr.him4.sin_addr.s_addr);
720 733 }
721 734
722 735 if (exceedSizeLimit(env, fd, address, packetBufferLen)) {
723 736 if (!((*env)->ExceptionOccurred(env))) {
724 737 NET_ThrowNew(env, WSAEMSGSIZE, "Datagram send failed");
725 738 }
726 739 return;
727 740 }
728 741 }
729 742
730 743 /* When JNI-ifying the JDK's IO routines, we turned
731 744 * read's and write's of byte arrays of size greater
732 745 * than 2048 bytes into several operations of size 2048.
733 746 * This saves a malloc()/memcpy()/free() for big
734 747 * buffers. This is OK for file IO and TCP, but that
735 748 * strategy violates the semantics of a datagram protocol.
736 749 * (one big send) != (several smaller sends). So here
737 750 * we *must* alloc the buffer. Note it needn't be bigger
738 751 * than 65,536 (0xFFFF) the max size of an IP packet.
739 752 * anything bigger is truncated anyway.
740 753 */
741 754 fullPacket = (char *)malloc(packetBufferLen);
742 755 if (!fullPacket) {
743 756 JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
744 757 return;
745 758 }
746 759 } else {
747 760 fullPacket = &(BUF[0]);
748 761 }
749 762
750 763 (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
751 764 (jbyte *)fullPacket);
752 765 switch (sendto(fd, fullPacket, packetBufferLen, 0,
753 766 (struct sockaddr *)addrp, addrlen)) {
754 767 case JVM_IO_ERR:
755 768 NET_ThrowCurrent(env, "Datagram send failed");
756 769 break;
757 770
758 771 case JVM_IO_INTR:
759 772 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
760 773 "operation interrupted");
761 774 }
762 775
763 776 if (packetBufferLen > MAX_BUFFER_LEN) {
764 777 free(fullPacket);
765 778 }
766 779 }
767 780
768 781 /*
769 782 * check which socket was last serviced when there was data on both sockets.
770 783 * Only call this if sure that there is data on both sockets.
771 784 */
772 785 static int checkLastFD (JNIEnv *env, jobject this, int fd, int fd1) {
773 786 int nextfd, lastfd = (*env)->GetIntField(env, this, pdsi_lastfdID);
774 787 if (lastfd == -1) {
775 788 /* arbitrary. Choose fd */
776 789 (*env)->SetIntField(env, this, pdsi_lastfdID, fd);
777 790 return fd;
778 791 } else {
779 792 if (lastfd == fd) {
780 793 nextfd = fd1;
781 794 } else {
782 795 nextfd = fd;
783 796 }
784 797 (*env)->SetIntField(env, this, pdsi_lastfdID, nextfd);
785 798 return nextfd;
786 799 }
787 800 }
788 801
789 802 /*
790 803 * Class: java_net_TwoStacksPlainDatagramSocketImpl
791 804 * Method: peek
792 805 * Signature: (Ljava/net/InetAddress;)I
793 806 */
794 807 JNIEXPORT jint JNICALL
795 808 Java_java_net_TwoStacksPlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
796 809 jobject addressObj) {
797 810
798 811 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
799 812 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
800 813 jint fd;
801 814
802 815 /* The address and family fields of addressObj */
803 816 jint address, family;
804 817
805 818 int n;
806 819 struct sockaddr_in remote_addr;
807 820 jint remote_addrsize = sizeof (remote_addr);
808 821 char buf[1];
809 822 BOOL retry;
810 823 jlong prevTime = 0;
811 824
812 825 if (IS_NULL(fdObj)) {
813 826 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
814 827 return -1;
815 828 } else {
816 829 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
817 830 if (fd < 0) {
818 831 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
819 832 "socket closed");
820 833 return -1;
821 834 }
822 835 }
823 836 if (IS_NULL(addressObj)) {
824 837 JNU_ThrowNullPointerException(env, "Null address in peek()");
825 838 } else {
826 839 address = (*env)->GetIntField(env, addressObj, ia_addressID);
827 840 /* We only handle IPv4 for now. Will support IPv6 once its in the os */
828 841 family = AF_INET;
829 842 }
830 843
831 844 do {
832 845 retry = FALSE;
833 846
834 847 /*
835 848 * If a timeout has been specified then we select on the socket
836 849 * waiting for a read event or a timeout.
837 850 */
838 851 if (timeout) {
839 852 int ret;
840 853 prevTime = JVM_CurrentTimeMillis(env, 0);
841 854 ret = NET_Timeout (fd, timeout);
842 855 if (ret == 0) {
843 856 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
844 857 "Peek timed out");
845 858 return ret;
846 859 } else if (ret == JVM_IO_ERR) {
847 860 NET_ThrowCurrent(env, "timeout in datagram socket peek");
848 861 return ret;
849 862 } else if (ret == JVM_IO_INTR) {
850 863 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
851 864 "operation interrupted");
852 865 return ret;
853 866 }
854 867 }
855 868
856 869 /* now try the peek */
857 870 n = recvfrom(fd, buf, 1, MSG_PEEK,
858 871 (struct sockaddr *)&remote_addr, &remote_addrsize);
859 872
860 873 if (n == JVM_IO_ERR) {
861 874 if (WSAGetLastError() == WSAECONNRESET) {
862 875 jboolean connected;
863 876
864 877 /*
865 878 * An icmp port unreachable - we must receive this as Windows
866 879 * does not reset the state of the socket until this has been
867 880 * received.
868 881 */
869 882 purgeOutstandingICMP(env, this, fd);
870 883
871 884 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
872 885 if (connected) {
873 886 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
874 887 "ICMP Port Unreachable");
875 888 return 0;
876 889 }
877 890
878 891 /*
879 892 * If a timeout was specified then we need to adjust it because
880 893 * we may have used up some of the timeout befor the icmp port
881 894 * unreachable arrived.
882 895 */
883 896 if (timeout) {
884 897 jlong newTime = JVM_CurrentTimeMillis(env, 0);
885 898 timeout -= (jint)(newTime - prevTime);
886 899 if (timeout <= 0) {
887 900 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
888 901 "Receive timed out");
889 902 return 0;
890 903 }
891 904 prevTime = newTime;
892 905 }
893 906
894 907 /* Need to retry the recv */
895 908 retry = TRUE;
896 909 }
897 910 }
898 911 } while (retry);
899 912
900 913 if (n == JVM_IO_ERR && WSAGetLastError() != WSAEMSGSIZE) {
901 914 NET_ThrowCurrent(env, "Datagram peek failed");
902 915 return 0;
903 916 }
904 917 if (n == JVM_IO_INTR) {
905 918 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 0);
906 919 return 0;
907 920 }
908 921 (*env)->SetIntField(env, addressObj, ia_addressID,
909 922 ntohl(remote_addr.sin_addr.s_addr));
910 923 (*env)->SetIntField(env, addressObj, ia_familyID, IPv4);
911 924
912 925 /* return port */
913 926 return ntohs(remote_addr.sin_port);
914 927 }
915 928
916 929 JNIEXPORT jint JNICALL
917 930 Java_java_net_TwoStacksPlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
918 931 jobject packet) {
919 932
920 933 char BUF[MAX_BUFFER_LEN];
921 934 char *fullPacket;
922 935 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
923 936 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
924 937 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
925 938
926 939 jbyteArray packetBuffer;
927 940 jint packetBufferOffset, packetBufferLen;
928 941
929 942 int fd, fd1, fduse, nsockets=0, errorCode;
930 943 int port;
931 944
932 945 int checkBoth = 0;
933 946 int n;
934 947 SOCKETADDRESS remote_addr;
935 948 jint remote_addrsize=sizeof(remote_addr);
936 949 BOOL retry;
937 950 jlong prevTime = 0;
938 951
939 952 if (!IS_NULL(fdObj)) {
940 953 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
941 954 if (fd < 0) {
942 955 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
943 956 "socket closed");
944 957 return -1;
945 958 }
946 959 nsockets = 1;
947 960 }
948 961
949 962 if (!IS_NULL(fd1Obj)) {
950 963 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
951 964 if (fd1 < 0) {
952 965 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
953 966 "socket closed");
954 967 return -1;
955 968 }
956 969 nsockets ++;
957 970 }
958 971
959 972 switch (nsockets) {
960 973 case 0:
961 974 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
962 975 "socket closed");
963 976 return -1;
964 977 case 1:
965 978 if (!IS_NULL(fdObj)) {
966 979 fduse = fd;
967 980 } else {
968 981 fduse = fd1;
969 982 }
970 983 break;
971 984 case 2:
972 985 checkBoth = TRUE;
973 986 break;
974 987 }
975 988
976 989 if (IS_NULL(packet)) {
977 990 JNU_ThrowNullPointerException(env, "packet");
978 991 return -1;
979 992 }
980 993
981 994 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
982 995
983 996 if (IS_NULL(packetBuffer)) {
984 997 JNU_ThrowNullPointerException(env, "packet buffer");
985 998 return -1;
986 999 }
987 1000
988 1001 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
989 1002 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
990 1003
991 1004 if (packetBufferLen > MAX_BUFFER_LEN) {
992 1005
993 1006 /* When JNI-ifying the JDK's IO routines, we turned
994 1007 * read's and write's of byte arrays of size greater
995 1008 * than 2048 bytes into several operations of size 2048.
996 1009 * This saves a malloc()/memcpy()/free() for big
997 1010 * buffers. This is OK for file IO and TCP, but that
998 1011 * strategy violates the semantics of a datagram protocol.
999 1012 * (one big send) != (several smaller sends). So here
1000 1013 * we *must* alloc the buffer. Note it needn't be bigger
1001 1014 * than 65,536 (0xFFFF) the max size of an IP packet.
1002 1015 * anything bigger is truncated anyway.
1003 1016 */
1004 1017 fullPacket = (char *)malloc(packetBufferLen);
1005 1018 if (!fullPacket) {
1006 1019 JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
1007 1020 return -1;
1008 1021 }
1009 1022 } else {
1010 1023 fullPacket = &(BUF[0]);
1011 1024 }
1012 1025
1013 1026 do {
1014 1027 int ret;
1015 1028 retry = FALSE;
1016 1029
1017 1030 /*
1018 1031 * If a timeout has been specified then we select on the socket
1019 1032 * waiting for a read event or a timeout.
1020 1033 */
1021 1034 if (checkBoth) {
1022 1035 int t = timeout == 0 ? -1: timeout;
1023 1036 prevTime = JVM_CurrentTimeMillis(env, 0);
1024 1037 ret = NET_Timeout2 (fd, fd1, t, &fduse);
1025 1038 /* all subsequent calls to recv() or select() will use the same fd
1026 1039 * for this call to peek() */
1027 1040 if (ret <= 0) {
1028 1041 if (ret == 0) {
1029 1042 JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
1030 1043 "Peek timed out");
1031 1044 } else if (ret == JVM_IO_ERR) {
1032 1045 NET_ThrowCurrent(env, "timeout in datagram socket peek");
1033 1046 } else if (ret == JVM_IO_INTR) {
1034 1047 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1035 1048 "operation interrupted");
1036 1049 }
1037 1050 if (packetBufferLen > MAX_BUFFER_LEN) {
1038 1051 free(fullPacket);
1039 1052 }
1040 1053 return -1;
1041 1054 }
1042 1055 if (ret == 2) {
1043 1056 fduse = checkLastFD (env, this, fd, fd1);
1044 1057 }
1045 1058 checkBoth = FALSE;
1046 1059 } else if (timeout) {
1047 1060 if (prevTime == 0) {
1048 1061 prevTime = JVM_CurrentTimeMillis(env, 0);
1049 1062 }
1050 1063 ret = NET_Timeout (fduse, timeout);
1051 1064 if (ret <= 0) {
1052 1065 if (ret == 0) {
1053 1066 JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
1054 1067 "Receive timed out");
1055 1068 } else if (ret == JVM_IO_ERR) {
1056 1069 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1057 1070 "Socket closed");
1058 1071 } else if (ret == JVM_IO_INTR) {
1059 1072 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1060 1073 "operation interrupted");
1061 1074 }
1062 1075 if (packetBufferLen > MAX_BUFFER_LEN) {
1063 1076 free(fullPacket);
1064 1077 }
1065 1078 return -1;
1066 1079 }
1067 1080 }
1068 1081
1069 1082 /* receive the packet */
1070 1083 n = recvfrom(fduse, fullPacket, packetBufferLen, MSG_PEEK,
1071 1084 (struct sockaddr *)&remote_addr, &remote_addrsize);
1072 1085 port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&remote_addr));
1073 1086 if (n == JVM_IO_ERR) {
1074 1087 if (WSAGetLastError() == WSAECONNRESET) {
1075 1088 jboolean connected;
1076 1089
1077 1090 /*
1078 1091 * An icmp port unreachable - we must receive this as Windows
1079 1092 * does not reset the state of the socket until this has been
1080 1093 * received.
1081 1094 */
1082 1095 purgeOutstandingICMP(env, this, fduse);
1083 1096
1084 1097 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1085 1098 if (connected) {
1086 1099 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1087 1100 "ICMP Port Unreachable");
1088 1101
1089 1102 if (packetBufferLen > MAX_BUFFER_LEN) {
1090 1103 free(fullPacket);
1091 1104 }
1092 1105 return -1;
1093 1106 }
1094 1107
1095 1108 /*
1096 1109 * If a timeout was specified then we need to adjust it because
1097 1110 * we may have used up some of the timeout befor the icmp port
1098 1111 * unreachable arrived.
1099 1112 */
1100 1113 if (timeout) {
1101 1114 jlong newTime = JVM_CurrentTimeMillis(env, 0);
1102 1115 timeout -= (jint)(newTime - prevTime);
1103 1116 if (timeout <= 0) {
1104 1117 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1105 1118 "Receive timed out");
1106 1119 if (packetBufferLen > MAX_BUFFER_LEN) {
1107 1120 free(fullPacket);
1108 1121 }
1109 1122 return -1;
1110 1123 }
1111 1124 prevTime = newTime;
1112 1125 }
1113 1126 retry = TRUE;
1114 1127 }
1115 1128 }
1116 1129 } while (retry);
1117 1130
1118 1131 /* truncate the data if the packet's length is too small */
1119 1132 if (n > packetBufferLen) {
1120 1133 n = packetBufferLen;
1121 1134 }
1122 1135 if (n < 0) {
1123 1136 errorCode = WSAGetLastError();
1124 1137 /* check to see if it's because the buffer was too small */
1125 1138 if (errorCode == WSAEMSGSIZE) {
1126 1139 /* it is because the buffer is too small. It's UDP, it's
1127 1140 * unreliable, it's all good. discard the rest of the
1128 1141 * data..
1129 1142 */
1130 1143 n = packetBufferLen;
1131 1144 } else {
1132 1145 /* failure */
1133 1146 (*env)->SetIntField(env, packet, dp_lengthID, 0);
1134 1147 }
1135 1148 }
1136 1149 if (n == -1) {
1137 1150 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1138 1151 } else if (n == -2) {
1139 1152 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1140 1153 "operation interrupted");
1141 1154 } else if (n < 0) {
1142 1155 NET_ThrowCurrent(env, "Datagram receive failed");
1143 1156 } else {
1144 1157 jobject packetAddress;
1145 1158
1146 1159 /*
1147 1160 * Check if there is an InetAddress already associated with this
1148 1161 * packet. If so we check if it is the same source address. We
1149 1162 * can't update any existing InetAddress because it is immutable
1150 1163 */
1151 1164 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
1152 1165 if (packetAddress != NULL) {
1153 1166 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)
1154 1167 &remote_addr, packetAddress)) {
1155 1168 /* force a new InetAddress to be created */
1156 1169 packetAddress = NULL;
1157 1170 }
1158 1171 }
1159 1172 if (packetAddress == NULL) {
1160 1173 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)
1161 1174 &remote_addr, &port);
1162 1175 /* stuff the new Inetaddress in the packet */
1163 1176 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
1164 1177 }
1165 1178
1166 1179 /* populate the packet */
1167 1180 (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
1168 1181 (jbyte *)fullPacket);
1169 1182 (*env)->SetIntField(env, packet, dp_portID, port);
1170 1183 (*env)->SetIntField(env, packet, dp_lengthID, n);
1171 1184 }
1172 1185
1173 1186 /* make sure receive() picks up the right fd */
1174 1187 (*env)->SetIntField(env, this, pdsi_fduseID, fduse);
1175 1188
1176 1189 if (packetBufferLen > MAX_BUFFER_LEN) {
1177 1190 free(fullPacket);
1178 1191 }
1179 1192 return port;
1180 1193 }
1181 1194
1182 1195 /*
1183 1196 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1184 1197 * Method: receive
1185 1198 * Signature: (Ljava/net/DatagramPacket;)V
1186 1199 */
1187 1200 JNIEXPORT void JNICALL
1188 1201 Java_java_net_TwoStacksPlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
1189 1202 jobject packet) {
1190 1203
1191 1204 char BUF[MAX_BUFFER_LEN];
1192 1205 char *fullPacket;
1193 1206 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1194 1207 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1195 1208 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
1196 1209 jbyteArray packetBuffer;
1197 1210 jint packetBufferOffset, packetBufferLen;
1198 1211 int ipv6_supported = ipv6_available();
1199 1212
1200 1213 /* as a result of the changes for ipv6, peek() or peekData()
1201 1214 * must be called prior to receive() so that fduse can be set.
1202 1215 */
1203 1216 int fd, fd1, fduse, errorCode;
1204 1217
1205 1218 int n, nsockets=0;
1206 1219 SOCKETADDRESS remote_addr;
1207 1220 jint remote_addrsize=sizeof(remote_addr);
1208 1221 BOOL retry;
1209 1222 jlong prevTime = 0, selectTime=0;
1210 1223 jboolean connected;
1211 1224
1212 1225 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
1213 1226 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1214 1227 "Socket closed");
1215 1228 return;
1216 1229 }
1217 1230
1218 1231 if (!IS_NULL(fdObj)) {
1219 1232 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1220 1233 nsockets ++;
1221 1234 }
1222 1235 if (!IS_NULL(fd1Obj)) {
1223 1236 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1224 1237 nsockets ++;
1225 1238 }
1226 1239
1227 1240 if (nsockets == 2) { /* need to choose one of them */
1228 1241 /* was fduse set in peek? */
1229 1242 fduse = (*env)->GetIntField(env, this, pdsi_fduseID);
1230 1243 if (fduse == -1) {
1231 1244 /* not set in peek(), must select on both sockets */
1232 1245 int ret, t = (timeout == 0) ? -1: timeout;
1233 1246 ret = NET_Timeout2 (fd, fd1, t, &fduse);
1234 1247 if (ret == 2) {
1235 1248 fduse = checkLastFD (env, this, fd, fd1);
1236 1249 } else if (ret <= 0) {
1237 1250 if (ret == 0) {
1238 1251 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1239 1252 "Receive timed out");
1240 1253 } else if (ret == JVM_IO_ERR) {
1241 1254 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1242 1255 "Socket closed");
1243 1256 } else if (ret == JVM_IO_INTR) {
1244 1257 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1245 1258 "operation interrupted");
1246 1259 }
1247 1260 return;
1248 1261 }
1249 1262 }
1250 1263 } else if (!ipv6_supported) {
1251 1264 fduse = fd;
1252 1265 } else if (IS_NULL(fdObj)) {
1253 1266 /* ipv6 supported: and this socket bound to an IPV6 only address */
1254 1267 fduse = fd1;
1255 1268 } else {
1256 1269 /* ipv6 supported: and this socket bound to an IPV4 only address */
1257 1270 fduse = fd;
1258 1271 }
1259 1272
1260 1273 if (IS_NULL(packet)) {
1261 1274 JNU_ThrowNullPointerException(env, "packet");
1262 1275 return;
1263 1276 }
1264 1277
1265 1278 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
1266 1279
1267 1280 if (IS_NULL(packetBuffer)) {
1268 1281 JNU_ThrowNullPointerException(env, "packet buffer");
1269 1282 return;
1270 1283 }
1271 1284
1272 1285 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
1273 1286 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
1274 1287
1275 1288 if (packetBufferLen > MAX_BUFFER_LEN) {
1276 1289
1277 1290 /* When JNI-ifying the JDK's IO routines, we turned
1278 1291 * read's and write's of byte arrays of size greater
1279 1292 * than 2048 bytes into several operations of size 2048.
1280 1293 * This saves a malloc()/memcpy()/free() for big
1281 1294 * buffers. This is OK for file IO and TCP, but that
1282 1295 * strategy violates the semantics of a datagram protocol.
1283 1296 * (one big send) != (several smaller sends). So here
1284 1297 * we *must* alloc the buffer. Note it needn't be bigger
1285 1298 * than 65,536 (0xFFFF) the max size of an IP packet.
1286 1299 * anything bigger is truncated anyway.
1287 1300 */
1288 1301 fullPacket = (char *)malloc(packetBufferLen);
1289 1302 if (!fullPacket) {
1290 1303 JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
1291 1304 return;
1292 1305 }
1293 1306 } else {
1294 1307 fullPacket = &(BUF[0]);
1295 1308 }
1296 1309
1297 1310
1298 1311
1299 1312 /*
1300 1313 * If this Windows edition supports ICMP port unreachable and if we
1301 1314 * are not connected then we need to know if a timeout has been specified
1302 1315 * and if so we need to pick up the current time. These are required in
1303 1316 * order to implement the semantics of timeout, viz :-
1304 1317 * timeout set to t1 but ICMP port unreachable arrives in t2 where
1305 1318 * t2 < t1. In this case we must discard the ICMP packets and then
1306 1319 * wait for the next packet up to a maximum of t1 minus t2.
1307 1320 */
1308 1321 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1309 1322 if (supportPortUnreachable() && !connected && timeout &&!ipv6_supported) {
1310 1323 prevTime = JVM_CurrentTimeMillis(env, 0);
1311 1324 }
1312 1325
1313 1326 if (timeout && nsockets == 1) {
1314 1327 int ret;
1315 1328 ret = NET_Timeout(fduse, timeout);
1316 1329 if (ret <= 0) {
1317 1330 if (ret == 0) {
1318 1331 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1319 1332 "Receive timed out");
1320 1333 } else if (ret == JVM_IO_ERR) {
1321 1334 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1322 1335 "Socket closed");
1323 1336 } else if (ret == JVM_IO_INTR) {
1324 1337 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1325 1338 "operation interrupted");
1326 1339 }
1327 1340 if (packetBufferLen > MAX_BUFFER_LEN) {
1328 1341 free(fullPacket);
1329 1342 }
1330 1343 return;
1331 1344 }
1332 1345 }
1333 1346
1334 1347 /*
1335 1348 * Loop only if we discarding ICMP port unreachable packets
1336 1349 */
1337 1350 do {
1338 1351 retry = FALSE;
1339 1352
1340 1353 /* receive the packet */
1341 1354 n = recvfrom(fduse, fullPacket, packetBufferLen, 0,
1342 1355 (struct sockaddr *)&remote_addr, &remote_addrsize);
1343 1356
1344 1357 if (n == JVM_IO_ERR) {
1345 1358 if (WSAGetLastError() == WSAECONNRESET) {
1346 1359 /*
1347 1360 * An icmp port unreachable has been received - consume any other
1348 1361 * outstanding packets.
1349 1362 */
1350 1363 purgeOutstandingICMP(env, this, fduse);
1351 1364
1352 1365 /*
1353 1366 * If connected throw a PortUnreachableException
1354 1367 */
1355 1368
1356 1369 if (connected) {
1357 1370 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1358 1371 "ICMP Port Unreachable");
1359 1372
1360 1373 if (packetBufferLen > MAX_BUFFER_LEN) {
1361 1374 free(fullPacket);
1362 1375 }
1363 1376
1364 1377 return;
1365 1378 }
1366 1379
1367 1380 /*
1368 1381 * If a timeout was specified then we need to adjust it because
1369 1382 * we may have used up some of the timeout before the icmp port
1370 1383 * unreachable arrived.
1371 1384 */
1372 1385 if (timeout) {
1373 1386 int ret;
1374 1387 jlong newTime = JVM_CurrentTimeMillis(env, 0);
1375 1388 timeout -= (jint)(newTime - prevTime);
1376 1389 prevTime = newTime;
1377 1390
1378 1391 if (timeout <= 0) {
1379 1392 ret = 0;
1380 1393 } else {
1381 1394 ret = NET_Timeout(fduse, timeout);
1382 1395 }
1383 1396
1384 1397 if (ret <= 0) {
1385 1398 if (ret == 0) {
1386 1399 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1387 1400 "Receive timed out");
1388 1401 } else if (ret == JVM_IO_ERR) {
1389 1402 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1390 1403 "Socket closed");
1391 1404 } else if (ret == JVM_IO_INTR) {
1392 1405 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1393 1406 "operation interrupted");
1394 1407 }
1395 1408 if (packetBufferLen > MAX_BUFFER_LEN) {
1396 1409 free(fullPacket);
1397 1410 }
1398 1411 return;
1399 1412 }
1400 1413 }
1401 1414
1402 1415 /*
1403 1416 * An ICMP port unreachable was received but we are
1404 1417 * not connected so ignore it.
1405 1418 */
1406 1419 retry = TRUE;
1407 1420 }
1408 1421 }
1409 1422 } while (retry);
1410 1423
1411 1424 /* truncate the data if the packet's length is too small */
1412 1425 if (n > packetBufferLen) {
1413 1426 n = packetBufferLen;
1414 1427 }
1415 1428 if (n < 0) {
1416 1429 errorCode = WSAGetLastError();
1417 1430 /* check to see if it's because the buffer was too small */
1418 1431 if (errorCode == WSAEMSGSIZE) {
1419 1432 /* it is because the buffer is too small. It's UDP, it's
1420 1433 * unreliable, it's all good. discard the rest of the
1421 1434 * data..
1422 1435 */
1423 1436 n = packetBufferLen;
1424 1437 } else {
1425 1438 /* failure */
1426 1439 (*env)->SetIntField(env, packet, dp_lengthID, 0);
1427 1440 }
1428 1441 }
1429 1442 if (n == -1) {
1430 1443 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1431 1444 } else if (n == -2) {
1432 1445 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1433 1446 "operation interrupted");
1434 1447 } else if (n < 0) {
1435 1448 NET_ThrowCurrent(env, "Datagram receive failed");
1436 1449 } else {
1437 1450 int port;
1438 1451 jobject packetAddress;
1439 1452
1440 1453 /*
1441 1454 * Check if there is an InetAddress already associated with this
1442 1455 * packet. If so we check if it is the same source address. We
1443 1456 * can't update any existing InetAddress because it is immutable
1444 1457 */
1445 1458 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
1446 1459
1447 1460 if (packetAddress != NULL) {
1448 1461 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
1449 1462 /* force a new InetAddress to be created */
1450 1463 packetAddress = NULL;
1451 1464 }
1452 1465 }
1453 1466 if (packetAddress == NULL) {
1454 1467 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
1455 1468 /* stuff the new Inetaddress in the packet */
1456 1469 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
1457 1470 } else {
1458 1471 /* only get the new port number */
1459 1472 port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);
1460 1473 }
1461 1474 /* populate the packet */
1462 1475 (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
1463 1476 (jbyte *)fullPacket);
1464 1477 (*env)->SetIntField(env, packet, dp_portID, port);
1465 1478 (*env)->SetIntField(env, packet, dp_lengthID, n);
1466 1479 }
1467 1480 if (packetBufferLen > MAX_BUFFER_LEN) {
1468 1481 free(fullPacket);
1469 1482 }
1470 1483 }
1471 1484
1472 1485 /*
1473 1486 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1474 1487 * Method: datagramSocketCreate
1475 1488 * Signature: ()V
1476 1489 */
1477 1490 JNIEXPORT void JNICALL
1478 1491 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
1479 1492 jobject this) {
1480 1493 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1481 1494 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1482 1495
1483 1496 int fd, fd1;
1484 1497 int t = TRUE;
1485 1498 DWORD x1, x2; /* ignored result codes */
1486 1499 int ipv6_supported = ipv6_available();
1487 1500
1488 1501 int arg = -1;
1489 1502
1490 1503 if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
1491 1504 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1492 1505 return;
1493 1506 } else {
1494 1507 fd = (int) socket (AF_INET, SOCK_DGRAM, 0);
1495 1508 }
1496 1509 if (fd == JVM_IO_ERR) {
1497 1510 NET_ThrowCurrent(env, "Socket creation failed");
1498 1511 return;
1499 1512 }
1500 1513 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
1501 1514 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1502 1515 NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
↓ open down ↓ |
1012 lines elided |
↑ open up ↑ |
1503 1516
1504 1517 if (ipv6_supported) {
1505 1518 /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
1506 1519 * returns connection reset errors un connected UDP sockets (as well
1507 1520 * as connected sockets. The solution is to only enable this feature
1508 1521 * when the socket is connected
1509 1522 */
1510 1523 t = FALSE;
1511 1524 WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1512 1525 t = TRUE;
1513 - fd1 = socket (AF_INET6, SOCK_DGRAM, 0);
1526 + fd1 = (int)socket (AF_INET6, SOCK_DGRAM, 0);
1514 1527 if (fd1 == JVM_IO_ERR) {
1515 1528 NET_ThrowCurrent(env, "Socket creation failed");
1516 1529 return;
1517 1530 }
1518 1531 NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1519 1532 t = FALSE;
1520 1533 WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1521 1534 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
1522 1535 SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
1523 1536 } else {
1524 1537 /* drop the second fd */
1525 1538 (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
1526 1539 }
1527 1540 }
1528 1541
1529 1542 /*
1530 1543 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1531 1544 * Method: datagramSocketClose
1532 1545 * Signature: ()V
1533 1546 */
1534 1547 JNIEXPORT void JNICALL
1535 1548 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env,
1536 1549 jobject this) {
1537 1550 /*
1538 1551 * REMIND: PUT A LOCK AROUND THIS CODE
1539 1552 */
1540 1553 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1541 1554 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1542 1555 int ipv6_supported = ipv6_available();
1543 1556 int fd=-1, fd1=-1;
1544 1557
1545 1558 if (IS_NULL(fdObj) && (!ipv6_supported || IS_NULL(fd1Obj))) {
1546 1559 return;
1547 1560 }
1548 1561
1549 1562 if (!IS_NULL(fdObj)) {
1550 1563 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1551 1564 if (fd != -1) {
1552 1565 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
1553 1566 NET_SocketClose(fd);
1554 1567 }
1555 1568 }
1556 1569
1557 1570 if (ipv6_supported && fd1Obj != NULL) {
1558 1571 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1559 1572 if (fd1 == -1) {
1560 1573 return;
1561 1574 }
1562 1575 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
1563 1576 NET_SocketClose(fd1);
1564 1577 }
1565 1578 }
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
1566 1579
1567 1580 /*
1568 1581 * check the addresses attached to the NetworkInterface object
1569 1582 * and return the first one (of the requested family Ipv4 or Ipv6)
1570 1583 * in *iaddr
1571 1584 */
1572 1585
1573 1586 static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iaddr)
1574 1587 {
1575 1588 jobjectArray addrArray;
1576 - static jfieldID ni_addrsID=0;
1577 - static jfieldID ia_familyID=0;
1578 1589 jsize len;
1579 1590 jobject addr;
1580 1591 int i;
1581 1592
1582 - if (ni_addrsID == NULL) {
1583 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1584 - CHECK_NULL_RETURN (c, -1);
1585 - ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1586 - "[Ljava/net/InetAddress;");
1587 - CHECK_NULL_RETURN (ni_addrsID, -1);
1588 - c = (*env)->FindClass(env,"java/net/InetAddress");
1589 - CHECK_NULL_RETURN (c, -1);
1590 - ia_familyID = (*env)->GetFieldID(env, c, "family", "I");
1591 - CHECK_NULL_RETURN (ia_familyID, -1);
1592 - }
1593 -
1594 1593 addrArray = (*env)->GetObjectField(env, nif, ni_addrsID);
1595 1594 len = (*env)->GetArrayLength(env, addrArray);
1596 1595
1597 1596 /*
1598 1597 * Check that there is at least one address bound to this
1599 1598 * interface.
1600 1599 */
1601 1600 if (len < 1) {
1602 1601 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1603 1602 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1604 1603 return -1;
1605 1604 }
1606 1605 for (i=0; i<len; i++) {
1607 1606 int fam;
1608 1607 addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1609 1608 fam = (*env)->GetIntField(env, addr, ia_familyID);
1610 1609 if (fam == family) {
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
1611 1610 *iaddr = addr;
1612 1611 return 0;
1613 1612 }
1614 1613 }
1615 1614 return -1;
1616 1615 }
1617 1616
1618 1617 static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr)
1619 1618 {
1620 1619 jobject addr;
1621 - static jfieldID ia_addressID;
1622 1620
1623 1621 int ret = getInetAddrFromIf (env, IPv4, nif, &addr);
1624 1622 if (ret == -1) {
1625 1623 return -1;
1626 1624 }
1627 1625
1628 - if (ia_addressID == 0) {
1629 - jclass c = (*env)->FindClass(env,"java/net/InetAddress");
1630 - CHECK_NULL_RETURN (c, -1);
1631 - ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
1632 - CHECK_NULL_RETURN (ia_addressID, -1);
1633 - }
1634 1626 iaddr->s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
1635 1627 return 0;
1636 1628 }
1637 1629
1638 1630 /* Get the multicasting index from the interface */
1639 1631
1640 1632 static int getIndexFromIf (JNIEnv *env, jobject nif) {
1641 - static jfieldID ni_indexID;
1642 -
1643 - if (ni_indexID == NULL) {
1644 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1645 - CHECK_NULL_RETURN(c, -1);
1646 - ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1647 - CHECK_NULL_RETURN(ni_indexID, -1);
1648 - }
1649 -
1650 1633 return (*env)->GetIntField(env, nif, ni_indexID);
1651 1634 }
1652 1635
1653 1636 /*
1654 1637 * Sets the multicast interface.
1655 1638 *
1656 1639 * SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :-
1657 1640 * IPv4: set outgoing multicast interface using
1658 1641 * IPPROTO_IP/IP_MULTICAST_IF
1659 1642 *
1660 1643 * IPv6: Get the interface to which the
1661 1644 * InetAddress is bound
1662 1645 * and do same as SockOptions.IF_MULTICAST_IF2
1663 1646 *
1664 1647 * SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :-
1665 1648 * For each stack:
1666 1649 * IPv4: Obtain IP address bound to network interface
1667 1650 * (NetworkInterface.addres[0])
1668 1651 * set outgoing multicast interface using
1669 1652 * IPPROTO_IP/IP_MULTICAST_IF
1670 1653 *
1671 1654 * IPv6: Obtain NetworkInterface.index
1672 1655 * Set outgoing multicast interface using
1673 1656 * IPPROTO_IPV6/IPV6_MULTICAST_IF
1674 1657 *
1675 1658 */
1676 1659 static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
1677 1660 jint opt, jobject value)
1678 1661 {
1679 1662 int ipv6_supported = ipv6_available();
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
1680 1663
1681 1664 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1682 1665 /*
1683 1666 * value is an InetAddress.
1684 1667 * On IPv4 system use IP_MULTICAST_IF socket option
1685 1668 * On IPv6 system get the NetworkInterface that this IP
1686 1669 * address is bound to and use the IPV6_MULTICAST_IF
1687 1670 * option instead of IP_MULTICAST_IF
1688 1671 */
1689 1672 if (ipv6_supported) {
1690 - static jclass ni_class;
1691 - if (ni_class == NULL) {
1692 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1693 - CHECK_NULL(c);
1694 - ni_class = (*env)->NewGlobalRef(env, c);
1695 - CHECK_NULL(ni_class);
1696 - }
1697 -
1698 1673 value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1699 1674 if (value == NULL) {
1700 1675 if (!(*env)->ExceptionOccurred(env)) {
1701 1676 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1702 1677 "bad argument for IP_MULTICAST_IF"
1703 1678 ": address not bound to any interface");
1704 1679 }
1705 1680 return;
1706 1681 }
1707 1682 opt = java_net_SocketOptions_IP_MULTICAST_IF2;
1708 1683 } else {
1709 - static jfieldID ia_addressID;
1710 1684 struct in_addr in;
1711 1685
1712 - if (ia_addressID == NULL) {
1713 - jclass c = (*env)->FindClass(env,"java/net/InetAddress");
1714 - CHECK_NULL(c);
1715 - ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
1716 - CHECK_NULL(ia_addressID);
1717 - }
1718 -
1719 1686 in.s_addr = htonl((*env)->GetIntField(env, value, ia_addressID));
1720 1687
1721 1688 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1722 1689 (const char*)&in, sizeof(in)) < 0) {
1723 1690 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1724 1691 "Error setting socket option");
1725 1692 }
1726 1693 return;
1727 1694 }
1728 1695 }
1729 1696
1730 1697 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1731 1698 /*
1732 1699 * value is a NetworkInterface.
1733 1700 * On IPv6 system get the index of the interface and use the
1734 1701 * IPV6_MULTICAST_IF socket option
1735 1702 * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF
1736 1703 * option. For IPv6 both must be done.
1737 1704 */
1738 1705 if (ipv6_supported) {
1739 - static jfieldID ni_indexID;
1740 1706 struct in_addr in;
1741 1707 int index;
1742 1708
1743 - if (ni_indexID == NULL) {
1744 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1745 - CHECK_NULL(c);
1746 - ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1747 - CHECK_NULL(ni_indexID);
1748 - }
1749 1709 index = (*env)->GetIntField(env, value, ni_indexID);
1750 1710
1751 1711 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1752 1712 (const char*)&index, sizeof(index)) < 0) {
1753 1713 if (errno == EINVAL && index > 0) {
1754 1714 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1755 1715 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1756 1716 "address only?)");
1757 1717 } else {
1758 1718 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1759 1719 "Error setting socket option");
1760 1720 }
1761 1721 return;
1762 1722 }
1763 1723
1764 1724 /* If there are any IPv4 addresses on this interface then
1765 1725 * repeat the operation on the IPv4 fd */
1766 1726
1767 1727 if (getInet4AddrFromIf (env, value, &in) < 0) {
1768 1728 return;
1769 1729 }
1770 1730 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1771 1731 (const char*)&in, sizeof(in)) < 0) {
1772 1732 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1773 1733 "Error setting socket option");
1774 1734 }
1775 1735 return;
1776 1736 } else {
1777 1737 struct in_addr in;
1778 1738
1779 1739 if (getInet4AddrFromIf (env, value, &in) < 0) {
1780 1740 if ((*env)->ExceptionOccurred(env)) {
1781 1741 return;
1782 1742 }
1783 1743 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1784 1744 "no InetAddress instances of requested type");
1785 1745 return;
1786 1746 }
1787 1747
1788 1748 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1789 1749 (const char*)&in, sizeof(in)) < 0) {
1790 1750 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1791 1751 "Error setting socket option");
1792 1752 }
1793 1753 return;
1794 1754 }
1795 1755 }
1796 1756 }
1797 1757
1798 1758 /*
1799 1759 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1800 1760 * Method: socketSetOption
1801 1761 * Signature: (ILjava/lang/Object;)V
1802 1762 */
1803 1763 JNIEXPORT void JNICALL
1804 1764 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketSetOption(JNIEnv *env,jobject this,
1805 1765 jint opt,jobject value) {
1806 1766
1807 1767 int fd=-1, fd1=-1;
1808 1768 int levelv4, levelv6, optnamev4, optnamev6, optlen;
1809 1769 union {
1810 1770 int i;
1811 1771 char c;
1812 1772 } optval;
1813 1773 int ipv6_supported = ipv6_available();
1814 1774
1815 1775 fd = getFD(env, this);
1816 1776
1817 1777 if (ipv6_supported) {
1818 1778 fd1 = getFD1(env, this);
1819 1779 }
1820 1780 if (fd < 0 && fd1 < 0) {
1821 1781 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1822 1782 return;
1823 1783 }
1824 1784
1825 1785 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1826 1786 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1827 1787
1828 1788 setMulticastInterface(env, this, fd, fd1, opt, value);
1829 1789 return;
1830 1790 }
1831 1791
1832 1792 /*
1833 1793 * Map the Java level socket option to the platform specific
1834 1794 * level(s) and option name(s).
1835 1795 */
1836 1796 if (fd1 != -1) {
1837 1797 if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) {
1838 1798 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1839 1799 return;
1840 1800 }
1841 1801 }
1842 1802 if (fd != -1) {
1843 1803 if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) {
↓ open down ↓ |
85 lines elided |
↑ open up ↑ |
1844 1804 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1845 1805 return;
1846 1806 }
1847 1807 }
1848 1808
1849 1809 switch (opt) {
1850 1810 case java_net_SocketOptions_SO_SNDBUF :
1851 1811 case java_net_SocketOptions_SO_RCVBUF :
1852 1812 case java_net_SocketOptions_IP_TOS :
1853 1813 {
1854 - jclass cls;
1855 - jfieldID fid;
1856 -
1857 - cls = (*env)->FindClass(env, "java/lang/Integer");
1858 - CHECK_NULL(cls);
1859 - fid = (*env)->GetFieldID(env, cls, "value", "I");
1860 - CHECK_NULL(fid);
1861 -
1862 - optval.i = (*env)->GetIntField(env, value, fid);
1814 + optval.i = retrieveInteger(env, value);
1863 1815 optlen = sizeof(optval.i);
1864 1816 }
1865 1817 break;
1866 1818
1867 1819 case java_net_SocketOptions_SO_REUSEADDR:
1868 1820 case java_net_SocketOptions_SO_BROADCAST:
1869 1821 case java_net_SocketOptions_IP_MULTICAST_LOOP:
1870 1822 {
1871 - jclass cls;
1872 - jfieldID fid;
1873 - jboolean on;
1874 -
1875 - cls = (*env)->FindClass(env, "java/lang/Boolean");
1876 - CHECK_NULL(cls);
1877 - fid = (*env)->GetFieldID(env, cls, "value", "Z");
1878 - CHECK_NULL(fid);
1879 -
1880 - on = (*env)->GetBooleanField(env, value, fid);
1823 + jboolean on = retrieveBoolean(env, value);
1881 1824 optval.i = (on ? 1 : 0);
1882 1825 /*
1883 1826 * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather
1884 1827 * than enabling it.
1885 1828 */
1886 1829 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1887 1830 optval.i = !optval.i;
1888 1831 }
1889 1832 optlen = sizeof(optval.i);
1890 1833 }
1891 1834 break;
1892 1835
1893 1836 default :
1894 1837 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1895 1838 "Socket option not supported by PlainDatagramSocketImp");
1896 1839 break;
1897 1840
1898 1841 }
1899 1842
1900 1843 if (fd1 != -1) {
1901 1844 if (NET_SetSockOpt(fd1, levelv6, optnamev6, (void *)&optval, optlen) < 0) {
1902 1845 NET_ThrowCurrent(env, "setsockopt IPv6");
1903 1846 return;
1904 1847 }
1905 1848 }
1906 1849 if (fd != -1) {
1907 1850 if (NET_SetSockOpt(fd, levelv4, optnamev4, (void *)&optval, optlen) < 0) {
1908 1851 NET_ThrowCurrent(env, "setsockopt");
1909 1852 return;
1910 1853 }
1911 1854 }
1912 1855 }
1913 1856
1914 1857 /*
1915 1858 * Return the multicast interface:
1916 1859 *
1917 1860 * SocketOptions.IP_MULTICAST_IF
1918 1861 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1919 1862 * Create InetAddress
1920 1863 * IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1921 1864 * kernel but struct in_addr on 2.4 kernel
1922 1865 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
1923 1866 * obtain from impl is Linux 2.2 kernel
1924 1867 * If index == 0 return InetAddress representing
1925 1868 * anyLocalAddress.
1926 1869 * If index > 0 query NetworkInterface by index
1927 1870 * and returns addrs[0]
1928 1871 *
1929 1872 * SocketOptions.IP_MULTICAST_IF2
1930 1873 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1931 1874 * Query NetworkInterface by IP address and
1932 1875 * return the NetworkInterface that the address
1933 1876 * is bound too.
1934 1877 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1935 1878 * (except Linux .2 kernel)
↓ open down ↓ |
45 lines elided |
↑ open up ↑ |
1936 1879 * Query NetworkInterface by index and
1937 1880 * return NetworkInterface.
1938 1881 */
1939 1882 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
1940 1883 jboolean isIPV4 = !ipv6_available() || fd1 == -1;
1941 1884
1942 1885 /*
1943 1886 * IPv4 implementation
1944 1887 */
1945 1888 if (isIPV4) {
1946 - static jclass inet4_class;
1947 - static jmethodID inet4_ctrID;
1948 - static jfieldID inet4_addrID;
1949 -
1950 - static jclass ni_class;
1951 - static jmethodID ni_ctrID;
1952 - static jfieldID ni_indexID;
1953 - static jfieldID ni_addrsID;
1954 -
1955 1889 jobjectArray addrArray;
1956 1890 jobject addr;
1957 1891 jobject ni;
1958 1892
1959 1893 struct in_addr in;
1960 1894 struct in_addr *inP = ∈
1961 1895 int len = sizeof(struct in_addr);
1962 1896
1963 1897 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1964 1898 (char *)inP, &len) < 0) {
1965 1899 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1966 1900 "Error getting socket option");
1967 1901 return NULL;
1968 1902 }
1969 1903
1970 1904 /*
1971 1905 * Construct and populate an Inet4Address
1972 1906 */
1973 - if (inet4_class == NULL) {
1974 - jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1975 - CHECK_NULL_RETURN(c, NULL);
1976 - inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1977 - CHECK_NULL_RETURN(inet4_ctrID, NULL);
1978 - inet4_addrID = (*env)->GetFieldID(env, c, "address", "I");
1979 - CHECK_NULL_RETURN(inet4_addrID, NULL);
1980 - inet4_class = (*env)->NewGlobalRef(env, c);
1981 - CHECK_NULL_RETURN(inet4_class, NULL);
1982 - }
1983 - addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1907 + addr = (*env)->NewObject(env, ia4_class, ia4_ctrID, 0);
1984 1908 CHECK_NULL_RETURN(addr, NULL);
1985 1909
1986 - (*env)->SetIntField(env, addr, inet4_addrID, ntohl(in.s_addr));
1910 + (*env)->SetIntField(env, addr, ia_addressID, ntohl(in.s_addr));
1987 1911
1988 1912 /*
1989 1913 * For IP_MULTICAST_IF return InetAddress
1990 1914 */
1991 1915 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1992 1916 return addr;
1993 1917 }
1994 1918
1995 1919 /*
1996 1920 * For IP_MULTICAST_IF2 we get the NetworkInterface for
1997 1921 * this address and return it
1998 1922 */
1999 - if (ni_class == NULL) {
2000 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
2001 - CHECK_NULL_RETURN(c, NULL);
2002 - ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
2003 - CHECK_NULL_RETURN(ni_ctrID, NULL);
2004 - ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
2005 - CHECK_NULL_RETURN(ni_indexID, NULL);
2006 - ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
2007 - "[Ljava/net/InetAddress;");
2008 - CHECK_NULL_RETURN(ni_addrsID, NULL);
2009 - ni_class = (*env)->NewGlobalRef(env, c);
2010 - CHECK_NULL_RETURN(ni_class, NULL);
2011 - }
2012 1923 ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
2013 1924 if (ni) {
2014 1925 return ni;
2015 1926 }
2016 1927
2017 1928 /*
2018 1929 * The address doesn't appear to be bound at any known
2019 1930 * NetworkInterface. Therefore we construct a NetworkInterface
2020 1931 * with this address.
2021 1932 */
2022 1933 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
2023 1934 CHECK_NULL_RETURN(ni, NULL);
2024 1935
2025 1936 (*env)->SetIntField(env, ni, ni_indexID, -1);
2026 - addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
1937 + addrArray = (*env)->NewObjectArray(env, 1, ia4_class, NULL);
2027 1938 CHECK_NULL_RETURN(addrArray, NULL);
2028 1939 (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
2029 1940 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
2030 1941 return ni;
2031 1942 }
2032 1943
2033 1944
2034 1945 /*
2035 1946 * IPv6 implementation
2036 1947 */
2037 1948 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
2038 1949 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
2039 1950
2040 - static jclass ni_class;
2041 - static jmethodID ni_ctrID;
2042 - static jfieldID ni_indexID;
2043 - static jfieldID ni_addrsID;
2044 - static jclass ia_class;
2045 1951 static jmethodID ia_anyLocalAddressID;
2046 1952
2047 1953 int index;
2048 1954 int len = sizeof(index);
2049 1955
2050 1956 jobjectArray addrArray;
2051 1957 jobject addr;
2052 1958 jobject ni;
2053 1959
2054 1960 {
2055 1961 if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2056 1962 (char*)&index, &len) < 0) {
2057 1963 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
2058 1964 "Error getting socket option");
2059 1965 return NULL;
2060 1966 }
2061 1967 }
2062 1968
2063 - if (ni_class == NULL) {
2064 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
2065 - CHECK_NULL_RETURN(c, NULL);
2066 - ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
2067 - CHECK_NULL_RETURN(ni_ctrID, NULL);
2068 - ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
2069 - CHECK_NULL_RETURN(ni_indexID, NULL);
2070 - ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
2071 - "[Ljava/net/InetAddress;");
2072 - CHECK_NULL_RETURN(ni_addrsID, NULL);
2073 -
2074 - ia_class = (*env)->FindClass(env, "java/net/InetAddress");
2075 - CHECK_NULL_RETURN(ia_class, NULL);
2076 - ia_class = (*env)->NewGlobalRef(env, ia_class);
2077 - CHECK_NULL_RETURN(ia_class, NULL);
1969 + if (ia_anyLocalAddressID == NULL) {
2078 1970 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
2079 1971 ia_class,
2080 1972 "anyLocalAddress",
2081 1973 "()Ljava/net/InetAddress;");
2082 1974 CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
2083 - ni_class = (*env)->NewGlobalRef(env, c);
2084 - CHECK_NULL_RETURN(ni_class, NULL);
2085 1975 }
2086 1976
2087 1977 /*
2088 1978 * If multicast to a specific interface then return the
2089 1979 * interface (for IF2) or the any address on that interface
2090 1980 * (for IF).
2091 1981 */
2092 1982 if (index > 0) {
2093 1983 ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
2094 1984 index);
2095 1985 if (ni == NULL) {
2096 1986 char errmsg[255];
2097 1987 sprintf(errmsg,
2098 1988 "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
2099 1989 index);
2100 1990 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
2101 1991 return NULL;
2102 1992 }
2103 1993
2104 1994 /*
2105 1995 * For IP_MULTICAST_IF2 return the NetworkInterface
2106 1996 */
2107 1997 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
2108 1998 return ni;
2109 1999 }
2110 2000
2111 2001 /*
2112 2002 * For IP_MULTICAST_IF return addrs[0]
2113 2003 */
2114 2004 addrArray = (*env)->GetObjectField(env, ni, ni_addrsID);
2115 2005 if ((*env)->GetArrayLength(env, addrArray) < 1) {
2116 2006 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2117 2007 "IPV6_MULTICAST_IF returned interface without IP bindings");
2118 2008 return NULL;
2119 2009 }
2120 2010
2121 2011 addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
2122 2012 return addr;
2123 2013 }
2124 2014
2125 2015 /*
2126 2016 * Multicast to any address - return anyLocalAddress
2127 2017 * or a NetworkInterface with addrs[0] set to anyLocalAddress
2128 2018 */
2129 2019
2130 2020 addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID,
2131 2021 NULL);
2132 2022 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
2133 2023 return addr;
2134 2024 }
2135 2025
2136 2026 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
2137 2027 CHECK_NULL_RETURN(ni, NULL);
2138 2028 (*env)->SetIntField(env, ni, ni_indexID, -1);
2139 2029 addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL);
2140 2030 CHECK_NULL_RETURN(addrArray, NULL);
2141 2031 (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
2142 2032 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
2143 2033 return ni;
2144 2034 }
2145 2035 return NULL;
2146 2036 }
2147 2037 /*
2148 2038 * Returns relevant info as a jint.
2149 2039 *
2150 2040 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2151 2041 * Method: socketGetOption
2152 2042 * Signature: (I)Ljava/lang/Object;
2153 2043 */
2154 2044 JNIEXPORT jobject JNICALL
2155 2045 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this,
2156 2046 jint opt) {
2157 2047
2158 2048 int fd=-1, fd1=-1;
2159 2049 int level, optname, optlen;
2160 2050 union {
2161 2051 int i;
2162 2052 } optval;
2163 2053 int ipv6_supported = ipv6_available();
2164 2054
2165 2055 fd = getFD(env, this);
2166 2056 if (ipv6_supported) {
2167 2057 fd1 = getFD1(env, this);
2168 2058 }
2169 2059
2170 2060 if (fd < 0 && fd1 < 0) {
2171 2061 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2172 2062 "Socket closed");
2173 2063 return NULL;
2174 2064 }
2175 2065
2176 2066 /*
2177 2067 * Handle IP_MULTICAST_IF separately
2178 2068 */
2179 2069 if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
2180 2070 opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
2181 2071 return getMulticastInterface(env, this, fd, fd1, opt);
2182 2072 }
2183 2073
2184 2074 if (opt == java_net_SocketOptions_SO_BINDADDR) {
2185 2075 /* find out local IP address */
2186 2076 SOCKETADDRESS him;
2187 2077 int len = 0;
2188 2078 int port;
2189 2079 jobject iaObj;
2190 2080
2191 2081 len = sizeof (struct sockaddr_in);
2192 2082
2193 2083 if (fd == -1) {
2194 2084 fd = fd1; /* must be IPv6 only */
2195 2085 len = sizeof (struct SOCKADDR_IN6);
2196 2086 }
2197 2087
2198 2088 if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
2199 2089 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
2200 2090 "Error getting socket name");
2201 2091 return NULL;
2202 2092 }
2203 2093 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
2204 2094
2205 2095 return iaObj;
2206 2096 }
2207 2097
2208 2098 /*
2209 2099 * Map the Java level socket option to the platform specific
2210 2100 * level and option name.
2211 2101 */
2212 2102 if (NET_MapSocketOption(opt, &level, &optname)) {
2213 2103 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
2214 2104 return NULL;
2215 2105 }
2216 2106
2217 2107 if (fd == -1) {
2218 2108 if (NET_MapSocketOptionV6(opt, &level, &optname)) {
2219 2109 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
2220 2110 return NULL;
2221 2111 }
2222 2112 fd = fd1; /* must be IPv6 only */
2223 2113 }
2224 2114
2225 2115 optlen = sizeof(optval.i);
2226 2116 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
2227 2117 char errmsg[255];
2228 2118 sprintf(errmsg, "error getting socket option: %s\n", strerror(errno));
2229 2119 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
2230 2120 return NULL;
2231 2121 }
2232 2122
2233 2123 switch (opt) {
2234 2124 case java_net_SocketOptions_SO_BROADCAST:
2235 2125 case java_net_SocketOptions_SO_REUSEADDR:
2236 2126 return createBoolean(env, optval.i);
2237 2127
2238 2128 case java_net_SocketOptions_IP_MULTICAST_LOOP:
2239 2129 /* getLoopbackMode() returns true if IP_MULTICAST_LOOP is disabled */
2240 2130 return createBoolean(env, !optval.i);
2241 2131
2242 2132 case java_net_SocketOptions_SO_SNDBUF:
2243 2133 case java_net_SocketOptions_SO_RCVBUF:
2244 2134 case java_net_SocketOptions_IP_TOS:
2245 2135 return createInteger(env, optval.i);
2246 2136
2247 2137 default :
2248 2138 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2249 2139 "Socket option not supported by TwoStacksPlainDatagramSocketImpl");
2250 2140 return NULL;
2251 2141
2252 2142 }
2253 2143 }
2254 2144
2255 2145 /*
2256 2146 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2257 2147 * Method: setTimeToLive
2258 2148 * Signature: (I)V
2259 2149 */
2260 2150 JNIEXPORT void JNICALL
2261 2151 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
2262 2152 jint ttl) {
2263 2153
2264 2154 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2265 2155 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2266 2156 int fd = -1, fd1 = -1;
2267 2157 int ittl = (int)ttl;
2268 2158
2269 2159 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2270 2160 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2271 2161 "Socket closed");
2272 2162 return;
2273 2163 } else {
2274 2164 if (!IS_NULL(fdObj)) {
2275 2165 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2276 2166 }
2277 2167 if (!IS_NULL(fd1Obj)) {
2278 2168 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2279 2169 }
2280 2170 }
2281 2171
2282 2172 /* setsockopt to be correct ttl */
2283 2173 if (fd >= 0) {
2284 2174 if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
2285 2175 sizeof (ittl)) < 0) {
2286 2176 NET_ThrowCurrent(env, "set IP_MULTICAST_TTL failed");
2287 2177 }
2288 2178 }
2289 2179
2290 2180 if (fd1 >= 0) {
2291 2181 if (NET_SetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ittl,
2292 2182 sizeof(ittl)) <0) {
2293 2183 NET_ThrowCurrent(env, "set IPV6_MULTICAST_HOPS failed");
2294 2184 }
2295 2185 }
2296 2186 }
2297 2187
2298 2188 /*
2299 2189 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2300 2190 * Method: setTTL
2301 2191 * Signature: (B)V
2302 2192 */
2303 2193 JNIEXPORT void JNICALL
2304 2194 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
2305 2195 jbyte ttl) {
2306 2196 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(env, this,
2307 2197 (jint)ttl & 0xFF);
2308 2198 }
2309 2199
2310 2200 /*
2311 2201 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2312 2202 * Method: getTimeToLive
2313 2203 * Signature: ()I
2314 2204 */
2315 2205 JNIEXPORT jint JNICALL
2316 2206 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
2317 2207 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2318 2208 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2319 2209 int fd = -1, fd1 = -1;
2320 2210 int ttl = 0;
2321 2211 int len = sizeof(ttl);
2322 2212
2323 2213 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2324 2214 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2325 2215 "Socket closed");
2326 2216 return -1;
2327 2217 } else {
2328 2218 if (!IS_NULL(fdObj)) {
2329 2219 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2330 2220 }
2331 2221 if (!IS_NULL(fd1Obj)) {
2332 2222 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2333 2223 }
2334 2224 }
2335 2225
2336 2226 /* getsockopt of ttl */
2337 2227 if (fd >= 0) {
2338 2228 if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, &len) < 0) {
2339 2229 NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2340 2230 return -1;
2341 2231 }
2342 2232 return (jint)ttl;
2343 2233 }
2344 2234 if (fd1 >= 0) {
2345 2235 if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl, &len) < 0) {
2346 2236 NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2347 2237 return -1;
2348 2238 }
2349 2239 return (jint)ttl;
2350 2240 }
2351 2241 return -1;
2352 2242 }
2353 2243
2354 2244 /*
2355 2245 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2356 2246 * Method: getTTL
2357 2247 * Signature: ()B
2358 2248 */
2359 2249 JNIEXPORT jbyte JNICALL
2360 2250 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {
2361 2251 int result = Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(env, this);
2362 2252
2363 2253 return (jbyte)result;
2364 2254 }
2365 2255
2366 2256 /* join/leave the named group on the named interface, or if no interface specified
2367 2257 * then the interface set with setInterfac(), or the default interface otherwise */
2368 2258
2369 2259 static void mcast_join_leave(JNIEnv *env, jobject this,
2370 2260 jobject iaObj, jobject niObj,
2371 2261 jboolean join)
2372 2262 {
2373 2263 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2374 2264 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2375 2265 jint fd = -1, fd1 = -1;
2376 2266
2377 2267 SOCKETADDRESS name;
2378 2268 struct ip_mreq mname;
2379 2269 struct ipv6_mreq mname6;
2380 2270
2381 2271 struct in_addr in;
2382 2272 DWORD ifindex;
2383 2273
2384 2274 int len, family;
2385 2275 int ipv6_supported = ipv6_available();
2386 2276 int cmd ;
2387 2277
2388 2278 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2389 2279 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2390 2280 "Socket closed");
2391 2281 return;
2392 2282 }
2393 2283 if (!IS_NULL(fdObj)) {
2394 2284 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2395 2285 }
2396 2286 if (ipv6_supported && !IS_NULL(fd1Obj)) {
2397 2287 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2398 2288 }
2399 2289
2400 2290 if (IS_NULL(iaObj)) {
2401 2291 JNU_ThrowNullPointerException(env, "address");
2402 2292 return;
2403 2293 }
2404 2294
2405 2295 if (NET_InetAddressToSockaddr(env, iaObj, 0, (struct sockaddr *)&name, &len, JNI_FALSE) != 0) {
2406 2296 return;
2407 2297 }
2408 2298
2409 2299 /* Set the multicast group address in the ip_mreq field
2410 2300 * eventually this check should be done by the security manager
2411 2301 */
2412 2302 family = name.him.sa_family;
2413 2303
2414 2304 if (family == AF_INET) {
2415 2305 int address = name.him4.sin_addr.s_addr;
2416 2306 if (!IN_MULTICAST(ntohl(address))) {
2417 2307 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in multicast");
2418 2308 return;
2419 2309 }
2420 2310 mname.imr_multiaddr.s_addr = address;
2421 2311 if (fd < 0) {
2422 2312 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv4 group on an IPv6 only socket");
2423 2313 return;
2424 2314 }
2425 2315 if (IS_NULL(niObj)) {
2426 2316 len = sizeof (in);
2427 2317 if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2428 2318 (char *)&in, &len) < 0) {
2429 2319 NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed");
2430 2320 return;
2431 2321 }
2432 2322 mname.imr_interface.s_addr = in.s_addr;
2433 2323 } else {
2434 2324 if (getInet4AddrFromIf (env, niObj, &mname.imr_interface) != 0) {
2435 2325 NET_ThrowCurrent(env, "no Inet4Address associated with interface");
2436 2326 return;
2437 2327 }
2438 2328 }
2439 2329
2440 2330 cmd = join ? IP_ADD_MEMBERSHIP: IP_DROP_MEMBERSHIP;
2441 2331
2442 2332 /* Join the multicast group */
2443 2333 if (NET_SetSockOpt(fd, IPPROTO_IP, cmd, (char *) &mname, sizeof (mname)) < 0) {
2444 2334 if (WSAGetLastError() == WSAENOBUFS) {
2445 2335 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2446 2336 "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2447 2337 } else {
2448 2338 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2449 2339 }
2450 2340 }
2451 2341 } else /* AF_INET6 */ {
2452 2342 if (ipv6_supported) {
2453 2343 struct in6_addr *address;
2454 2344 address = &name.him6.sin6_addr;
2455 2345 if (!IN6_IS_ADDR_MULTICAST(address)) {
2456 2346 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in6 multicast");
2457 2347 return;
2458 2348 }
2459 2349 mname6.ipv6mr_multiaddr = *address;
2460 2350 } else {
2461 2351 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "IPv6 not supported");
2462 2352 return;
2463 2353 }
2464 2354 if (fd1 < 0) {
2465 2355 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv6 group on a IPv4 socket");
2466 2356 return;
2467 2357 }
2468 2358 if (IS_NULL(niObj)) {
2469 2359 len = sizeof (ifindex);
2470 2360 if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, &len) < 0) {
2471 2361 NET_ThrowCurrent(env, "get IPV6_MULTICAST_IF failed");
2472 2362 return;
2473 2363 }
2474 2364 } else {
2475 2365 ifindex = getIndexFromIf (env, niObj);
2476 2366 if (ifindex == -1) {
2477 2367 NET_ThrowCurrent(env, "get ifindex failed");
2478 2368 return;
2479 2369 }
2480 2370 }
2481 2371 mname6.ipv6mr_interface = ifindex;
2482 2372 cmd = join ? IPV6_ADD_MEMBERSHIP: IPV6_DROP_MEMBERSHIP;
2483 2373
2484 2374 /* Join the multicast group */
2485 2375 if (NET_SetSockOpt(fd1, IPPROTO_IPV6, cmd, (char *) &mname6, sizeof (mname6)) < 0) {
2486 2376 if (WSAGetLastError() == WSAENOBUFS) {
2487 2377 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2488 2378 "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2489 2379 } else {
2490 2380 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2491 2381 }
2492 2382 }
2493 2383 }
2494 2384
2495 2385 return;
2496 2386 }
2497 2387
2498 2388 /*
2499 2389 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2500 2390 * Method: join
2501 2391 * Signature: (Ljava/net/InetAddress;)V
2502 2392 */
2503 2393 JNIEXPORT void JNICALL
2504 2394 Java_java_net_TwoStacksPlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
2505 2395 jobject iaObj, jobject niObj)
2506 2396 {
2507 2397 mcast_join_leave (env, this, iaObj, niObj, JNI_TRUE);
2508 2398 }
2509 2399
2510 2400 /*
2511 2401 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2512 2402 * Method: leave
2513 2403 * Signature: (Ljava/net/InetAddress;)V
2514 2404 */
2515 2405 JNIEXPORT void JNICALL
2516 2406 Java_java_net_TwoStacksPlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
2517 2407 jobject iaObj, jobject niObj)
2518 2408 {
2519 2409 mcast_join_leave (env, this, iaObj, niObj, JNI_FALSE);
2520 2410 }
↓ open down ↓ |
426 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX