annotate src/solaris/native/java/net/PlainDatagramSocketImpl.c @ 5398:979c364ea1f1

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