Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/solaris/native/java/net/PlainDatagramSocketImpl.c
+++ new/src/solaris/native/java/net/PlainDatagramSocketImpl.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 <errno.h>
27 27 #include <netinet/in.h>
28 28 #include <stdlib.h>
29 29 #include <string.h>
30 30 #include <sys/types.h>
31 31 #include <sys/socket.h>
32 32
33 33 #ifdef __solaris__
34 34 #include <fcntl.h>
35 35 #endif
36 36 #ifdef __linux__
37 37 #include <linux/unistd.h>
38 38 #include <linux/sysctl.h>
39 39 #include <sys/utsname.h>
40 40 #include <netinet/ip.h>
41 41
42 42 #define IPV6_MULTICAST_IF 17
43 43 #ifndef SO_BSDCOMPAT
44 44 #define SO_BSDCOMPAT 14
45 45 #endif
46 46 #endif
47 47
48 48 #ifndef IPTOS_TOS_MASK
49 49 #define IPTOS_TOS_MASK 0x1e
50 50 #endif
51 51 #ifndef IPTOS_PREC_MASK
52 52 #define IPTOS_PREC_MASK 0xe0
53 53 #endif
54 54
55 55 #include "jvm.h"
56 56 #include "jni_util.h"
57 57 #include "net_util.h"
58 58
59 59 #include "java_net_SocketOptions.h"
60 60 #include "java_net_PlainDatagramSocketImpl.h"
61 61 #include "java_net_NetworkInterface.h"
62 62 /************************************************************************
63 63 * PlainDatagramSocketImpl
64 64 */
65 65
66 66 static jfieldID IO_fd_fdID;
67 67
68 68 static jfieldID pdsi_fdID;
69 69 static jfieldID pdsi_timeoutID;
70 70 static jfieldID pdsi_trafficClassID;
71 71 static jfieldID pdsi_localPortID;
72 72 static jfieldID pdsi_connected;
73 73 static jfieldID pdsi_connectedAddress;
74 74 static jfieldID pdsi_connectedPort;
75 75
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
76 76 #ifdef __linux__
77 77 static jboolean isOldKernel;
78 78 #endif
79 79
80 80 #if defined(__linux__) && defined(AF_INET6)
81 81 static jfieldID pdsi_multicastInterfaceID;
82 82 static jfieldID pdsi_loopbackID;
83 83 static jfieldID pdsi_ttlID;
84 84 #endif
85 85
86 -/*
87 - * Returns a java.lang.Integer based on 'i'
88 - */
89 -static jobject createInteger(JNIEnv *env, int i) {
90 - static jclass i_class;
91 - static jmethodID i_ctrID;
86 +static jclass i_class;
87 +static jmethodID i_ctrID;
88 +static jfieldID i_valueID;
92 89
90 +int initIntegerIDs(JNIEnv* env) {
93 91 if (i_class == NULL) {
94 92 jclass c = (*env)->FindClass(env, "java/lang/Integer");
95 93 CHECK_NULL_RETURN(c, NULL);
96 94 i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
97 95 CHECK_NULL_RETURN(i_ctrID, NULL);
96 + i_valueID = (*env)->GetFieldID(env, c, "value", "I");
97 + CHECK_NULL_RETURN(i_valueID, NULL);
98 98 i_class = (*env)->NewGlobalRef(env, c);
99 99 CHECK_NULL_RETURN(i_class, NULL);
100 100 }
101 + return 1;
102 +}
101 103
104 +/* Returns a java.lang.Integer based on 'i' */
105 +static jobject createInteger(JNIEnv *env, int i) {
106 + CHECK_NULL_RETURN(initIntegerIDs(env), NULL);
102 107 return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
103 108 }
104 109
105 -/*
106 - * Returns a java.lang.Boolean based on 'b'
107 - */
108 -static jobject createBoolean(JNIEnv *env, int b) {
109 - static jclass b_class;
110 - static jmethodID b_ctrID;
110 +/* Returns a jint based on the given java.lang.Integer */
111 +static jint retrieveInteger(JNIEnv *env, jobject i) {
112 + CHECK_NULL_RETURN(initIntegerIDs(env), NULL);
113 + return (*env)->GetIntField(env, i, i_valueID);
114 +}
111 115
116 +static jclass b_class;
117 +static jmethodID b_ctrID;
118 +static jfieldID b_valueID;
119 +
120 +int initBooleanIDs(JNIEnv* env) {
112 121 if (b_class == NULL) {
113 122 jclass c = (*env)->FindClass(env, "java/lang/Boolean");
114 123 CHECK_NULL_RETURN(c, NULL);
115 124 b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
116 125 CHECK_NULL_RETURN(b_ctrID, NULL);
126 + b_valueID = (*env)->GetFieldID(env, c, "value", "Z");
127 + CHECK_NULL_RETURN(b_valueID, NULL);
117 128 b_class = (*env)->NewGlobalRef(env, c);
118 129 CHECK_NULL_RETURN(b_class, NULL);
119 130 }
131 + return 1;
132 +}
120 133
134 +/* Returns a java.lang.Boolean based on 'b' */
135 +static jobject createBoolean(JNIEnv *env, int b) {
136 + CHECK_NULL_RETURN(initBooleanIDs(env), NULL);
121 137 return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
122 138 }
123 139
140 +/* Returns a jboolean based on the given java.lang.Boolean */
141 +static jboolean retrieveBoolean(JNIEnv *env, jobject b) {
142 + CHECK_NULL_RETURN(initBooleanIDs(env), NULL);
143 + return (*env)->GetBooleanField(env, b, b_valueID);
144 +}
124 145
125 146 /*
126 147 * Returns the fd for a PlainDatagramSocketImpl or -1
127 148 * if closed.
128 149 */
129 150 static int getFD(JNIEnv *env, jobject this) {
130 151 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
131 152 if (fdObj == NULL) {
132 153 return -1;
133 154 }
134 155 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
135 156 }
136 157
137 158
138 159 /*
139 160 * Class: java_net_PlainDatagramSocketImpl
140 161 * Method: init
141 162 * Signature: ()V
142 163 */
143 164 JNIEXPORT void JNICALL
144 165 Java_java_net_PlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
145 166
146 167 #ifdef __linux__
147 168 struct utsname sysinfo;
148 169 #endif
149 170 pdsi_fdID = (*env)->GetFieldID(env, cls, "fd",
150 171 "Ljava/io/FileDescriptor;");
151 172 CHECK_NULL(pdsi_fdID);
152 173 pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
153 174 CHECK_NULL(pdsi_timeoutID);
154 175 pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
155 176 CHECK_NULL(pdsi_trafficClassID);
156 177 pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I");
157 178 CHECK_NULL(pdsi_localPortID);
158 179 pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z");
159 180 CHECK_NULL(pdsi_connected);
160 181 pdsi_connectedAddress = (*env)->GetFieldID(env, cls, "connectedAddress",
161 182 "Ljava/net/InetAddress;");
162 183 CHECK_NULL(pdsi_connectedAddress);
163 184 pdsi_connectedPort = (*env)->GetFieldID(env, cls, "connectedPort", "I");
164 185 CHECK_NULL(pdsi_connectedPort);
165 186
166 187 IO_fd_fdID = NET_GetFileDescriptorID(env);
167 188 CHECK_NULL(IO_fd_fdID);
168 189
169 190 Java_java_net_InetAddress_init(env, 0);
170 191 Java_java_net_Inet4Address_init(env, 0);
171 192 Java_java_net_Inet6Address_init(env, 0);
172 193 Java_java_net_NetworkInterface_init(env, 0);
173 194
174 195 #ifdef __linux__
175 196 /*
176 197 * We need to determine if this is a 2.2 kernel.
177 198 */
178 199 if (uname(&sysinfo) == 0) {
179 200 sysinfo.release[3] = '\0';
180 201 isOldKernel = (strcmp(sysinfo.release, "2.2") == 0);
181 202 } else {
182 203 /*
183 204 * uname failed - move to plan B and examine /proc/version
184 205 * If this fails assume that /proc has changed and that
185 206 * this must be new /proc format and hence new kernel.
186 207 */
187 208 FILE *fP;
188 209 isOldKernel = JNI_FALSE;
189 210 if ((fP = fopen("/proc/version", "r")) != NULL) {
190 211 char ver[25];
191 212 if (fgets(ver, sizeof(ver), fP) != NULL) {
192 213 isOldKernel = (strstr(ver, "2.2.") != NULL);
193 214 }
194 215 fclose(fP);
195 216 }
196 217 }
197 218
198 219 #ifdef AF_INET6
199 220 pdsi_multicastInterfaceID = (*env)->GetFieldID(env, cls, "multicastInterface", "I");
200 221 CHECK_NULL(pdsi_multicastInterfaceID);
201 222 pdsi_loopbackID = (*env)->GetFieldID(env, cls, "loopbackMode", "Z");
202 223 CHECK_NULL(pdsi_loopbackID);
203 224 pdsi_ttlID = (*env)->GetFieldID(env, cls, "ttl", "I");
204 225 CHECK_NULL(pdsi_ttlID);
205 226 #endif
206 227
207 228 #endif
208 229
209 230 }
210 231
211 232 /*
212 233 * Class: java_net_PlainDatagramSocketImpl
213 234 * Method: bind
214 235 * Signature: (ILjava/net/InetAddress;)V
215 236 */
216 237 JNIEXPORT void JNICALL
217 238 Java_java_net_PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
218 239 jint localport, jobject iaObj) {
219 240 /* fdObj is the FileDescriptor field on this */
220 241 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
221 242 /* fd is an int field on fdObj */
222 243 int fd;
223 244 int len = 0;
224 245 SOCKADDR him;
225 246
226 247 if (IS_NULL(fdObj)) {
227 248 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
228 249 "Socket closed");
229 250 return;
230 251 } else {
231 252 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
232 253 }
233 254
234 255 if (IS_NULL(iaObj)) {
235 256 JNU_ThrowNullPointerException(env, "iaObj is null.");
236 257 return;
237 258 }
238 259
239 260 /* bind */
240 261 if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
241 262 return;
242 263 }
243 264
244 265 if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {
245 266 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
246 267 errno == EPERM || errno == EACCES) {
247 268 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
248 269 "Bind failed");
249 270 } else {
250 271 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
251 272 "Bind failed");
252 273 }
253 274 return;
254 275 }
255 276
256 277 /* intialize the local port */
257 278 if (localport == 0) {
258 279 /* Now that we're a connected socket, let's extract the port number
259 280 * that the system chose for us and store it in the Socket object.
260 281 */
261 282 if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
262 283 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
263 284 "Error getting socket name");
264 285 return;
265 286 }
266 287
267 288 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
268 289
269 290 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
270 291 } else {
271 292 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
272 293 }
273 294 }
274 295
275 296 /*
276 297 * Class: java_net_PlainDatagramSocketImpl
277 298 * Method: connect0
278 299 * Signature: (Ljava/net/InetAddress;I)V
279 300 */
280 301 JNIEXPORT void JNICALL
281 302 Java_java_net_PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
282 303 jobject address, jint port) {
283 304 /* The object's field */
284 305 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
285 306 /* The fdObj'fd */
286 307 jint fd;
287 308 /* The packetAddress address, family and port */
288 309 SOCKADDR rmtaddr;
289 310 int len = 0;
290 311
291 312 if (IS_NULL(fdObj)) {
292 313 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
293 314 "Socket closed");
294 315 return;
295 316 }
296 317 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
297 318
298 319 if (IS_NULL(address)) {
299 320 JNU_ThrowNullPointerException(env, "address");
300 321 return;
301 322 }
302 323
303 324 if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
304 325 return;
305 326 }
306 327
307 328 #ifdef __linux__
308 329 if (isOldKernel) {
309 330 int t = 0;
310 331 setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, (char*) &t, sizeof(int));
311 332 } else
312 333 #endif
313 334 {
314 335 if (JVM_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
315 336 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
316 337 "Connect failed");
317 338 return;
318 339 }
319 340 }
320 341 }
321 342
322 343 /*
323 344 * Class: java_net_PlainDatagramSocketImpl
324 345 * Method: disconnect0
325 346 * Signature: ()V
326 347 */
327 348 JNIEXPORT void JNICALL
328 349 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
329 350 /* The object's field */
330 351 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
331 352 /* The fdObj'fd */
332 353 jint fd;
333 354
334 355 #ifdef __linux__
335 356 SOCKADDR addr;
336 357 int len;
337 358 #endif
338 359
339 360 if (IS_NULL(fdObj)) {
340 361 return;
341 362 }
342 363 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
343 364
344 365 #ifdef __linux__
345 366 if (isOldKernel) {
346 367 int t = 1;
347 368 setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, (char*) &t, sizeof(int));
348 369 } else {
349 370 memset(&addr, 0, sizeof(addr));
350 371 #ifdef AF_INET6
351 372 if (ipv6_available()) {
352 373 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&addr;
353 374 him6->sin6_family = AF_UNSPEC;
354 375 len = sizeof(struct sockaddr_in6);
355 376 } else
356 377 #endif
357 378 {
358 379 struct sockaddr_in *him4 = (struct sockaddr_in*)&addr;
359 380 him4->sin_family = AF_UNSPEC;
360 381 len = sizeof(struct sockaddr_in);
361 382 }
362 383 JVM_Connect(fd, (struct sockaddr *)&addr, len);
363 384
364 385 // After disconnecting a UDP socket, Linux kernel will set
365 386 // local port to zero if the port number comes from implicit
366 387 // bind. Successive send/recv on the same socket will fail.
367 388 // So bind again with former port number here.
368 389 int localPort = 0;
369 390 if (JVM_GetSockName(fd, (struct sockaddr *)&addr, &len) == -1) {
370 391 return;
371 392 }
372 393 localPort = NET_GetPortFromSockaddr((struct sockaddr *)&addr);
373 394 if (localPort == 0) {
374 395 localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
375 396 #ifdef AF_INET6
376 397 if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
377 398 ((struct sockaddr_in6*)&addr)->sin6_port = htons(localPort);
378 399 } else
379 400 #endif /* AF_INET6 */
380 401 {
381 402 ((struct sockaddr_in*)&addr)->sin_port = htons(localPort);
382 403 }
383 404 NET_Bind(fd, (struct sockaddr *)&addr, len);
384 405 }
385 406 }
386 407 #else
387 408 JVM_Connect(fd, 0, 0);
388 409 #endif
389 410 }
390 411
391 412 /*
392 413 * Class: java_net_PlainDatagramSocketImpl
393 414 * Method: send
394 415 * Signature: (Ljava/net/DatagramPacket;)V
395 416 */
396 417 JNIEXPORT void JNICALL
397 418 Java_java_net_PlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
398 419 jobject packet) {
399 420
400 421 char BUF[MAX_BUFFER_LEN];
401 422 char *fullPacket = NULL;
402 423 int ret, mallocedPacket = JNI_FALSE;
403 424 /* The object's field */
404 425 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
405 426 jint trafficClass = (*env)->GetIntField(env, this, pdsi_trafficClassID);
406 427
407 428 jbyteArray packetBuffer;
408 429 jobject packetAddress;
409 430 jint packetBufferOffset, packetBufferLen, packetPort;
410 431 jboolean connected;
411 432
412 433 /* The fdObj'fd */
413 434 jint fd;
414 435
415 436 SOCKADDR rmtaddr, *rmtaddrP=&rmtaddr;
416 437 int len;
417 438
418 439 if (IS_NULL(fdObj)) {
419 440 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
420 441 "Socket closed");
421 442 return;
422 443 }
423 444 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
424 445
425 446 if (IS_NULL(packet)) {
426 447 JNU_ThrowNullPointerException(env, "packet");
427 448 return;
428 449 }
429 450
430 451 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
431 452
432 453 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
433 454 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
434 455 if (IS_NULL(packetBuffer) || IS_NULL(packetAddress)) {
435 456 JNU_ThrowNullPointerException(env, "null buffer || null address");
436 457 return;
437 458 }
438 459
439 460 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
440 461 packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
441 462
442 463 #ifdef __linux__
443 464 if (connected && !isOldKernel) {
444 465 #else
445 466 if (connected) {
446 467 #endif
447 468 /* arg to NET_Sendto () null in this case */
448 469 len = 0;
449 470 rmtaddrP = 0;
450 471 } else {
451 472 packetPort = (*env)->GetIntField(env, packet, dp_portID);
452 473 if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
453 474 return;
454 475 }
455 476 }
456 477
457 478 if (packetBufferLen > MAX_BUFFER_LEN) {
458 479 /* When JNI-ifying the JDK's IO routines, we turned
459 480 * read's and write's of byte arrays of size greater
460 481 * than 2048 bytes into several operations of size 2048.
461 482 * This saves a malloc()/memcpy()/free() for big
462 483 * buffers. This is OK for file IO and TCP, but that
463 484 * strategy violates the semantics of a datagram protocol.
464 485 * (one big send) != (several smaller sends). So here
465 486 * we *must* alloc the buffer. Note it needn't be bigger
466 487 * than 65,536 (0xFFFF) the max size of an IP packet.
467 488 * Anything bigger should be truncated anyway.
468 489 *
469 490 * We may want to use a smarter allocation scheme at some
470 491 * point.
471 492 */
472 493 if (packetBufferLen > MAX_PACKET_LEN) {
473 494 packetBufferLen = MAX_PACKET_LEN;
474 495 }
475 496 fullPacket = (char *)malloc(packetBufferLen);
476 497
477 498 if (!fullPacket) {
478 499 JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
479 500 return;
480 501 } else {
481 502 mallocedPacket = JNI_TRUE;
482 503 }
483 504 } else {
484 505 fullPacket = &(BUF[0]);
485 506 }
486 507
487 508 (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
488 509 (jbyte *)fullPacket);
489 510 #ifdef AF_INET6
490 511 if (trafficClass != 0 && ipv6_available()) {
491 512 NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
492 513 }
493 514 #endif /* AF_INET6 */
494 515
495 516
496 517 /*
497 518 * Send the datagram.
498 519 *
499 520 * If we are connected it's possible that sendto will return
500 521 * ECONNREFUSED indicating that an ICMP port unreachable has
501 522 * received.
502 523 */
503 524 ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
504 525 (struct sockaddr *)rmtaddrP, len);
505 526
506 527 if (ret < 0) {
507 528 switch (ret) {
508 529 case JVM_IO_ERR :
509 530 if (errno == ECONNREFUSED) {
510 531 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
511 532 "ICMP Port Unreachable");
512 533 } else {
513 534 NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
514 535 }
515 536 break;
516 537
517 538 case JVM_IO_INTR:
518 539 JNU_ThrowByName(env, "java/io/InterruptedIOException",
519 540 "operation interrupted");
520 541 break;
521 542 }
522 543 }
523 544
524 545 if (mallocedPacket) {
525 546 free(fullPacket);
526 547 }
527 548 return;
528 549 }
529 550
530 551 /*
531 552 * Class: java_net_PlainDatagramSocketImpl
532 553 * Method: peek
533 554 * Signature: (Ljava/net/InetAddress;)I
534 555 */
535 556 JNIEXPORT jint JNICALL
536 557 Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
537 558 jobject addressObj) {
538 559
539 560 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
540 561 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
541 562 jint fd;
542 563 ssize_t n;
543 564 SOCKADDR remote_addr;
544 565 int len;
545 566 char buf[1];
546 567 jint family;
547 568 jobject iaObj;
548 569 int port;
549 570 if (IS_NULL(fdObj)) {
550 571 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
551 572 return -1;
552 573 } else {
553 574 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
554 575 }
555 576 if (IS_NULL(addressObj)) {
556 577 JNU_ThrowNullPointerException(env, "Null address in peek()");
557 578 }
558 579 if (timeout) {
559 580 int ret = NET_Timeout(fd, timeout);
560 581 if (ret == 0) {
561 582 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
562 583 "Peek timed out");
563 584 return ret;
564 585 } else if (ret == JVM_IO_ERR) {
565 586 if (errno == EBADF) {
566 587 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
567 588 } else {
568 589 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
569 590 }
570 591 return ret;
571 592 } else if (ret == JVM_IO_INTR) {
572 593 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
573 594 "operation interrupted");
574 595 return ret; /* WARNING: SHOULD WE REALLY RETURN -2??? */
575 596 }
576 597 }
577 598
578 599 len = SOCKADDR_LEN;
579 600 n = NET_RecvFrom(fd, buf, 1, MSG_PEEK,
580 601 (struct sockaddr *)&remote_addr, &len);
581 602
582 603 if (n == JVM_IO_ERR) {
583 604
584 605 #ifdef __solaris__
585 606 if (errno == ECONNREFUSED) {
586 607 int orig_errno = errno;
587 608 (void) recv(fd, buf, 1, 0);
588 609 errno = orig_errno;
589 610 }
590 611 #endif
591 612 if (errno == ECONNREFUSED) {
592 613 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
593 614 "ICMP Port Unreachable");
594 615 } else {
595 616 if (errno == EBADF) {
596 617 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
597 618 } else {
598 619 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
599 620 }
600 621 }
601 622 return 0;
602 623 } else if (n == JVM_IO_INTR) {
603 624 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
604 625 return 0;
605 626 }
606 627
607 628 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
608 629 #ifdef AF_INET6
609 630 family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4?
610 631 AF_INET : AF_INET6;
611 632 #else
612 633 family = AF_INET;
613 634 #endif
614 635 if (family == AF_INET) { /* this api can't handle IPV6 addresses */
615 636 int address = (*env)->GetIntField(env, iaObj, ia_addressID);
616 637 (*env)->SetIntField(env, addressObj, ia_addressID, address);
617 638 }
618 639 return port;
619 640 }
620 641
621 642 JNIEXPORT jint JNICALL
622 643 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
623 644 jobject packet) {
624 645
625 646 char BUF[MAX_BUFFER_LEN];
626 647 char *fullPacket = NULL;
627 648 int mallocedPacket = JNI_FALSE;
628 649 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
629 650 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
630 651
631 652 jbyteArray packetBuffer;
632 653 jint packetBufferOffset, packetBufferLen;
633 654
634 655 int fd;
635 656
636 657 int n;
637 658 SOCKADDR remote_addr;
638 659 int len;
639 660 int port;
640 661
641 662 if (IS_NULL(fdObj)) {
642 663 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
643 664 "Socket closed");
644 665 return -1;
645 666 }
646 667
647 668 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
648 669
649 670 if (IS_NULL(packet)) {
650 671 JNU_ThrowNullPointerException(env, "packet");
651 672 return -1;
652 673 }
653 674
654 675 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
655 676 if (IS_NULL(packetBuffer)) {
656 677 JNU_ThrowNullPointerException(env, "packet buffer");
657 678 return -1;
658 679 }
659 680 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
660 681 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
661 682 if (timeout) {
662 683 int ret = NET_Timeout(fd, timeout);
663 684 if (ret == 0) {
664 685 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
665 686 "Receive timed out");
666 687 return -1;
667 688 } else if (ret == JVM_IO_ERR) {
668 689 #ifdef __linux__
669 690 if (errno == EBADF) {
670 691 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
671 692 } else {
672 693 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
673 694 }
674 695 #else
675 696 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
676 697 #endif
677 698 return -1;
678 699 } else if (ret == JVM_IO_INTR) {
679 700 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
680 701 "operation interrupted");
681 702 return -1;
682 703 }
683 704 }
684 705
685 706 if (packetBufferLen > MAX_BUFFER_LEN) {
686 707
687 708 /* When JNI-ifying the JDK's IO routines, we turned
688 709 * read's and write's of byte arrays of size greater
689 710 * than 2048 bytes into several operations of size 2048.
690 711 * This saves a malloc()/memcpy()/free() for big
691 712 * buffers. This is OK for file IO and TCP, but that
692 713 * strategy violates the semantics of a datagram protocol.
693 714 * (one big send) != (several smaller sends). So here
694 715 * we *must* alloc the buffer. Note it needn't be bigger
695 716 * than 65,536 (0xFFFF) the max size of an IP packet.
696 717 * anything bigger is truncated anyway.
697 718 *
698 719 * We may want to use a smarter allocation scheme at some
699 720 * point.
700 721 */
701 722 if (packetBufferLen > MAX_PACKET_LEN) {
702 723 packetBufferLen = MAX_PACKET_LEN;
703 724 }
704 725 fullPacket = (char *)malloc(packetBufferLen);
705 726
706 727 if (!fullPacket) {
707 728 JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
708 729 return -1;
709 730 } else {
710 731 mallocedPacket = JNI_TRUE;
711 732 }
712 733 } else {
713 734 fullPacket = &(BUF[0]);
714 735 }
715 736
716 737 len = SOCKADDR_LEN;
717 738 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
718 739 (struct sockaddr *)&remote_addr, &len);
719 740 /* truncate the data if the packet's length is too small */
720 741 if (n > packetBufferLen) {
721 742 n = packetBufferLen;
722 743 }
723 744 if (n == JVM_IO_ERR) {
724 745
725 746 #ifdef __solaris__
726 747 if (errno == ECONNREFUSED) {
727 748 int orig_errno = errno;
728 749 (void) recv(fd, fullPacket, 1, 0);
729 750 errno = orig_errno;
730 751 }
731 752 #endif
732 753 (*env)->SetIntField(env, packet, dp_offsetID, 0);
733 754 (*env)->SetIntField(env, packet, dp_lengthID, 0);
734 755 if (errno == ECONNREFUSED) {
735 756 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
736 757 "ICMP Port Unreachable");
737 758 } else {
738 759 if (errno == EBADF) {
739 760 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
740 761 } else {
741 762 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
742 763 }
743 764 }
744 765 } else if (n == JVM_IO_INTR) {
745 766 (*env)->SetIntField(env, packet, dp_offsetID, 0);
746 767 (*env)->SetIntField(env, packet, dp_lengthID, 0);
747 768 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
748 769 "operation interrupted");
749 770 } else {
750 771 /*
751 772 * success - fill in received address...
752 773 *
753 774 * REMIND: Fill in an int on the packet, and create inetadd
754 775 * object in Java, as a performance improvement. Also
755 776 * construct the inetadd object lazily.
756 777 */
757 778
758 779 jobject packetAddress;
759 780
760 781 /*
761 782 * Check if there is an InetAddress already associated with this
762 783 * packet. If so we check if it is the same source address. We
763 784 * can't update any existing InetAddress because it is immutable
764 785 */
765 786 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
766 787 if (packetAddress != NULL) {
767 788 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
768 789 /* force a new InetAddress to be created */
769 790 packetAddress = NULL;
770 791 }
771 792 }
772 793 if (packetAddress == NULL) {
773 794 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
774 795 /* stuff the new Inetaddress in the packet */
775 796 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
776 797 } else {
777 798 /* only get the new port number */
778 799 port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);
779 800 }
780 801 /* and fill in the data, remote address/port and such */
781 802 (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
782 803 (jbyte *)fullPacket);
783 804 (*env)->SetIntField(env, packet, dp_portID, port);
784 805 (*env)->SetIntField(env, packet, dp_lengthID, n);
785 806 }
786 807
787 808 if (mallocedPacket) {
788 809 free(fullPacket);
789 810 }
790 811 return port;
791 812 }
792 813
793 814 /*
794 815 * Class: java_net_PlainDatagramSocketImpl
795 816 * Method: receive
796 817 * Signature: (Ljava/net/DatagramPacket;)V
797 818 */
798 819 JNIEXPORT void JNICALL
799 820 Java_java_net_PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
800 821 jobject packet) {
801 822
802 823 char BUF[MAX_BUFFER_LEN];
803 824 char *fullPacket = NULL;
804 825 int mallocedPacket = JNI_FALSE;
805 826 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
806 827 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
807 828
808 829 jbyteArray packetBuffer;
809 830 jint packetBufferOffset, packetBufferLen;
810 831
811 832 int fd;
812 833
813 834 int n;
814 835 SOCKADDR remote_addr;
815 836 int len;
816 837 jboolean retry;
817 838 #ifdef __linux__
818 839 jboolean connected = JNI_FALSE;
819 840 jobject connectedAddress = NULL;
820 841 jint connectedPort = 0;
821 842 jlong prevTime = 0;
822 843 #endif
823 844
824 845 if (IS_NULL(fdObj)) {
825 846 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
826 847 "Socket closed");
827 848 return;
828 849 }
829 850
830 851 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
831 852
832 853 if (IS_NULL(packet)) {
833 854 JNU_ThrowNullPointerException(env, "packet");
834 855 return;
835 856 }
836 857
837 858 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
838 859 if (IS_NULL(packetBuffer)) {
839 860 JNU_ThrowNullPointerException(env, "packet buffer");
840 861 return;
841 862 }
842 863 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
843 864 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
844 865
845 866 if (packetBufferLen > MAX_BUFFER_LEN) {
846 867
847 868 /* When JNI-ifying the JDK's IO routines, we turned
848 869 * read's and write's of byte arrays of size greater
849 870 * than 2048 bytes into several operations of size 2048.
850 871 * This saves a malloc()/memcpy()/free() for big
851 872 * buffers. This is OK for file IO and TCP, but that
852 873 * strategy violates the semantics of a datagram protocol.
853 874 * (one big send) != (several smaller sends). So here
854 875 * we *must* alloc the buffer. Note it needn't be bigger
855 876 * than 65,536 (0xFFFF) the max size of an IP packet.
856 877 * anything bigger is truncated anyway.
857 878 *
858 879 * We may want to use a smarter allocation scheme at some
859 880 * point.
860 881 */
861 882 if (packetBufferLen > MAX_PACKET_LEN) {
862 883 packetBufferLen = MAX_PACKET_LEN;
863 884 }
864 885 fullPacket = (char *)malloc(packetBufferLen);
865 886
866 887 if (!fullPacket) {
867 888 JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
868 889 return;
869 890 } else {
870 891 mallocedPacket = JNI_TRUE;
871 892 }
872 893 } else {
873 894 fullPacket = &(BUF[0]);
874 895 }
875 896
876 897 #ifdef __linux__
877 898 /*
878 899 * On Linux with the 2.2 kernel we simulate connected datagrams by
879 900 * discarding packets
880 901 */
881 902 if (isOldKernel) {
882 903 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
883 904 if (connected) {
884 905 connectedAddress = (*env)->GetObjectField(env, this, pdsi_connectedAddress);
885 906 connectedPort = (*env)->GetIntField(env, this, pdsi_connectedPort);
886 907
887 908 if (timeout) {
888 909 prevTime = JVM_CurrentTimeMillis(env, 0);
889 910 }
890 911 }
891 912 }
892 913 #endif
893 914
894 915 do {
895 916 retry = JNI_FALSE;
896 917
897 918 if (timeout) {
898 919 int ret = NET_Timeout(fd, timeout);
899 920 if (ret <= 0) {
900 921 if (ret == 0) {
901 922 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
902 923 "Receive timed out");
903 924 } else if (ret == JVM_IO_ERR) {
904 925 #ifdef __linux__
905 926 if (errno == EBADF) {
906 927 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
907 928 } else {
908 929 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
909 930 }
910 931 #else
911 932 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
912 933 #endif
913 934 } else if (ret == JVM_IO_INTR) {
914 935 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
915 936 "operation interrupted");
916 937 }
917 938
918 939 if (mallocedPacket) {
919 940 free(fullPacket);
920 941 }
921 942
922 943 return;
923 944 }
924 945 }
925 946
926 947 /*
927 948 * Security Note: For Linux 2.2 with connected datagrams ensure that
928 949 * you receive into the stack/heap allocated buffer - do not attempt
929 950 * to receive directly into DatagramPacket's byte array.
930 951 * (ie: if the virtual machine support pinning don't use
931 952 * GetByteArrayElements or a JNI critical section and receive
932 953 * directly into the byte array)
933 954 */
934 955 len = SOCKADDR_LEN;
935 956 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
936 957 (struct sockaddr *)&remote_addr, &len);
937 958 /* truncate the data if the packet's length is too small */
938 959 if (n > packetBufferLen) {
939 960 n = packetBufferLen;
940 961 }
941 962 if (n == JVM_IO_ERR) {
942 963 (*env)->SetIntField(env, packet, dp_offsetID, 0);
943 964 (*env)->SetIntField(env, packet, dp_lengthID, 0);
944 965 if (errno == ECONNREFUSED) {
945 966 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
946 967 "ICMP Port Unreachable");
947 968 } else {
948 969 if (errno == EBADF) {
949 970 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
950 971 } else {
951 972 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
952 973 }
953 974 }
954 975 } else if (n == JVM_IO_INTR) {
955 976 (*env)->SetIntField(env, packet, dp_offsetID, 0);
956 977 (*env)->SetIntField(env, packet, dp_lengthID, 0);
957 978 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
958 979 "operation interrupted");
959 980 } else {
960 981 int port;
961 982 jobject packetAddress;
962 983
963 984 /*
964 985 * If we are connected then we know that the datagram that we have
965 986 * received is from the address that we are connected too. However
966 987 * on Linux with 2.2 kernel we have to simulate this behaviour by
967 988 * discarding any datagrams that aren't from the connected address.
968 989 */
969 990 #ifdef __linux__
970 991 if (isOldKernel && connected) {
971 992
972 993 if (NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr) != connectedPort ||
973 994 !NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, connectedAddress)) {
974 995
975 996 /*
976 997 * Discard the datagram as it's not from the connected
977 998 * address
978 999 */
979 1000 retry = JNI_TRUE;
980 1001
981 1002 /*
982 1003 * Adjust timeout if necessary to ensure that we adhere to
983 1004 * timeout semantics.
984 1005 */
985 1006 if (timeout) {
986 1007 jlong newTime = JVM_CurrentTimeMillis(env, 0);
987 1008 timeout -= (newTime - prevTime);
988 1009 if (timeout <= 0) {
989 1010 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
990 1011 "Receive timed out");
991 1012 if (mallocedPacket) {
992 1013 free(fullPacket);
993 1014 }
994 1015 return;
995 1016 }
996 1017 prevTime = newTime;
997 1018 }
998 1019
999 1020 continue;
1000 1021 }
1001 1022 }
1002 1023 #endif
1003 1024
1004 1025 /*
1005 1026 * success - fill in received address...
1006 1027 *
1007 1028 * REMIND: Fill in an int on the packet, and create inetadd
1008 1029 * object in Java, as a performance improvement. Also
1009 1030 * construct the inetadd object lazily.
1010 1031 */
1011 1032
1012 1033 /*
1013 1034 * Check if there is an InetAddress already associated with this
1014 1035 * packet. If so we check if it is the same source address. We
1015 1036 * can't update any existing InetAddress because it is immutable
1016 1037 */
1017 1038 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
1018 1039 if (packetAddress != NULL) {
1019 1040 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
1020 1041 /* force a new InetAddress to be created */
1021 1042 packetAddress = NULL;
1022 1043 }
1023 1044 }
1024 1045 if (packetAddress == NULL) {
1025 1046 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
1026 1047 /* stuff the new Inetaddress in the packet */
1027 1048 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
1028 1049 } else {
1029 1050 /* only get the new port number */
1030 1051 port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);
1031 1052 }
1032 1053 /* and fill in the data, remote address/port and such */
1033 1054 (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
1034 1055 (jbyte *)fullPacket);
1035 1056 (*env)->SetIntField(env, packet, dp_portID, port);
1036 1057 (*env)->SetIntField(env, packet, dp_lengthID, n);
1037 1058 }
1038 1059
1039 1060 } while (retry);
1040 1061
1041 1062 if (mallocedPacket) {
1042 1063 free(fullPacket);
1043 1064 }
1044 1065 }
1045 1066
1046 1067 /*
1047 1068 * Class: java_net_PlainDatagramSocketImpl
1048 1069 * Method: datagramSocketCreate
1049 1070 * Signature: ()V
1050 1071 */
1051 1072 JNIEXPORT void JNICALL
1052 1073 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
1053 1074 jobject this) {
1054 1075 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1055 1076 int fd;
1056 1077
1057 1078 int t = 1;
1058 1079
1059 1080 if (IS_NULL(fdObj)) {
1060 1081 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1061 1082 "Socket closed");
1062 1083 return;
1063 1084 } else {
1064 1085 #ifdef AF_INET6
1065 1086 if (ipv6_available()) {
1066 1087 fd = JVM_Socket(AF_INET6, SOCK_DGRAM, 0);
1067 1088 } else
1068 1089 #endif /* AF_INET6 */
1069 1090 {
1070 1091 fd = JVM_Socket(AF_INET, SOCK_DGRAM, 0);
1071 1092 }
1072 1093 }
1073 1094 if (fd == JVM_IO_ERR) {
1074 1095 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1075 1096 "Error creating socket");
1076 1097 return;
1077 1098 }
1078 1099
1079 1100 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
1080 1101
1081 1102 #ifdef __linux__
1082 1103 if (isOldKernel) {
1083 1104 setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, (char*) &t, sizeof(int));
1084 1105 }
1085 1106
1086 1107 #ifdef AF_INET6
1087 1108 /*
1088 1109 * On Linux for IPv6 sockets we must set the hop limit
1089 1110 * to 1 to be compatible with default ttl of 1 for IPv4 sockets.
1090 1111 */
1091 1112 if (ipv6_available()) {
1092 1113 int ttl = 1;
1093 1114 setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl,
1094 1115 sizeof(ttl));
1095 1116
1096 1117 if (isOldKernel) {
1097 1118 (*env)->SetIntField(env, this, pdsi_ttlID, ttl);
1098 1119 }
1099 1120 }
1100 1121 #endif
1101 1122
1102 1123 #endif /* __linux__ */
1103 1124
1104 1125 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1105 1126 }
1106 1127
1107 1128 /*
1108 1129 * Class: java_net_PlainDatagramSocketImpl
1109 1130 * Method: datagramSocketClose
1110 1131 * Signature: ()V
1111 1132 */
1112 1133 JNIEXPORT void JNICALL
1113 1134 Java_java_net_PlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env,
1114 1135 jobject this) {
1115 1136 /*
1116 1137 * REMIND: PUT A LOCK AROUND THIS CODE
1117 1138 */
1118 1139 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1119 1140 int fd;
1120 1141
1121 1142 if (IS_NULL(fdObj)) {
1122 1143 return;
1123 1144 }
1124 1145 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1125 1146 if (fd == -1) {
1126 1147 return;
1127 1148 }
↓ open down ↓ |
994 lines elided |
↑ open up ↑ |
1128 1149 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
1129 1150 NET_SocketClose(fd);
1130 1151 }
1131 1152
1132 1153
1133 1154 /*
1134 1155 * Set outgoing multicast interface designated by a NetworkInterface.
1135 1156 * Throw exception if failed.
1136 1157 */
1137 1158 static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1138 - static jfieldID ni_addrsID;
1139 - static jfieldID ia_addressID;
1140 1159 struct in_addr in;
1141 1160 jobjectArray addrArray;
1142 1161 jsize len;
1143 1162 jobject addr;
1144 1163 int i;
1145 1164
1146 - if (ni_addrsID == NULL) {
1147 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1148 - CHECK_NULL(c);
1149 - ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1150 - "[Ljava/net/InetAddress;");
1151 - CHECK_NULL(ni_addrsID);
1152 - c = (*env)->FindClass(env,"java/net/InetAddress");
1153 - CHECK_NULL(c);
1154 - ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
1155 - CHECK_NULL(ia_addressID);
1156 - }
1157 -
1158 1165 addrArray = (*env)->GetObjectField(env, value, ni_addrsID);
1159 1166 len = (*env)->GetArrayLength(env, addrArray);
1160 1167
1161 1168 /*
1162 1169 * Check that there is at least one address bound to this
1163 1170 * interface.
1164 1171 */
1165 1172 if (len < 1) {
1166 1173 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1167 1174 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1168 1175 return;
1169 1176 }
1170 1177
1171 1178 /*
1172 1179 * We need an ipv4 address here
1173 1180 */
1174 1181 for (i = 0; i < len; i++) {
1175 1182 addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1176 1183 if ((*env)->GetIntField(env, addr, ia_familyID) == IPv4) {
1177 1184 in.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
1178 1185 break;
1179 1186 }
1180 1187 }
1181 1188
1182 1189 if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1183 1190 (const char*)&in, sizeof(in)) < 0) {
1184 1191 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
1185 1192 "Error setting socket option");
1186 1193 }
1187 1194 }
1188 1195
1189 1196 /*
1190 1197 * Set outgoing multicast interface designated by a NetworkInterface.
1191 1198 * Throw exception if failed.
1192 1199 */
1193 1200 #ifdef AF_INET6
1194 1201 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1195 - static jfieldID ni_indexID;
1196 1202 int index;
1197 1203
1198 - if (ni_indexID == NULL) {
1199 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1200 - CHECK_NULL(c);
1201 - ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1202 - CHECK_NULL(ni_indexID);
1203 - }
1204 1204 index = (*env)->GetIntField(env, value, ni_indexID);
1205 1205
1206 1206 if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1207 1207 (const char*)&index, sizeof(index)) < 0) {
1208 1208 if (errno == EINVAL && index > 0) {
1209 1209 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1210 1210 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1211 1211 "address only?)");
1212 1212 } else {
1213 1213 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1214 1214 "Error setting socket option");
1215 1215 }
1216 1216 return;
1217 1217 }
1218 1218
1219 1219 #ifdef __linux__
1220 1220 /*
1221 1221 * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socket
1222 1222 * option so record index for later retrival.
1223 1223 */
1224 1224 if (isOldKernel) {
1225 1225 (*env)->SetIntField(env, this, pdsi_multicastInterfaceID,
1226 1226 (jint)index);
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
1227 1227 }
1228 1228 #endif
1229 1229 }
1230 1230 #endif /* AF_INET6 */
1231 1231
1232 1232 /*
1233 1233 * Set outgoing multicast interface designated by an InetAddress.
1234 1234 * Throw exception if failed.
1235 1235 */
1236 1236 static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1237 - static jfieldID ia_addressID;
1238 1237 struct in_addr in;
1239 1238
1240 - if (ia_addressID == NULL) {
1241 - jclass c = (*env)->FindClass(env,"java/net/InetAddress");
1242 - CHECK_NULL(c);
1243 - ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
1244 - CHECK_NULL(ia_addressID);
1245 - }
1246 -
1247 1239 in.s_addr = htonl( (*env)->GetIntField(env, value, ia_addressID) );
1248 1240
1249 1241 if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1250 1242 (const char*)&in, sizeof(in)) < 0) {
1251 1243 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1252 1244 "Error setting socket option");
1253 1245 }
1254 1246 }
1255 1247
1256 1248 /*
1257 1249 * Set outgoing multicast interface designated by an InetAddress.
1258 1250 * Throw exception if failed.
1259 1251 */
1260 1252 #ifdef AF_INET6
1261 1253 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1262 - static jclass ni_class;
1263 - if (ni_class == NULL) {
1264 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1265 - CHECK_NULL(c);
1266 - ni_class = (*env)->NewGlobalRef(env, c);
1267 - CHECK_NULL(ni_class);
1268 - }
1269 -
1270 1254 value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1271 1255 if (value == NULL) {
1272 1256 if (!(*env)->ExceptionOccurred(env)) {
1273 1257 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1274 1258 "bad argument for IP_MULTICAST_IF"
1275 1259 ": address not bound to any interface");
1276 1260 }
1277 1261 return;
1278 1262 }
1279 1263
1280 1264 mcast_set_if_by_if_v6(env, this, fd, value);
1281 1265 }
1282 1266 #endif
1283 1267
1284 1268 /*
1285 1269 * Sets the multicast interface.
1286 1270 *
1287 1271 * SocketOptions.IP_MULTICAST_IF :-
1288 1272 * value is a InetAddress
1289 1273 * IPv4: set outgoing multicast interface using
1290 1274 * IPPROTO_IP/IP_MULTICAST_IF
1291 1275 * IPv6: Get the index of the interface to which the
1292 1276 * InetAddress is bound
1293 1277 * Set outgoing multicast interface using
1294 1278 * IPPROTO_IPV6/IPV6_MULTICAST_IF
1295 1279 * On Linux 2.2 record interface index as can't
1296 1280 * query the multicast interface.
1297 1281 *
1298 1282 * SockOptions.IF_MULTICAST_IF2 :-
1299 1283 * value is a NetworkInterface
1300 1284 * IPv4: Obtain IP address bound to network interface
1301 1285 * (NetworkInterface.addres[0])
1302 1286 * set outgoing multicast interface using
1303 1287 * IPPROTO_IP/IP_MULTICAST_IF
1304 1288 * IPv6: Obtain NetworkInterface.index
1305 1289 * Set outgoing multicast interface using
1306 1290 * IPPROTO_IPV6/IPV6_MULTICAST_IF
1307 1291 * On Linux 2.2 record interface index as can't
1308 1292 * query the multicast interface.
1309 1293 *
1310 1294 */
1311 1295 static void setMulticastInterface(JNIEnv *env, jobject this, int fd,
1312 1296 jint opt, jobject value)
1313 1297 {
1314 1298 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1315 1299 /*
1316 1300 * value is an InetAddress.
1317 1301 */
1318 1302 #ifdef AF_INET6
1319 1303 #ifdef __solaris__
1320 1304 if (ipv6_available()) {
1321 1305 mcast_set_if_by_addr_v6(env, this, fd, value);
1322 1306 } else {
1323 1307 mcast_set_if_by_addr_v4(env, this, fd, value);
1324 1308 }
1325 1309 #endif
1326 1310 #ifdef __linux__
1327 1311 mcast_set_if_by_addr_v4(env, this, fd, value);
1328 1312 if (ipv6_available()) {
1329 1313 mcast_set_if_by_addr_v6(env, this, fd, value);
1330 1314 }
1331 1315 #endif
1332 1316 #else
1333 1317 mcast_set_if_by_addr_v4(env, this, fd, value);
1334 1318 #endif /* AF_INET6 */
1335 1319 }
1336 1320
1337 1321 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1338 1322 /*
1339 1323 * value is a NetworkInterface.
1340 1324 */
1341 1325 #ifdef AF_INET6
1342 1326 #ifdef __solaris__
1343 1327 if (ipv6_available()) {
1344 1328 mcast_set_if_by_if_v6(env, this, fd, value);
1345 1329 } else {
1346 1330 mcast_set_if_by_if_v4(env, this, fd, value);
1347 1331 }
1348 1332 #endif
1349 1333 #ifdef __linux__
1350 1334 mcast_set_if_by_if_v4(env, this, fd, value);
1351 1335 if (ipv6_available()) {
1352 1336 mcast_set_if_by_if_v6(env, this, fd, value);
1353 1337 }
1354 1338 #endif
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
1355 1339 #else
1356 1340 mcast_set_if_by_if_v4(env, this, fd, value);
1357 1341 #endif /* AF_INET6 */
1358 1342 }
1359 1343 }
1360 1344
1361 1345 /*
1362 1346 * Enable/disable local loopback of multicast datagrams.
1363 1347 */
1364 1348 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1365 - jclass cls;
1366 - jfieldID fid;
1367 1349 jboolean on;
1368 1350 char loopback;
1369 1351
1370 - cls = (*env)->FindClass(env, "java/lang/Boolean");
1371 - CHECK_NULL(cls);
1372 - fid = (*env)->GetFieldID(env, cls, "value", "Z");
1373 - CHECK_NULL(fid);
1374 -
1375 - on = (*env)->GetBooleanField(env, value, fid);
1352 + on = retrieveBoolean(env, value);
1376 1353 loopback = (!on ? 1 : 0);
1377 1354
1378 1355 if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&loopback, sizeof(char)) < 0) {
1379 1356 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1380 1357 return;
1381 1358 }
1382 1359 }
1383 1360
1384 1361 /*
1385 1362 * Enable/disable local loopback of multicast datagrams.
1386 1363 */
1387 1364 #ifdef AF_INET6
1388 1365 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1389 - jclass cls;
1390 - jfieldID fid;
1391 1366 jboolean on;
1392 1367 int loopback;
1393 1368
1394 - cls = (*env)->FindClass(env, "java/lang/Boolean");
1395 - CHECK_NULL(cls);
1396 - fid = (*env)->GetFieldID(env, cls, "value", "Z");
1397 - CHECK_NULL(fid);
1398 -
1399 - on = (*env)->GetBooleanField(env, value, fid);
1369 + on = retrieveBoolean(env, value);
1400 1370 loopback = (!on ? 1 : 0);
1401 1371
1402 1372 if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&loopback, sizeof(int)) < 0) {
1403 1373 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1404 1374 return;
1405 1375 }
1406 1376
1407 1377 #ifdef __linux__
1408 1378 /*
1409 1379 * Can't query IPV6_MULTICAST_LOOP on Linux 2.2 kernel so
1410 1380 * store it in impl so that we can simulate getsockopt.
1411 1381 */
1412 1382 if (isOldKernel) {
1413 1383 (*env)->SetBooleanField(env, this, pdsi_loopbackID, on);
1414 1384 }
1415 1385 #endif
1416 1386 }
1417 1387 #endif /* AF_INET6 */
1418 1388
1419 1389 /*
1420 1390 * Sets the multicast loopback mode.
1421 1391 */
1422 1392 static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
1423 1393 jint opt, jobject value) {
1424 1394 #ifdef AF_INET6
1425 1395 #ifdef __solaris__
1426 1396 if (ipv6_available()) {
1427 1397 mcast_set_loop_v6(env, this, fd, value);
1428 1398 } else {
1429 1399 mcast_set_loop_v4(env, this, fd, value);
1430 1400 }
1431 1401 #endif
1432 1402 #ifdef __linux__
1433 1403 mcast_set_loop_v4(env, this, fd, value);
1434 1404 if (ipv6_available()) {
1435 1405 mcast_set_loop_v6(env, this, fd, value);
1436 1406 }
1437 1407 #endif
1438 1408 #else
1439 1409 mcast_set_loop_v4(env, this, fd, value);
1440 1410 #endif /* AF_INET6 */
1441 1411 }
1442 1412
1443 1413 /*
1444 1414 * Class: java_net_PlainDatagramSocketImpl
1445 1415 * Method: socketSetOption
1446 1416 * Signature: (ILjava/lang/Object;)V
1447 1417 */
1448 1418 JNIEXPORT void JNICALL
1449 1419 Java_java_net_PlainDatagramSocketImpl_socketSetOption(JNIEnv *env,
1450 1420 jobject this,
1451 1421 jint opt,
1452 1422 jobject value) {
1453 1423 int fd;
1454 1424 int level, optname, optlen;
1455 1425 union {
1456 1426 int i;
1457 1427 char c;
1458 1428 } optval;
1459 1429
1460 1430 /*
1461 1431 * Check that socket hasn't been closed
1462 1432 */
1463 1433 fd = getFD(env, this);
1464 1434 if (fd < 0) {
1465 1435 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1466 1436 "Socket closed");
1467 1437 return;
1468 1438 }
1469 1439
1470 1440 /*
1471 1441 * Check argument has been provided
1472 1442 */
1473 1443 if (IS_NULL(value)) {
1474 1444 JNU_ThrowNullPointerException(env, "value argument");
1475 1445 return;
1476 1446 }
1477 1447
1478 1448 /*
1479 1449 * Setting the multicast interface handled seperately
1480 1450 */
1481 1451 if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1482 1452 opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1483 1453
1484 1454 setMulticastInterface(env, this, fd, opt, value);
1485 1455 return;
1486 1456 }
1487 1457
1488 1458 /*
1489 1459 * Setting the multicast loopback mode handled separately
1490 1460 */
1491 1461 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1492 1462 setMulticastLoopbackMode(env, this, fd, opt, value);
1493 1463 return;
1494 1464 }
1495 1465
1496 1466 /*
1497 1467 * Map the Java level socket option to the platform specific
1498 1468 * level and option name.
1499 1469 */
↓ open down ↓ |
90 lines elided |
↑ open up ↑ |
1500 1470 if (NET_MapSocketOption(opt, &level, &optname)) {
1501 1471 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1502 1472 return;
1503 1473 }
1504 1474
1505 1475 switch (opt) {
1506 1476 case java_net_SocketOptions_SO_SNDBUF :
1507 1477 case java_net_SocketOptions_SO_RCVBUF :
1508 1478 case java_net_SocketOptions_IP_TOS :
1509 1479 {
1510 - jclass cls;
1511 - jfieldID fid;
1512 -
1513 - cls = (*env)->FindClass(env, "java/lang/Integer");
1514 - CHECK_NULL(cls);
1515 - fid = (*env)->GetFieldID(env, cls, "value", "I");
1516 - CHECK_NULL(fid);
1517 -
1518 - optval.i = (*env)->GetIntField(env, value, fid);
1480 + optval.i = retrieveInteger(env, value);
1519 1481 optlen = sizeof(optval.i);
1520 1482 break;
1521 1483 }
1522 1484
1523 1485 case java_net_SocketOptions_SO_REUSEADDR:
1524 1486 case java_net_SocketOptions_SO_BROADCAST:
1525 1487 {
1526 - jclass cls;
1527 - jfieldID fid;
1528 - jboolean on;
1488 + jboolean on = retrieveBoolean(env, value);
1529 1489
1530 - cls = (*env)->FindClass(env, "java/lang/Boolean");
1531 - CHECK_NULL(cls);
1532 - fid = (*env)->GetFieldID(env, cls, "value", "Z");
1533 - CHECK_NULL(fid);
1534 -
1535 - on = (*env)->GetBooleanField(env, value, fid);
1536 -
1537 1490 /* SO_REUSEADDR or SO_BROADCAST */
1538 1491 optval.i = (on ? 1 : 0);
1539 1492 optlen = sizeof(optval.i);
1540 1493
1541 1494 break;
1542 1495 }
1543 1496
1544 1497 default :
1545 1498 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1546 1499 "Socket option not supported by PlainDatagramSocketImp");
1547 1500 break;
1548 1501
1549 1502 }
1550 1503
1551 1504 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
1552 1505 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1553 1506 return;
1554 1507 }
1555 1508 }
1556 1509
1557 1510
1558 1511 /*
1559 1512 * Return the multicast interface:
1560 1513 *
1561 1514 * SocketOptions.IP_MULTICAST_IF
1562 1515 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1563 1516 * Create InetAddress
1564 1517 * IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1565 1518 * kernel but struct in_addr on 2.4 kernel
1566 1519 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
1567 1520 * obtain from impl is Linux 2.2 kernel
1568 1521 * If index == 0 return InetAddress representing
1569 1522 * anyLocalAddress.
1570 1523 * If index > 0 query NetworkInterface by index
1571 1524 * and returns addrs[0]
1572 1525 *
1573 1526 * SocketOptions.IP_MULTICAST_IF2
1574 1527 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1575 1528 * Query NetworkInterface by IP address and
1576 1529 * return the NetworkInterface that the address
1577 1530 * is bound too.
1578 1531 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1579 1532 * (except Linux .2 kernel)
1580 1533 * Query NetworkInterface by index and
1581 1534 * return NetworkInterface.
1582 1535 */
1583 1536 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) {
1584 1537 jboolean isIPV4 = JNI_TRUE;
1585 1538
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
1586 1539 #ifdef AF_INET6
1587 1540 if (ipv6_available()) {
1588 1541 isIPV4 = JNI_FALSE;
1589 1542 }
1590 1543 #endif
1591 1544
1592 1545 /*
1593 1546 * IPv4 implementation
1594 1547 */
1595 1548 if (isIPV4) {
1596 - static jclass inet4_class;
1597 - static jmethodID inet4_ctrID;
1598 - static jfieldID inet4_addrID;
1599 -
1600 - static jclass ni_class;
1601 - static jmethodID ni_ctrID;
1602 - static jfieldID ni_indexID;
1603 - static jfieldID ni_addrsID;
1604 -
1605 1549 jobjectArray addrArray;
1606 1550 jobject addr;
1607 1551 jobject ni;
1608 1552
1609 1553 struct in_addr in;
1610 1554 struct in_addr *inP = ∈
1611 1555 int len = sizeof(struct in_addr);
1612 1556
1613 1557 #ifdef __linux__
1614 1558 struct ip_mreqn mreqn;
1615 1559 if (isOldKernel) {
1616 1560 inP = (struct in_addr *)&mreqn;
1617 1561 len = sizeof(struct ip_mreqn);
1618 1562 }
1619 1563 #endif
1620 1564
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
1621 1565 if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1622 1566 (char *)inP, &len) < 0) {
1623 1567 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1624 1568 "Error getting socket option");
1625 1569 return NULL;
1626 1570 }
1627 1571
1628 1572 /*
1629 1573 * Construct and populate an Inet4Address
1630 1574 */
1631 - if (inet4_class == NULL) {
1632 - jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1633 - CHECK_NULL_RETURN(c, NULL);
1634 - inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1635 - CHECK_NULL_RETURN(inet4_ctrID, NULL);
1636 - inet4_addrID = (*env)->GetFieldID(env, c, "address", "I");
1637 - CHECK_NULL_RETURN(inet4_addrID, NULL);
1638 - inet4_class = (*env)->NewGlobalRef(env, c);
1639 - CHECK_NULL_RETURN(inet4_class, NULL);
1640 - }
1641 - addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1575 + addr = (*env)->NewObject(env, ia4_class, ia4_ctrID, 0);
1642 1576 CHECK_NULL_RETURN(addr, NULL);
1643 1577
1644 1578 #ifdef __linux__
1645 - (*env)->SetIntField(env, addr, inet4_addrID,
1579 + (*env)->SetIntField(env, addr, ia_addressID,
1646 1580 (isOldKernel ? ntohl(mreqn.imr_address.s_addr) : ntohl(in.s_addr)) );
1647 1581 #else
1648 - (*env)->SetIntField(env, addr, inet4_addrID, ntohl(in.s_addr));
1582 + (*env)->SetIntField(env, addr, ia_addressID, ntohl(in.s_addr));
1649 1583 #endif
1650 1584
1651 1585 /*
1652 1586 * For IP_MULTICAST_IF return InetAddress
1653 1587 */
1654 1588 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1655 1589 return addr;
1656 1590 }
1657 1591
1658 1592 /*
1659 1593 * For IP_MULTICAST_IF2 we get the NetworkInterface for
1660 1594 * this address and return it
1661 1595 */
1662 - if (ni_class == NULL) {
1663 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1664 - CHECK_NULL_RETURN(c, NULL);
1665 - ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1666 - CHECK_NULL_RETURN(ni_ctrID, NULL);
1667 - ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1668 - CHECK_NULL_RETURN(ni_indexID, NULL);
1669 - ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1670 - "[Ljava/net/InetAddress;");
1671 - CHECK_NULL_RETURN(ni_addrsID, NULL);
1672 - ni_class = (*env)->NewGlobalRef(env, c);
1673 - CHECK_NULL_RETURN(ni_class, NULL);
1674 - }
1675 1596 ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
1676 1597 if (ni) {
1677 1598 return ni;
1678 1599 }
1679 1600
1680 1601 /*
1681 1602 * The address doesn't appear to be bound at any known
1682 1603 * NetworkInterface. Therefore we construct a NetworkInterface
1683 1604 * with this address.
1684 1605 */
1685 1606 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1686 1607 CHECK_NULL_RETURN(ni, NULL);
1687 1608
1688 1609 (*env)->SetIntField(env, ni, ni_indexID, -1);
1689 - addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
1610 + addrArray = (*env)->NewObjectArray(env, 1, ia4_class, NULL);
1690 1611 CHECK_NULL_RETURN(addrArray, NULL);
1691 1612 (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1692 1613 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1693 1614 return ni;
1694 1615 }
1695 1616
1696 1617
1697 1618 #ifdef AF_INET6
1698 1619 /*
1699 1620 * IPv6 implementation
1700 1621 */
1701 1622 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1702 1623 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1703 -
1704 - static jclass ni_class;
1705 - static jmethodID ni_ctrID;
1706 - static jfieldID ni_indexID;
1707 - static jfieldID ni_addrsID;
1708 - static jclass ia_class;
1709 1624 static jmethodID ia_anyLocalAddressID;
1710 1625
1711 1626 int index;
1712 1627 int len = sizeof(index);
1713 1628
1714 1629 jobjectArray addrArray;
1715 1630 jobject addr;
1716 1631 jobject ni;
1717 1632
1718 1633 #ifdef __linux__
1719 1634 /*
1720 1635 * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socke option
1721 1636 * so use cached index.
1722 1637 */
1723 1638 if (isOldKernel) {
1724 1639 index = (*env)->GetIntField(env, this, pdsi_multicastInterfaceID);
1725 1640 } else
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
1726 1641 #endif
1727 1642 {
1728 1643 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1729 1644 (char*)&index, &len) < 0) {
1730 1645 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1731 1646 "Error getting socket option");
1732 1647 return NULL;
1733 1648 }
1734 1649 }
1735 1650
1736 - if (ni_class == NULL) {
1737 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1738 - CHECK_NULL_RETURN(c, NULL);
1739 - ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1740 - CHECK_NULL_RETURN(ni_ctrID, NULL);
1741 - ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1742 - CHECK_NULL_RETURN(ni_indexID, NULL);
1743 - ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1744 - "[Ljava/net/InetAddress;");
1745 - CHECK_NULL_RETURN(ni_addrsID, NULL);
1746 -
1747 - ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1748 - CHECK_NULL_RETURN(ia_class, NULL);
1749 - ia_class = (*env)->NewGlobalRef(env, ia_class);
1750 - CHECK_NULL_RETURN(ia_class, NULL);
1651 + if (ia_anyLocalAddressID == NULL) {
1751 1652 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1752 1653 ia_class,
1753 1654 "anyLocalAddress",
1754 1655 "()Ljava/net/InetAddress;");
1755 1656 CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
1756 - ni_class = (*env)->NewGlobalRef(env, c);
1757 - CHECK_NULL_RETURN(ni_class, NULL);
1758 1657 }
1759 1658
1760 1659 /*
1761 1660 * If multicast to a specific interface then return the
1762 1661 * interface (for IF2) or the any address on that interface
1763 1662 * (for IF).
1764 1663 */
1765 1664 if (index > 0) {
1766 1665 ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
1767 1666 index);
1768 1667 if (ni == NULL) {
1769 1668 char errmsg[255];
1770 1669 sprintf(errmsg,
1771 1670 "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
1772 1671 index);
1773 1672 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1774 1673 return NULL;
1775 1674 }
1776 1675
1777 1676 /*
1778 1677 * For IP_MULTICAST_IF2 return the NetworkInterface
1779 1678 */
1780 1679 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1781 1680 return ni;
1782 1681 }
1783 1682
1784 1683 /*
1785 1684 * For IP_MULTICAST_IF return addrs[0]
1786 1685 */
1787 1686 addrArray = (*env)->GetObjectField(env, ni, ni_addrsID);
1788 1687 if ((*env)->GetArrayLength(env, addrArray) < 1) {
1789 1688 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1790 1689 "IPV6_MULTICAST_IF returned interface without IP bindings");
1791 1690 return NULL;
1792 1691 }
1793 1692
1794 1693 addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
1795 1694 return addr;
1796 1695 }
1797 1696
1798 1697 /*
1799 1698 * Multicast to any address - return anyLocalAddress
1800 1699 * or a NetworkInterface with addrs[0] set to anyLocalAddress
1801 1700 */
1802 1701
1803 1702 addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID,
1804 1703 NULL);
1805 1704 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1806 1705 return addr;
1807 1706 }
1808 1707
1809 1708 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1810 1709 CHECK_NULL_RETURN(ni, NULL);
1811 1710 (*env)->SetIntField(env, ni, ni_indexID, -1);
1812 1711 addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL);
1813 1712 CHECK_NULL_RETURN(addrArray, NULL);
1814 1713 (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1815 1714 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1816 1715 return ni;
1817 1716 }
1818 1717 #endif
1819 1718 return NULL;
1820 1719 }
1821 1720
1822 1721
1823 1722
1824 1723 /*
1825 1724 * Returns relevant info as a jint.
1826 1725 *
1827 1726 * Class: java_net_PlainDatagramSocketImpl
1828 1727 * Method: socketGetOption
1829 1728 * Signature: (I)Ljava/lang/Object;
1830 1729 */
1831 1730 JNIEXPORT jobject JNICALL
1832 1731 Java_java_net_PlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this,
1833 1732 jint opt) {
1834 1733 int fd;
1835 1734 int level, optname, optlen;
1836 1735 union {
1837 1736 int i;
1838 1737 char c;
1839 1738 } optval;
1840 1739
1841 1740 fd = getFD(env, this);
1842 1741 if (fd < 0) {
1843 1742 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1844 1743 "socket closed");
1845 1744 return NULL;
1846 1745 }
1847 1746
1848 1747 /*
1849 1748 * Handle IP_MULTICAST_IF seperately
1850 1749 */
1851 1750 if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1852 1751 opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1853 1752 return getMulticastInterface(env, this, fd, opt);
1854 1753
1855 1754 }
1856 1755
1857 1756 /*
1858 1757 * SO_BINDADDR implemented using getsockname
1859 1758 */
1860 1759 if (opt == java_net_SocketOptions_SO_BINDADDR) {
1861 1760 /* find out local IP address */
1862 1761 SOCKADDR him;
1863 1762 socklen_t len = 0;
1864 1763 int port;
1865 1764 jobject iaObj;
1866 1765
1867 1766 len = SOCKADDR_LEN;
1868 1767
1869 1768 if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
1870 1769 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1871 1770 "Error getting socket name");
1872 1771 return NULL;
1873 1772 }
1874 1773 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1875 1774
1876 1775 return iaObj;
1877 1776 }
1878 1777
1879 1778 /*
1880 1779 * Map the Java level socket option to the platform specific
1881 1780 * level and option name.
1882 1781 */
1883 1782 if (NET_MapSocketOption(opt, &level, &optname)) {
1884 1783 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1885 1784 return NULL;
1886 1785 }
1887 1786
1888 1787 /*
1889 1788 * IP_MULTICAST_LOOP socket option isn't available on Linux 2.2
1890 1789 * kernel with IPv6 so return value stored in impl.
1891 1790 */
1892 1791 #if defined(AF_INET6) && defined(__linux__)
1893 1792 if (isOldKernel && opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&
1894 1793 level == IPPROTO_IPV6) {
1895 1794 int mode = (int)(*env)->GetBooleanField(env, this, pdsi_loopbackID);
1896 1795 return createBoolean(env, mode);
1897 1796 }
1898 1797 #endif
1899 1798
1900 1799 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&
1901 1800 level == IPPROTO_IP) {
1902 1801 optlen = sizeof(optval.c);
1903 1802 } else {
1904 1803 optlen = sizeof(optval.i);
1905 1804 }
1906 1805
1907 1806 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1908 1807 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1909 1808 "Error getting socket option");
1910 1809 return NULL;
1911 1810 }
1912 1811
1913 1812 switch (opt) {
1914 1813 case java_net_SocketOptions_IP_MULTICAST_LOOP:
1915 1814 /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */
1916 1815 if (level == IPPROTO_IP) {
1917 1816 return createBoolean(env, (int)!optval.c);
1918 1817 } else {
1919 1818 return createBoolean(env, !optval.i);
1920 1819 }
1921 1820
1922 1821 case java_net_SocketOptions_SO_BROADCAST:
1923 1822 case java_net_SocketOptions_SO_REUSEADDR:
1924 1823 return createBoolean(env, optval.i);
1925 1824
1926 1825 case java_net_SocketOptions_SO_SNDBUF:
1927 1826 case java_net_SocketOptions_SO_RCVBUF:
1928 1827 case java_net_SocketOptions_IP_TOS:
1929 1828 return createInteger(env, optval.i);
1930 1829
1931 1830 }
1932 1831
1933 1832 /* should never rearch here */
1934 1833 return NULL;
1935 1834 }
1936 1835
1937 1836 /*
1938 1837 * Multicast-related calls
1939 1838 */
1940 1839
1941 1840 JNIEXPORT void JNICALL
1942 1841 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1943 1842 jbyte ttl) {
1944 1843 jint ittl = ttl;
1945 1844 if (ittl < 0) {
1946 1845 ittl += 0x100;
1947 1846 }
1948 1847 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1949 1848 }
1950 1849
1951 1850 /*
1952 1851 * Set TTL for a socket. Throw exception if failed.
1953 1852 */
1954 1853 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1955 1854 char ittl = (char)ttl;
1956 1855 if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1957 1856 sizeof(ittl)) < 0) {
1958 1857 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1959 1858 "Error setting socket option");
1960 1859 }
1961 1860 }
1962 1861
1963 1862 /*
1964 1863 * Set hops limit for a socket. Throw exception if failed.
1965 1864 */
1966 1865 #ifdef AF_INET6
1967 1866 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1968 1867 int ittl = (int)ttl;
1969 1868 if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1970 1869 (char*)&ittl, sizeof(ittl)) < 0) {
1971 1870 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1972 1871 "Error setting socket option");
1973 1872 }
1974 1873 }
1975 1874 #endif
1976 1875
1977 1876 /*
1978 1877 * Class: java_net_PlainDatagramSocketImpl
1979 1878 * Method: setTTL
1980 1879 * Signature: (B)V
1981 1880 */
1982 1881 JNIEXPORT void JNICALL
1983 1882 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
1984 1883 jint ttl) {
1985 1884
1986 1885 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1987 1886 int fd;
1988 1887 /* it is important to cast this to a char, otherwise setsockopt gets confused */
1989 1888
1990 1889 if (IS_NULL(fdObj)) {
1991 1890 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1992 1891 "Socket closed");
1993 1892 return;
1994 1893 } else {
1995 1894 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1996 1895 }
1997 1896 /* setsockopt to be correct ttl */
1998 1897 #ifdef AF_INET6
1999 1898 #ifdef __solaris__
2000 1899 if (ipv6_available()) {
2001 1900 setHopLimit(env, fd, ttl);
2002 1901 } else {
2003 1902 setTTL(env, fd, ttl);
2004 1903 }
2005 1904 #endif
2006 1905 #ifdef __linux__
2007 1906 setTTL(env, fd, ttl);
2008 1907 if (ipv6_available()) {
2009 1908 setHopLimit(env, fd, ttl);
2010 1909 if (isOldKernel) {
2011 1910 (*env)->SetIntField(env, this, pdsi_ttlID, ttl);
2012 1911 }
2013 1912 }
2014 1913 #endif // __linux__
2015 1914 #else
2016 1915 setTTL(env, fd, ttl);
2017 1916 #endif /* AF_INET6 */
2018 1917 }
2019 1918
2020 1919 /*
2021 1920 * Class: java_net_PlainDatagramSocketImpl
2022 1921 * Method: getTTL
2023 1922 * Signature: ()B
2024 1923 */
2025 1924 JNIEXPORT jbyte JNICALL
2026 1925 Java_java_net_PlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {
2027 1926 return (jbyte)Java_java_net_PlainDatagramSocketImpl_getTimeToLive(env, this);
2028 1927 }
2029 1928
2030 1929
2031 1930 /*
2032 1931 * Class: java_net_PlainDatagramSocketImpl
2033 1932 * Method: getTTL
2034 1933 * Signature: ()B
2035 1934 */
2036 1935 JNIEXPORT jint JNICALL
2037 1936 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
2038 1937
2039 1938 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2040 1939 jint fd = -1;
2041 1940
2042 1941 if (IS_NULL(fdObj)) {
2043 1942 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2044 1943 "Socket closed");
2045 1944 return -1;
2046 1945 } else {
2047 1946 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2048 1947 }
2049 1948 /* getsockopt of ttl */
2050 1949 #ifdef AF_INET6
2051 1950 if (ipv6_available()) {
2052 1951 int ttl = 0;
2053 1952 int len = sizeof(ttl);
2054 1953
2055 1954 #ifdef __linux__
2056 1955 /*
2057 1956 * Linux 2.2 kernel doesn't support IPV6_MULTICAST_HOPS socket option
2058 1957 */
2059 1958 if (isOldKernel) {
2060 1959 return (*env)->GetIntField(env, this, pdsi_ttlID);
2061 1960 }
2062 1961 #endif
2063 1962
2064 1963 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
2065 1964 (char*)&ttl, &len) < 0) {
2066 1965 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
2067 1966 "Error getting socket option");
2068 1967 return -1;
2069 1968 }
2070 1969 return (jint)ttl;
2071 1970 } else
2072 1971 #endif /* AF_INET6 */
2073 1972 {
2074 1973 u_char ttl = 0;
2075 1974 int len = sizeof(ttl);
2076 1975 if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
2077 1976 (char*)&ttl, &len) < 0) {
2078 1977 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
2079 1978 "Error getting socket option");
2080 1979 return -1;
2081 1980 }
2082 1981 return (jint)ttl;
2083 1982 }
2084 1983 }
2085 1984
2086 1985
2087 1986 /*
2088 1987 * mcast_join_leave: Join or leave a multicast group.
2089 1988 *
2090 1989 * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
2091 1990 * to join/leave multicast group.
2092 1991 *
2093 1992 * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
2094 1993 * to join/leave multicast group. If multicast group is an IPv4 address then
2095 1994 * an IPv4-mapped address is used.
2096 1995 *
2097 1996 * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
2098 1997 * we must use the IPv4 socket options. This is because the IPv6 socket options
2099 1998 * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7
2100 1999 * kernel releases. In the future it's possible that IP_ADD_MEMBERSHIP
2101 2000 * will be updated to return ENOPROTOOPT if uses with an IPv6 socket (Solaris
2102 2001 * already does this). Thus to cater for this we first try with the IPv4
2103 2002 * socket options and if they fail we use the IPv6 socket options. This
2104 2003 * seems a reasonable failsafe solution.
2105 2004 */
2106 2005 static void mcast_join_leave(JNIEnv *env, jobject this,
2107 2006 jobject iaObj, jobject niObj,
2108 2007 jboolean join) {
2109 2008
2110 2009 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2111 2010 jint fd;
2112 2011 jint ipv6_join_leave;
2113 2012
2114 2013 if (IS_NULL(fdObj)) {
2115 2014 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2116 2015 "Socket closed");
2117 2016 return;
2118 2017 } else {
2119 2018 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2120 2019 }
2121 2020 if (IS_NULL(iaObj)) {
2122 2021 JNU_ThrowNullPointerException(env, "iaObj");
2123 2022 return;
2124 2023 }
2125 2024
2126 2025 /*
2127 2026 * Determine if this is an IPv4 or IPv6 join/leave.
2128 2027 */
2129 2028 #ifdef AF_INET6
2130 2029 ipv6_join_leave = ipv6_available();
2131 2030
2132 2031 #ifdef __linux__
2133 2032 if ((*env)->GetIntField(env, iaObj, ia_familyID) == IPv4) {
2134 2033 ipv6_join_leave = JNI_FALSE;
2135 2034 }
2136 2035 #endif
2137 2036
2138 2037 #else
2139 2038 /*
2140 2039 * IPv6 not compiled in
2141 2040 */
2142 2041 ipv6_join_leave = JNI_FALSE;
2143 2042 #endif
2144 2043
2145 2044 /*
2146 2045 * For IPv4 join use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
2147 2046 *
2148 2047 * On Linux if IPv4 or IPv6 use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP
2149 2048 */
2150 2049 if (!ipv6_join_leave) {
2151 2050 #ifdef __linux__
2152 2051 struct ip_mreqn mname;
2153 2052 #else
2154 2053 struct ip_mreq mname;
2155 2054 #endif
2156 2055 int mname_len;
2157 2056
2158 2057 /*
2159 2058 * joinGroup(InetAddress, NetworkInterface) implementation :-
2160 2059 *
↓ open down ↓ |
393 lines elided |
↑ open up ↑ |
2161 2060 * Linux/IPv6: use ip_mreqn structure populated with multicast
2162 2061 * address and interface index.
2163 2062 *
2164 2063 * IPv4: use ip_mreq structure populated with multicast
2165 2064 * address and first address obtained from
2166 2065 * NetworkInterface
2167 2066 */
2168 2067 if (niObj != NULL) {
2169 2068 #if defined(__linux__) && defined(AF_INET6)
2170 2069 if (ipv6_available()) {
2171 - static jfieldID ni_indexID;
2172 -
2173 - if (ni_indexID == NULL) {
2174 - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
2175 - CHECK_NULL(c);
2176 - ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
2177 - CHECK_NULL(ni_indexID);
2178 - }
2179 -
2180 2070 mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID));
2181 2071 mname.imr_address.s_addr = 0;
2182 2072 mname.imr_ifindex = (*env)->GetIntField(env, niObj, ni_indexID);
2183 2073 mname_len = sizeof(struct ip_mreqn);
2184 2074 } else
2185 2075 #endif
2186 2076 {
2187 2077 jobjectArray addrArray = (*env)->GetObjectField(env, niObj, ni_addrsID);
2188 2078 jobject addr;
2189 2079
2190 2080 if ((*env)->GetArrayLength(env, addrArray) < 1) {
2191 2081 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2192 2082 "bad argument for IP_ADD_MEMBERSHIP: "
2193 2083 "No IP addresses bound to interface");
2194 2084 return;
2195 2085 }
2196 2086 addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
2197 2087
2198 2088 mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID));
2199 2089 #ifdef __linux__
2200 2090 mname.imr_address.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
2201 2091 #else
2202 2092 mname.imr_interface.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
2203 2093 #endif
2204 2094 mname_len = sizeof(struct ip_mreq);
2205 2095 }
2206 2096 }
2207 2097
2208 2098
2209 2099 /*
2210 2100 * joinGroup(InetAddress) implementation :-
2211 2101 *
2212 2102 * Linux/IPv6: use ip_mreqn structure populated with multicast
2213 2103 * address and interface index. index obtained
2214 2104 * from cached value or IPV6_MULTICAST_IF.
2215 2105 *
2216 2106 * IPv4: use ip_mreq structure populated with multicast
2217 2107 * address and local address obtained from
2218 2108 * IP_MULTICAST_IF. On Linux IP_MULTICAST_IF
2219 2109 * returns different structure depending on
2220 2110 * kernel.
2221 2111 */
2222 2112
2223 2113 if (niObj == NULL) {
2224 2114
2225 2115 #if defined(__linux__) && defined(AF_INET6)
2226 2116 if (ipv6_available()) {
2227 2117
2228 2118 int index;
2229 2119 int len = sizeof(index);
2230 2120
2231 2121 if (isOldKernel) {
2232 2122 index = (*env)->GetIntField(env, this, pdsi_multicastInterfaceID);
2233 2123 } else {
2234 2124 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2235 2125 (char*)&index, &len) < 0) {
2236 2126 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2237 2127 return;
2238 2128 }
2239 2129 }
2240 2130
2241 2131 mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID));
2242 2132 mname.imr_address.s_addr = 0 ;
2243 2133 mname.imr_ifindex = index;
2244 2134 mname_len = sizeof(struct ip_mreqn);
2245 2135 } else
2246 2136 #endif
2247 2137 {
2248 2138 struct in_addr in;
2249 2139 struct in_addr *inP = ∈
2250 2140 int len = sizeof(struct in_addr);
2251 2141
2252 2142 #ifdef __linux__
2253 2143 struct ip_mreqn mreqn;
2254 2144 if (isOldKernel) {
2255 2145 inP = (struct in_addr *)&mreqn;
2256 2146 len = sizeof(struct ip_mreqn);
2257 2147 }
2258 2148 #endif
2259 2149 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)inP, &len) < 0) {
2260 2150 NET_ThrowCurrent(env, "getsockopt IP_MULTICAST_IF failed");
2261 2151 return;
2262 2152 }
2263 2153
2264 2154 #ifdef __linux__
2265 2155 mname.imr_address.s_addr =
2266 2156 (isOldKernel ? mreqn.imr_address.s_addr : in.s_addr);
2267 2157
2268 2158 #else
2269 2159 mname.imr_interface.s_addr = in.s_addr;
2270 2160 #endif
2271 2161 mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID));
2272 2162 mname_len = sizeof(struct ip_mreq);
2273 2163 }
2274 2164 }
2275 2165
2276 2166
2277 2167 /*
2278 2168 * Join the multicast group.
2279 2169 */
2280 2170 if (JVM_SetSockOpt(fd, IPPROTO_IP, (join ? IP_ADD_MEMBERSHIP:IP_DROP_MEMBERSHIP),
2281 2171 (char *) &mname, mname_len) < 0) {
2282 2172
2283 2173 /*
2284 2174 * If IP_ADD_MEMBERSHIP returns ENOPROTOOPT on Linux and we've got
2285 2175 * IPv6 enabled then it's possible that the kernel has been fixed
2286 2176 * so we switch to IPV6_ADD_MEMBERSHIP socket option.
2287 2177 * As of 2.4.7 kernel IPV6_ADD_MEMERSHIP can't handle IPv4-mapped
2288 2178 * addresses so we have to use IP_ADD_MEMERSHIP for IPv4 multicast
2289 2179 * groups. However if the socket is an IPv6 socket then then setsockopt
2290 2180 * should reurn ENOPROTOOPT. We assume this will be fixed in Linux
2291 2181 * at some stage.
2292 2182 */
2293 2183 #if defined(__linux__) && defined(AF_INET6)
2294 2184 if (errno == ENOPROTOOPT) {
2295 2185 if (ipv6_available()) {
2296 2186 ipv6_join_leave = JNI_TRUE;
2297 2187 errno = 0;
2298 2188 } else {
2299 2189 errno = ENOPROTOOPT; /* errno can be changed by ipv6_available */
2300 2190 }
2301 2191 }
2302 2192 #endif
2303 2193 if (errno) {
2304 2194 if (join) {
2305 2195 NET_ThrowCurrent(env, "setsockopt IP_ADD_MEMBERSHIP failed");
2306 2196 } else {
2307 2197 if (errno == ENOENT)
2308 2198 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2309 2199 "Not a member of the multicast group");
2310 2200 else
2311 2201 NET_ThrowCurrent(env, "setsockopt IP_DROP_MEMBERSHIP failed");
2312 2202 }
2313 2203 }
2314 2204 }
2315 2205
2316 2206 /*
2317 2207 * If we haven't switched to IPv6 socket option then we're done.
2318 2208 */
2319 2209 if (!ipv6_join_leave) {
2320 2210 return;
2321 2211 }
2322 2212 }
2323 2213
2324 2214
2325 2215 /*
2326 2216 * IPv6 join. If it's an IPv4 multicast group then we use an IPv4-mapped
2327 2217 * address.
2328 2218 */
2329 2219 #ifdef AF_INET6
2330 2220 {
2331 2221 struct ipv6_mreq mname6;
2332 2222 jbyteArray ipaddress;
2333 2223 jbyte caddr[16];
2334 2224 jint family;
2335 2225 jint address;
2336 2226 family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? AF_INET : AF_INET6;
2337 2227 if (family == AF_INET) { /* will convert to IPv4-mapped address */
2338 2228 memset((char *) caddr, 0, 16);
2339 2229 address = (*env)->GetIntField(env, iaObj, ia_addressID);
2340 2230
2341 2231 caddr[10] = 0xff;
2342 2232 caddr[11] = 0xff;
2343 2233
2344 2234 caddr[12] = ((address >> 24) & 0xff);
2345 2235 caddr[13] = ((address >> 16) & 0xff);
2346 2236 caddr[14] = ((address >> 8) & 0xff);
2347 2237 caddr[15] = (address & 0xff);
2348 2238 } else {
2349 2239 ipaddress = (*env)->GetObjectField(env, iaObj, ia6_ipaddressID);
2350 2240 (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
2351 2241 }
2352 2242
2353 2243 memcpy((void *)&(mname6.ipv6mr_multiaddr), caddr, sizeof(struct in6_addr));
2354 2244 if (IS_NULL(niObj)) {
2355 2245 int index;
2356 2246 int len = sizeof(index);
2357 2247
2358 2248 #ifdef __linux__
2359 2249 /*
2360 2250 * 2.2 kernel doens't support IPV6_MULTICAST_IF socket option
2361 2251 */
2362 2252 if (isOldKernel) {
2363 2253 index = (*env)->GetIntField(env, this, pdsi_multicastInterfaceID);
2364 2254 } else
2365 2255 #endif
2366 2256 {
2367 2257 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2368 2258 (char*)&index, &len) < 0) {
2369 2259 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2370 2260 return;
2371 2261 }
2372 2262 }
2373 2263
2374 2264 #ifdef __linux__
2375 2265 /*
2376 2266 * On 2.4.8+ if we join a group with the interface set to 0
2377 2267 * then the kernel records the interface it decides. This causes
2378 2268 * subsequent leave groups to fail as there is no match. Thus we
2379 2269 * pick the interface if there is a matching route.
2380 2270 */
2381 2271 if (index == 0 && !isOldKernel) {
2382 2272 int rt_index = getDefaultIPv6Interface(&(mname6.ipv6mr_multiaddr));
2383 2273 if (rt_index > 0) {
2384 2274 index = rt_index;
2385 2275 }
2386 2276 }
2387 2277 #endif
2388 2278
2389 2279 mname6.ipv6mr_interface = index;
2390 2280 } else {
2391 2281 jint idx = (*env)->GetIntField(env, niObj, ni_indexID);
2392 2282 mname6.ipv6mr_interface = idx;
2393 2283 }
2394 2284
2395 2285 /* Join the multicast group */
2396 2286 if (JVM_SetSockOpt(fd, IPPROTO_IPV6, (join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP),
2397 2287 (char *) &mname6, sizeof (mname6)) < 0) {
2398 2288
2399 2289 if (join) {
2400 2290 NET_ThrowCurrent(env, "setsockopt IPV6_ADD_MEMBERSHIP failed");
2401 2291 } else {
2402 2292 if (errno == ENOENT) {
2403 2293 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2404 2294 "Not a member of the multicast group");
2405 2295 } else {
2406 2296 NET_ThrowCurrent(env, "setsockopt IPV6_DROP_MEMBERSHIP failed");
2407 2297 }
2408 2298 }
2409 2299 }
2410 2300 }
2411 2301 #endif
2412 2302 }
2413 2303
2414 2304 /*
2415 2305 * Class: java_net_PlainDatagramSocketImpl
2416 2306 * Method: join
2417 2307 * Signature: (Ljava/net/InetAddress;)V
2418 2308 */
2419 2309 JNIEXPORT void JNICALL
2420 2310 Java_java_net_PlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
2421 2311 jobject iaObj, jobject niObj)
2422 2312 {
2423 2313 mcast_join_leave(env, this, iaObj, niObj, JNI_TRUE);
2424 2314 }
2425 2315
2426 2316 /*
2427 2317 * Class: java_net_PlainDatagramSocketImpl
2428 2318 * Method: leave
2429 2319 * Signature: (Ljava/net/InetAddress;)V
2430 2320 */
2431 2321 JNIEXPORT void JNICALL
2432 2322 Java_java_net_PlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
2433 2323 jobject iaObj, jobject niObj)
2434 2324 {
2435 2325 mcast_join_leave(env, this, iaObj, niObj, JNI_FALSE);
2436 2326 }
↓ open down ↓ |
247 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX